====== 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