====== Kommunikation über Named Pipes ====== Es gibt Aufgaben, daß die Ausgabe eines Programms (sagen wir //Prg1//) direkt als Eingabe eines anderen Programms (//Prg2//) verwendet und nicht als File gespeichert werden soll. Ein Beispiel: //Prg1// generiert Daten, die als geheim eingestuft sind (z.B. Paßwörter, PINs, etc.) und leitet sie nach **stdout**. //Prg2// empfängt diese Daten über **stdin** und bearbeitet weiter (z.B. verschlüsselt). Beide Prozesse sind über eine **Pipe** verbunden. **1)** Der Aufruf würde dann etwa so aussehen: Prg1 | Prg2 **2)** Eine andere Möglichkeit wäre, beide Prozesse über eine **Named Pipe** kommunizieren zu lassen: # Eine Named Pipe anlegen (der Name spielt keine Rolle). mkfifo /Pfad/Prg1.to.Prg2.fifo # Den schreibenden Prozeß im Hintergrund starten, die Pipe wird zum Schreiben geöffnet. Prg1 > /Pfad/Prg1.to.Prg2.fifo & # Der schreibende Prozeß wird solange angehalten, bis die Pipe durch den lesenden Prozeß zum Lesen geöffnet wird. Prg2 < /Pfad/Prg1.to.Prg2.fifo # Jetzt laufen beide Prozesse, die Daten werden über die Pipe geschaufelt. # Als die Kommunikation abgeschlossen ist, soll die Pipe wieder gelöscht werden. rm /Pfad/Prg1.to.Prg2.fifo **3)** Es gibt aber Situationen, daß es sinnvoller erscheint, alle in der 2. Möglichkeit erwähnten Schritte direkt in das //Prg1// zu kapseln. Das hat Vorteil, daß:\\ * Keine manuellen Schritte erforderlich sind, die fehleranfällig und manipulierbar sein könnten. * Da der Name und die Position im Filesystem der Named Pipe durch den //Prg1//-Prozeß bestimmt werden, sind sie für einen Angreifer nicht mehr so leicht abgreifbar. * Der Prozeß //Prg1// kümmert sich um den gesamten Ablauf selbst, so, daß die Prozeß-Leichen wegen den einseitig geöffneten Pipes einfacher vermieden werden können. * Der Prozeß //Prg1// löscht am Ende die Pipe, so, daß kein Müll im Filesystem liegen bleibt. Ein **Programmbeispiel** für die 3. Variante könnte so aussehen: { int rc = 0; // ReturnCode FILE *pipeFIFO = NULL; char pipeName [] = "/tmp/eineTestPipe.fifo"; char runStr [1024]; memset(runStr, '\0', sizeof(runStr)); // Teil 1: Vorbereitung if (!rc) remove(pipeName); // Evtl. bereits vorhandene Named Pipe wird vorsorglich entfernt. if (!rc) { if ((rc = mkfifo(pipeName, 0666)) == 0) printf("Named Pipe %s wurde angelegt.\n", pipeName); // Named Pipe anlegen. else printf("Named Pipe %s konnte nicht angelegt werden.\n", pipeName); } // if if (!rc) { sprintf(runStr, "cat %s &", pipeName); // Aufruf des Lese-Programms (im Text Prg2) vorbereiten. if ((rc = system(runStr)) != 0) printf("Prg2: Fehler beim Aufruf vom %s: %s\n", runStr, strerror(errno)); else printf("Prg2: submitted.\n"); } // if // Ab dieser Stelle hat das Leseprogramm die Pipe zum Lesen geöffnet und läuft im Hintergrund. if (!rc) pipeFIFO = fopen(pipeName, "w"); // Pipe zum Schreiben öffnen if (!pipeFIFO) printf("Named Pipe %s konnte nicht geöffnet werden.\n", pipeName); // Fehlermeldung. else printf("Named Pipe %s wurde geöffnet.\n", pipeName); // Teil 2: Datenausgabe in die Pipe if (pipeFIFO) fprintf(pipeFIFO, "Testausgabe:\nNamed Pipe = [%s], Aufruf von Prg2 = [%s]\n", pipeName, runStr); // Teil 3: Aufräumen if (pipeFIFO) { fflush(pipeFIFO); fclose(pipeFIFO); // Die Pipe schließen. pipeFIFO = NULL; sleep(1); // Vor dem Löschen evtl. kurz abwarten bis der Leseprozeß fertig ist (besser mit wait()). if ((rc = remove(pipeName)) != 0) printf("Named Pipe %s konnte nicht gelöscht werden.\n", pipeName); // Fehlermeldung. } // if return rc; } ---- Stand: 30.10.2009\\ --- //[[feedback.jk-wiki@kreick.de|: Jürgen Kreick]]// EOF