ein Kapitel zurück                                           ein Kapitel weiter

Um aus einem Lauffähigen Programm ein anderes Programm zu starten steht die Funktion system zur Verfügung....

#include <stdlib.h>

int system(const char *kommandozeile);  

Die Rückgabe bei Erfolg ist ungleich 0 und bei Fehler -1. Als kommandozeile können sie alles eingeben was auch in der Kommandozeile erlaubt ist z.b. ls-s , dir usw.

Ich möchte Ihnen den Befehl system anhand eines Beispiels demonstrieren das den Inhalt aller Directorys auf dem Bildschirm ausgibt die sie in der Kommandozeile eingeben. Das Programm benutzt den Dos-Befehl DIR /W bzw. unter Unix/Linux ls -C. Dies Programm ist für Linux/Unix geschrieben. Wenn sie es unter Dos laufen lassen wollen brauchen sie nur den Befehl ls -C durch dir /w auszutauschen in sämtlichen Zeilen wie dies vorkommt :

/*Download:system1.c*/
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int x; char kommando[100]; if(argc == 1) system("ls -C"); else { for(x=1; x<argc; x++) { sprintf(kommando,"ls -C %s",argv[x]); printf("Kommando : %s\n",kommando); system(kommando); printf("<RETURN>");getchar(); } } return 0; }

Sie können jetzt z.B. in der Kommandozeile eingeben...

system1 home floppy cdrom  

Somit gibt das Programm nacheinander den Inhalt von /home dann /floppy und anschließend von /cdrom aus. Als weiteres Beispiel möchte ich Ihnen ein weiteres Programm demonstrieren. Wir wollen ein Programm schreiben das ein Menü wie folgt haben soll....

-1- Programm Editieren
-2- Programm compilieren
-3- Programm ausführen
-4- Weiter Editieren von programmname.c
-5- Ende  

Dies Programm soll für Linux/Unix sein für Leute die Ihre Programme mit dem Editor Emacs schreiben. Ich benutze als Compiler den GNU-gcc und eben den entsprechenden Befehl "gcc" zum compelieren eines Programms. Wenn sie einen anderen Compiler verwenden oder entsprechendes unter Linux/Unix machen wollen, müssen sie das Programm einfach für Ihre Bedürfnisse anpassen. Das allgemeine Programm bietet nur die Grundlage und kann noch an vielen Stellen verbessert werden.....

/*Download:system2.c*/
#include <stdio.h> #include <stdlib.h> /*Funktion zum Anhängen eines Strings an den anderen*/ char *ownstrcat(char *dest, char *src) { char *sav; sav = dest; while (*dest) ++dest; while (*dest++ = *src++); return sav; } /*Funktion um aus dem String ein Lauffähigen Kommandonamen zu erzeugen damit das Programm getestet werden kann z.B. aus Hello.c wird Hello */ char *kommandoname(char *dest, char *src) { while ((*dest++ = *src++) && (*src != '.')); *dest++='\0'; return dest; } /*Funktion zum löschen des Inhaltes eines Arrays*/ char *empty(char *dest) { *dest = '\0'; return dest; } int main() { int wahl; char temp[100],temp2[100],temp3[100]; char editor [] = "emacs "; /*Bitte anpassen*/ char compiler[] = "gcc"; /*Ebenfalls anpassen*/ char kommandozeile[100]; temp[0] = '\0'; do{ printf("-1- Programm Editieren\n"); printf("-2- Programm compilieren\n"); printf("-3- Programm ausführen\n"); if(temp[0]!='\0') printf("-4- Weiter Editieren von %s\n",temp); else printf("-4- Noch keine Datei zum Editieren erstellt\n"); printf("-5- Ende\n"); printf("Ihre Auswahl bitte : "); scanf("%d",&wahl); switch(wahl) { case 1 : empty(kommandozeile); printf("Welches Programm wollen sie editieren : "); scanf("%s",temp); ownstrcat(kommandozeile,editor); ownstrcat(kommandozeile,temp); system(kommandozeile); break; case 2 : empty(kommandozeile); sprintf(kommandozeile,"%s -o %s %s", compiler,kommandoname(temp2,temp),temp); system(kommandozeile); break; case 3 : empty(kommandozeile); sprintf(temp3,"./%s",kommandoname(temp2,temp)); system(temp3); empty(temp2); empty(temp3); break; case 4 : empty(kommandozeile); ownstrcat(kommandozeile,editor); ownstrcat(kommandozeile,temp); system(kommandozeile); break; default: break; } }while(wahl != 5); return 0; }

Sie sehen es ist möglich mit ein paar Zeilen Code ein "Schnittstelle" zu programmieren womit wir auf mehrere Programme zugreifen können. Anstatt immer erst von Hand den Editor zu öffnen und anschließend das Programm von Hand in der Kommandozeile compilieren und anschließend wieder bearbeiten haben wir das alles in einem Menü gepackt und somit ist die Arbeitsweise auch schneller ein Programm zu schreiben. Wie gesagt an dem Programm können sie das was sie benötigen noch vieles hinzufügen und verbessern (z.B. verschiedene Schalter). Anstatt der Funktion ownstrcat hätte ich natürlich auch die Funktion strcat in der Headerdatei <string.h> verwenden können. Um zu testen ob ein Kommandoprozessor verfügbar ist brauchen sie nur mit...

if(system(NULL) == 0)
   {........FEHLER...........}  

....testen.

Sicherlich kommt Ihnen das Verhalten der Funktion system irgendwie bekannt vor. Wir starten unser Programm und rufen während dessen Ausführung einen neuen Prozeß auf. Und unser Aufrufendes Programm wartet solange. Manch einer wird erraten haben, intern sieht unser Funktionsaufruf system folgendermaßen aus : fork(), exec(), waitpid() Einfacher noch, system() übernimmt uns die ganze Arbeit der Fehlerbehandlung der Signale ab.

system und Sicherheit

Leider gibt es noch ein paar kleine Schönheitsfehler der Funktion system, die sie aber nicht stören sollten, wenn sie folgendes Beachten.

Vermeiden sie solche Schreibweisen dieser Funktion........

sprintf(kommando,"fgrep -i %s adressen.txt", name);
system(kommando);  

Auf den ersten Blick mag dies ganz praktisch erscheinen. Wir suchen mittels fgrep in der Datei "adressen.txt" nach einem bestimmten Namen. Vom Buffer Overflow mal abgesehen haben wir hier eine noch viel größere Sicherheitslücke. Nehmen wir mal an der User hat für Namen folgendes eingegeben....

"root" /etc/passwd  

Sie können dies gerne in der Kommandozeile testen....

find -i "root" /etc/passwd adressen.txt  

Damit haben sie dem Angreifer ein kleine Chance gegeben, sich bei Ihnen Zugang zu schaffen. In solch einem Beispiel sind mit den exec() Funktionen sicherer.............

execle ("/bin/fgrep", "-i", name, "adressen.txt" ,
        "PATH=/usr/bin:/bin:/usr/sbin:/sbin\0USER=nobody");  

Dies ist ein Beispiel wie man es oft in einem CGI-Programm findet.

Die zweite Gefahr von system() kommt weit aus seltener vor. Starten sie in einem Prozeß, bei dem die setuser/setgroup-ID gesetzt ist, bleibt dieses bei einem Aufruf von system() auch bei dem neuen Prozeß bestehen. Auf älteren Systemen kann man in diesem Fall den Input Field Seperator manipulieren. Bei den neueren Systemen funktioniert dies aber nicht mehr.

Wenn sie diese beiden Sicherheitsmaßnamen beachten, ist die Funktion system eine gute Wahl.

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf