Why do I need setuid(0) within a setuid-root C program that calls an administrative program with system()?
c, privilege-elevation, setuid, unix
Solution
From `man system`:
Do not use `system()` from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might be used to subvert system integrity. Use the `exec(3)` family of functions instead, but not `execlp(3)` or `execvp(3)`. `system()` will not, in fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which `/bin/sh` is bash version 2, since bash 2 drops privileges on startup.
And from `man bash`:
If the shell is started with the effective user (group) id not equal to the real user (group) id, and the `-p` option is not supplied, no startup files are read, shell functions are not inherited from the environment, the `SHELLOPTS` variable, if it appears in the environment, is ignored, and the effective user id is set to the real user id.
It appears your `setuid(0)` call circumvented that protection.
Problem
I had to do a dirty Linux hack for somebody so they could start a printer with the `cupsenable printername` shell command while being a non-root user. I didn't want them to be able to use the entirety of the `cupsenable` syntax as root, so I just wrote a C wrapper that sanitizes the input in `argv[1]` and calls `system("cupsenable sanitizedprintername")`. I made the program setuid root, but even so, `cupsenable` failed with "permission denied". Then I inserted a `setuid(0)` call before `system()` and, lo and behold, it worked. Disregard the issue of there being a better way to give users control of the printer. There probably is a better way. What I'm interested in are the intricacies of `chmod u+s` vs. `setuid(0)` vs. `system()`. Why did it behave that way?