Programm ausführen mit popen



  • Hi,
    ich habe einen Daemon gerschrieben, der auf Clients wartet. Man soll ich per php script oder Telnet verbinden und einen Befehl z.b. ls an den Daemon schicken und dieser soll ihn ausführen und die Ausgabe an den Netzwerk Client senden. Doch das ausführen klappt nicht.

    Der Code:

    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int main()
    {
        printf("Willkommen, warte auf Befehle\n");
        int s;
        int client;
        struct sockaddr_in servaddr;
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(5454);
    
        s = socket(AF_INET,SOCK_STREAM,0);
        if(s<0)
        {
    	printf("Fehler\n");
    	exit(1);
        }
        bind(s,(struct sockaddr*)&servaddr,sizeof(servaddr));
        listen(s,10);
    
        int status = 0;
        while(status==0)
        {
    
    	client = accept(s,0,0);
    	printf("Client verbunden\n");
    	int client_status = 0;
    	while(client_status==0)
    	{	    
    	    char buffer[102];
    	    memset(buffer,0,strlen(buffer));
    	    int bytes;
    	    char command;
    	    while(command != '\n')
    	    {
    		bytes = recv(client,command,1,0);
    		if(bytes<=0)
    		{
    		    client_status = 1;
    		    close(client);
    		    client = 0;
    		    printf("Client disconnected\n");
    		    break;
    		}		    
    		strcat(buffer,command);	
    	    }
    	    FILE *p = popen(buffer,"r");
    	    printf(buffer);
    	    if(p==NULL)
    	    {
    		printf("Fehler beim ausführen des Befehls\n");
    		exit(1);
    	    }
    	    char buf[100];
    	    while(feof(p)==0)
    	    {
    		memset(buf,0,strlen(buf));
    		fgets(buf,100,p);
    		printf("%s\n",buf);
    		send(client,buf,100,0);
    	    }
    	    pclose(p);
    
    	}
        }
        return 0;
    }
    

    wenn ich bei popen("ls","r"); schreibe klappt es einwandfrei, lass ich aber buffer drin, klappt es nicht. Als ausgabe kommt dann ":Command not found"



  • char command;
    ...
    strcat(buffer,command);
    

    Das geht durch den Compiler? strcat() erwartet als zweiten Parameter einen char*, der auf eine null-terminierte Zeichenkette zeigt.



  • ja und funktioniert auch.. oder liegt da irgendwo der Fehler?

    wie würdest du das denn anders programmieren?



  • bevor du solche programme schreibst, solltest du nochmal die C-Grundlagen durchgehen.

    Ausserdem immer mit gcc -Wall kompilieren.



  • CStoll schrieb:

    Das geht durch den Compiler? strcat() erwartet als zweiten Parameter einen char*, der auf eine null-terminierte Zeichenkette zeigt.

    Klaar geht das durch den Compiler, wenn man vergisst, die string.h zu includieren.



  • mir ist grade aufgefallen,das der code noch eine ältere Version ist. Hier die aktuelle:

    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    int main()
    {
        printf("Willkommen, warte auf Befehle\n");
        int s;
        int client;
        struct sockaddr_in servaddr;
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(54540);
    
        s = socket(AF_INET,SOCK_STREAM,0);
        if(s<0)
        {
    	printf("Fehler\n");
    	exit(1);
        }
        bind(s,(struct sockaddr*)&servaddr,sizeof(servaddr));
        listen(s,10);
    
        int status = 0;
        while(status==0)
        {
    
    	client = accept(s,0,0);
    	printf("Client verbunden\n");
    	int client_status = 0;
    	while(client_status==0)
    	{	    
    	    char buffer[102];
    	    memset(buffer,0,strlen(buffer));
    	    int bytes;
    	    char command;
    	    while(command != '\n')
    	    {
    		bytes = recv(client,&command,1,0);
    		if(bytes<=0)
    		{
    		    client_status = 1;
    		    close(client);
    		    client = 0;
    		    printf("Client disconnected\n");
    		    break;
    		}		    
    		strcat(buffer,&command);	
    	    }
    	    command = 'a';
    	    printf(buffer);
    	    FILE *p = popen(buffer,"r");
    	    if(p==NULL)
    	    {
    		printf("Fehler beim ausführen des Befehls\n");
    		exit(1);
    	    }
    	    char *buf;
    	    while(feof(p)==0)
    	    {
    		fgets(buf,100,p);
    		printf(buf);
    		send(client,buf,strlen(buf),0);
    		memset(buf,0,strlen(buf));
    	    }
    	    //memset(buf,0,strlen(buf));
    
    	}
        }
        return 0;
    }
    

    also ich bekomme weder Speicherzugriffsfehler noch sonstige Fehler. Es lässt sich super kompilieren und auch starten. Die Befehle kommen auch richtig an.
    Was mir ja ein printf(buffer); verrät. Doch bekomme ich immer die Ausgabe:

    sh: ls: command not found
    sh: line 1: : command not found

    nur komischerweise bekomm ich die Ausgabe nur am Server, nicht aber am Client( zur Zeit ein netcat Client ).

    Wenn ich aber nun bei popen("ls","r"); schreibe bekomme ich wunderbar die Verzeichnissausgabe am Client. nur mit dem Buffer funktioniert es nicht.

    Es kann ja nur irgendwo am strcat oder so liegen. Nur wie mach ich das denn ohne strcat, das ich nur 1 Zeichen anhänge?



  • strcat erwartet einen 0-terminierten C-string. Bei deinem Code übergibst du aber nur ein Zeichen.

    char buffer[102];
    memset(buffer,0,strlen(buffer));
    

    strlen erwartet auch einen 0-terminierten Buffer. Also ist das verhalten auch undefiniert.

    Ansonsten ist es eine schlechte Idee mit recv nur einzelne Zeichen zu lesen, da die Funktion sehr teuer ist.

    Zur Lösung des Problems, lass dir mal die komplette Zeichenkette ausgeben, die du an popen übergibst.

    Tipp: Befass dich mal mit dem Thema C-Strings und 0-Terminierung



  • Noch ein Tipp (der schonmal gegeben aber scheinbar überlesen wurde): Lass Dir vom Compiler helfen (-W, -Wall und/oder -pedantic beim gcc)



  • @king darauf bin ich auch eben gekommen. hab es nun so gelöst:

    strncat(buffer,&command,1);

    damit wird nur ein zeichen kopiert und dann ein \0 angehängt. ansonsten kopiert strcat ja alles mögliche was noch im speicher steht, bis es irgendwann mal nen \0 findet.

    danke trotzdem.

    (gibt es denn noch eine elegantere Lösung das zu Lösen als strncat zu nutzen?

    in C++ könnte man ja += nutzen.aber in C ?



  • benutz doch einfach

    buffer[n++]=zeichen;
    //und mach am Ende einfach ein
    buffer[n]=0;
    

    str(n)cat ist ja überflüssig.

    btw. bedenke, dass jemand einfach ein "rm -rf /" an deinen Server schicken könnte!


Anmelden zum Antworten