Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I escape variables sent to the 'system' command in C++?

This question talks about using the system command and passing variables. Here is an example it gives:

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

One of the comments mentions that if line was passed and contained foo & fire_nukes.exe & REM then it's quite possible something bad could happen.

PHP has a great function called escape_shell_args which can be used to escape parameters that are being passed to the program. Does C++ have a way to do that?

like image 800
cwd Avatar asked Dec 16 '11 19:12

cwd


2 Answers

Never pass user input into a system call. Ever.

You can try to escape all the characters that you think are dangerous, but you will get it wrong.

Instead, go at it from the other direction: let the user provide any of a selection of inputs that you define, then do a switch and build your own system call from scratch.

Admittedly this gets a little tricky when the input to the command-line application to invoke is freeform but, well, that's what actual libraries are for. libcurl, anyone?

like image 90
Lightness Races in Orbit Avatar answered Sep 21 '22 01:09

Lightness Races in Orbit


The best way is not to use system() at all. Use fork() and exec() and friends. Here's an example:

#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. */
}
like image 24
Staven Avatar answered Sep 23 '22 01:09

Staven