|
![ein Kapitel weiter](../weiter.gif)
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 weiter](../weiter.gif)
© 2001,2002 Jürgen Wolf
|