how to add a space character to trigger var args c++ execlp() - c++

I'm writing this program on Ubuntu.
If I type this command into a shell
groups root sys bin
it outputs
root : root
sys : sys
bin : bin
However I'm writing a c++ program that calls groups with execlp using
execlp("groups", "groups", args.c_str(), NULL);
where args = "root sys bin". I just get a :No such user error since groups' is obviously just looking at that entire string as argv[0] which is the equivalent of running
groups "root sys bin"
How do i create the proper variable argument for execlp to run groups on each user, one at a time?

One option is to ask /bin/sh to deal with the input the way it normally would. Of course in addition to dealing with spaces, this would also deal with characters like $, #, ~, *, etc., which may or may not be what you want.
execl("/bin/sh", "sh", "-c", ("groups " + args).c_str(), nullptr);
Obviously, don't use this way if the data is user-entered and might contain nasty strings like:
root ;rm *
Otherwise, execl type functions won't work unless you know the number of command-line arguments at compile time. Assuming your args string could have varying numbers of arguments, you'll need execv type functions instead.
std::string args = "root sys bin";
std::vector<std::string> arg_vec;
std::istringstream arg_iss(args);
std::copy(std::istream_iterator<std::string>(arg_iss),
std::istream_iterator<std::string>(),
std::back_inserter(arg_vec));
char groups_exec[] = "groups";
std::vector<char*> arg_ptr_vec{ groups_exec };
std::for_each(arg_vec.begin(), arg_vec.end(),
[&](std::string& arg){ arg_ptr_vec.push_back(&arg[0]); } );
arg_ptr_vec.push_back(nullptr);
execvp("groups", arg_ptr_vec.data());

The args parameter to execlp is defined as "char *const argv[]", so I think you could do something like
const char *myArgs[3] = {"root, "sys", "bin"};
and then replace args.c_str() with myArgs.
I should admit to having zero experience of writing software for Ubuntu - this is what I would try next were I trying to get execlp to work.
EDIT: This is wrong - I had got mixed up and was looking at execv(), bobah and sleepy42 seem to have got it.

Related

Compare symbol C++

I am trying to take an argument in the form of > in Linux.
I am trying to solve my problem ,like this :
std::string big(">");
if (argv[3]==big) {....}
But It doesn't work like this.
But It works like this:
std::string big("M");
if (argv[3]==big) {....}
I guess, I need to get ASCII CODE of my char and compare with argv[3]. But argv[3] it is type of a char , I connot compare int and char.
Can you help me?
Most shells (including the Windows CMD) handles symbols like <, > and | in a special way. < is input redirection, > is output redirection, and | is piping output from one process to the input of another.
Therefore you will never be able to get those symbols as arguments to your process, the command-line environment will use them and will not pass them on to your program.
Unix shells with background job support also adds & to the mix.

What does execve() do?

What exactly does execve() do? I've tried looking at the documentation (http://linux.die.net/man/2/execve) but given that I'm very new to linux and this sort of programming it doesn't make a lot of sense. What I want to do is be able to execute this command:
nc -l -p someport -e /bin/sh
Can I do something like the following (where someport is a number such as 4444)
char *command[2];
command[0] = "nc -l -p someport -e /bin/sh"
execve(command[0], name, NULL);
execve asks the operating system to start executing a different program in the current process.
Chances are pretty decent that you want execvp or execlp instead -- you haven't mentioned anything about wanting to provide the environment for the child, but from the looks of things you probably do want the path searched to find the executable you're using.
Correct usage is
extern char * const environ[];
char * const command[] = {"nc", "-l", "-p", "porthere", "-e", "/bin/sh", NULL};
execve("/usr/bin/nc", command, environ);
You must use a full pathname, not a short name such as "nc" (more precisely: no PATH search is done, the pathname must be an actual existing file), and you must split arguments into separate strings beforehand. You also need to propagate the environment somehow, either via the extern environ mentioned in the above snippet or as obtained from the third parameter of main(); the latter is slightly more standards-blessed but may be more painful to pass around as needed.

posix_spawn a shell script, trouble passing arguments

I need a to be able to use some of the process control facilities provided by posix_spawn() like suspend/resume/kill etc, something that system() does not give me.
So use the following call to posix_spawn() to launch a shell script from a c++ program:
int result = posix_spawn(&spawnedPid, processExecutable, 0, 0, argumentList, 0);
where processExecutable is "foo.sh" and argumentList is {"bar",0,0,0}; The process foo.sh starts up just fine, except for the argumentList part. If I do something like "echo $1" in foo.sh, I get an empty string. If I launch a binary the same way, the arguments are just fine and I can reach them via argv[]. Is there anything I should be doing differently in order to pass arguments to foo.sh ?
Shame on me, the argumentList parameter of posix_spawn() is 0-based so echo $1 actually outputs argumentList[1], which is, naturally, set to 0. Case closed.

C++: How to escape user input for safe system calls?

On a Linux platform, I have C++ code that goes like this:
// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
std::string command;
command = "mkdir " + myDir;
if (system(command.c_str()) != 0) {
return 1;
}
// continue....
Is passing user input to a system() call safe at all?
Should the user input be escaped / sanitized?
How?
How could the above code be exploited for malicious purposes?
Thanks.
Just don't use system. Prefer execl.
execl ("/bin/mkdir", "mkdir", myDir, (char *)0);
That way, myDir is always passed as a single argument to mkdir, and the shell isn't involved. Note that you need to fork if you use this method.
But if this is not just an example, you should use the mkdir C function:
mkdir(myDir, someMode);
Using system() call with command line parameters without sanitizing the input can be highly insecure.
The potential security threat could be a user passing the following as directory name
somedir ; rm -rf /
To prevent this , use a mixture of the following
use getopt to ensure your input is
sanitized
sanitize the input
use execl instead of system to execute
the command
The best option would be to use all three
Further to Matthew's answer, don't spawn a shell process unless you absolutely need it. If you use a fork/execl combination, individual parameters will never be parsed so don't need to be escaped. Beware of null characters however which will still prematurely terminate the parameter (this is not a security problem in some cases).
I assume mkdir is just an example, as mkdir can trivially be called from C++ much more easily than these subprocess suggestions.
Reviving this ancient question as I ran into the same problem and the top answers, based on fork() + execl(), weren't working for me. (They create a separate process, whereas I wanted to use async to launch the command in a thread and have the system call stay in-process to share state more easily.) So I'll give an alternative solution.
It's not usually safe to pass user input as-is, especially if the utility is designed to be sudo'd; in order to sanitize it, instead of composing the string to be executed yourself, use environment variables, which the shell has built-in escape mechanisms for.
For your example:
// ...
std::string myDir;
myDir = argv[1]; // myDir is initialized using user input from the command line.
setenv("MY_DIR", myDir, 1);
if (system("mkdir \"${MY_DIR}\"") != 0) {
return 1;
}
// continue....

Executing a command from C++, What is expected in argv[0]?

I am using execv() to run commands from /bin/ such as 'ls', 'pwd', 'echo' from my c++ program, and I am wondering what value I should provide in argv[0];
const char * path = getPath();
char ** argv = getArgs();
execv(path,argv);
argv[0] is supposed to be the program name. It's passed to the program's main function. Some programs differentiate their behavior depending on what string argv[0] is. For example the GNU bash shell will disable some of its features if called using sh instead of bash. Best give it the same value that you pass to path.
In linux, argv[0] is the process name displayed by the top utility (which it probably gets from reading entries in /proc/)
argv[0] should be the full path of the command that you want to run.
I know that this is not the answer you're looking for but is there a specific reason why you're doing this? The reason I ask is that most if not all of the actions people normally run with either system() or execv() are available in libraries on either Windows or Unix and are safer, faster and less likely to suffer from circumstantial errors. By that I mean, for example, when the PATH changes and suddenly your code stops working.
If you're passing in a string, either in whole or in part, and running it then you also leave yourself open to a user gaining access to the system by entering a command that could be damaging. E.g. imagine you've implemented a file search using find /home -name and your user types in:
"%" -exec rm {} \;
Ouch!