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?
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 theexec(3)
family of functions instead, but notexeclp(3)
orexecvp(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, theSHELLOPTS
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.