I read this but I couldn't solve my problem. I don't know how do I use setuid
I have a small python app that runs python commands and bash command in linux machine. I want only this part below to run as normal user. App run with sudo python3 app.py because do some commands that need sudo privilege. I upload only the part I want to run as normal user.
How can I do that?
import alsaaudio
m = alsaaudio.Mixer('Capture')
m.setvolume(10) # set volume
vol = m.getvolume() # get volume float value
One can't simply change the owner of a process back and forth at will (ok, one can with the proper call:
os.seteuid, I learned after starting this answer. Either way, there are more things required for this particular question than just setting the UID - the bottom part of the answer has a subprocess approach): just the root user can do that, and once its done, it is no longer root to switch back. So the trick is to call it in a process that is exclusive to run the limited tasks.You can fork the process and call
os.setuidon the child, and then terminate it:Of course, this won't make the
volvariable avaliable on the parent process - you have to setup a way to pass the value along.In that case, one can use Python multiprocessing, instead of fork, with multiprocessing.Queue to send
volvalue, and add the needed pauses to destroy the other user process: that is good if you are writing "production quality" code that will need to handle a lot of corner cases in third party computers. If your object is a simple script for setting up stuff in your box, writting the value to a file, and reading it on parent will be easier:Given the OP comments, this is not just a matter of changing the effective UID, but also environment variables, and reimporting the
alsaaudiomodule - a "fork" won't cut it (as env vars are not changed, and changingos.environmententries on the Pythonside will probably not be reflected on the native-code side of alsalib as it is initialized.In this case, running the process with
subprocess.Popenand ensuring the correct enviroment prior to it can attain the desired effects. Interprocess comunication can be resolved by capturing the subprocess stdout - so we can refrain from both the pickle.Also, the default subprocess call is synchronous, and no need for an arbitrary pause for the target child to initialize alsa and pick its value: the main process will continue just after the child is done, in the default call.I am not trying alsaaudio here, it may be that more environment variables than the 2 I set are needed on the subprocess. If that is the case, just go on adding then to the
env={ ...}part of the code as needed.This sample just do what you asked, and pass the value for "vol" back - if you ever need more data, drop the "encoding" argument to the subprocess, and pickle arbitrary data to
sys.stdouton the child process - you can then retriev it with pickle.loads onproc.stdout