2011-12-16 22 views
5

This question habla sobre el uso del comando system y el paso de variables. Aquí hay un ejemplo que da:¿Cómo puedo escapar de las variables enviadas al comando 'system' en C++?

string cmd("curl -b cookie.txt -d test="); 
cmd += line; 
cmd += " http://example.com"; 
system(cmd.c_str()); 

Uno de los comentarios menciona que si line fue aprobada y contenía foo & fire_nukes.exe & REM entonces es muy posible que algo malo podría suceder.

PHP tiene una gran función llamada escape_shell_args que se puede utilizar para escapar de los parámetros que se están pasando al programa. ¿Tiene C++ una manera de hacer eso?

+2

Siempre puedes usar 'fork' y' exec' ... –

+4

'man fork',' man exec' :-) (Realmente no puedes decir "Estoy usando Linux" si no lo haces) ¡sé 'hombre'!) –

+5

' man 3 exec'. O tal vez para ti: 'hombre hombre' ...? –

Respuesta

4

La mejor manera es no utilizar system() en absoluto. Use fork() y exec() y amigos. He aquí un ejemplo:

#include <string> 
#include <unistd.h> 
#include <error.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <errno.h> 
#include <cstdlib> 

int fork_curl(char *line) 
{ 
    std::string linearg("line="); 
    linearg += line; 

    int pid = fork(); 
    if(pid != 0) { 
     /* We're in the parent process, return the child's pid. */ 
     return pid; 
    } 
    /* Otherwise, we're in the child process, so let's exec curl. */ 

    execlp("curl", "-b", "cookie.txt", "-d", linearg.c_str()); 
    /* exec is not supposed to return, so something 
     must have gone wrong. */ 
    exit(100); 
    /* Note: You should probably use an exit status 
     that doesn't collide with these used by curl, if possible. */ 
} 

int main(int argc, char* argv[]) 
{ 
    int cpid = fork_curl("test"); 
    if(cpid == -1) { 
     /* Failed to fork */ 
     error(1, errno, "Fork failed"); 
     return 1; 
    } 

    /* Optionally, wait for the child to exit and get 
     the exit status. */ 
    int status; 
    waitpid(cpid, &status, 0); 
    if(! WIFEXITED(status)) { 
     error(1, 0, "The child was killed or segfaulted or something\n"); 
    } 

    status = WEXITSTATUS(status); 
    /* Status now contains the exit status of the child process. */ 
} 
+1

¿Puede proporcionar un enlace a la documentación de los comandos que debería utilizar? ¿O posiblemente dar un ejemplo de cómo usar esos comandos? – cwd

+1

Estás en Linux, ¿verdad? Escriba 'man 3 exec' en una terminal :). – Staven

+0

un ejemplo * would * be nice :) –

0

Usted podría intentar execl ..

http://linux.about.com/library/cmd/blcmdl3_execvp.htm

#include <unistd.h> 

int execl(const char *path, const char *arg, ...); 
+0

Quizás esto es lo que necesito. Si quiero pasar las variables que se pasaron a mi programa al comando'/bin/echo', ¿cómo lo haría? (Inútil pero usémoslo como ejemplo) – cwd

+0

Debe definir qué * variables * significan para usted. Una vez que entendió bien en su cabeza lo que significan, estuvo a punto de resolver el problema –

4

Nunca pase la entrada del usuario en una llamada system. Nunca.

Puede tratar de escapar de todos los personajes que cree que son peligrosos, pero se equivocará.

En cambio, van en ella desde la otra dirección: dejar que el usuario proporcione alguna de una selección de entradas que se definir, a continuación, hacer un switch y construir su propia llamada al sistema desde cero.

Es cierto que esto se vuelve un poco complicado cuando la entrada a la aplicación de línea de comandos para invocar es de forma libre, pero, bueno, para eso están las bibliotecas reales. libcurl, ¿alguien?

+0

¿Qué sucede si necesita pasar las variables que pasaron a su programa a otro programa? Esto es lo que estoy intentando hacer. La razón por la que aún no lo hice es porque sé que no es "seguro" y entonces me gustaría descubrir qué manera más segura de hacerlo. sería. gracias. – cwd

+0

+1 para nunca pasar la entrada del usuario a un llamada al sistema –

+1

Se refiere a una llamada al sistema (3), no a un syscall como en syscalls (2) –

0

Consulte la página man que enumera todas las syscalls (las llamadas al sistema no son la función system(3) que realiza un shell).

Leer más sobre system calls y linux kernel, y la organización general de operating systems

Volver a su pregunta, usted podría citar para la cáscara (sólo tiene que seguir las reglas de la cáscara de escape para transformar sus cadenas; por ejemplo, el prefijo no cualquier carácter de letra con una barra invertida).

Ver también las páginas del manual de fork, execve, etc.

leer un buen libro sobre advanced linux programming y el famoso Advanced Unix Programming

uso de la libertad de la mayor parte del software en una distribución de Linux. Por ejemplo, podría estudiar el código fuente de un shell simple como sash.

Y tal vez solo quiera usar curl. A continuación, la mejor manera es código para el libcurl biblioteca (sin ningún tipo de llamada a system(3))

Diviértete aprendiendo todo esto!

+1

El problema es que incluso escaparse de cada letra no es suficiente. ¿Qué sucede si un usuario malintencionado inicia un programa setuid con una RUTA y/o IFS modificados? – ninjalj

+0

Estoy de acuerdo, pero al menos responde la pregunta. Mi impresión es que el póster no debe usar 'system' ni teclear un proceso' curl', pero aprende a llamar a las funciones de 'libcurl' –

+0

y el resto de tu respuesta es bastante buena. Pero, realmente, 'system()' es realmente peligroso. – ninjalj

Cuestiones relacionadas