Running subprocess commands as root in python - python

I'm writing a GUI program, that configures your systems settings. For this purpose, the whole program should not be ran as root, otherwise it would configure the system for the root user. However, there is a subprocess command that needs to be ran as root, and I'm not sure how to safely, and properly incorporate this into my GUI for the following reasons.
The user would almost have to enter it into the GUI frontend.
I'm not sure how to verify that the users password was indeed correct. How to add error proofing to alert the user that the password is incorrect, without just letting the command fail miserably.
How to run this safely, since the users password is going to be involved.
I've been reccomended to create a daemon, and pass commands to that. This seems like a bit overkill, since it's just one command that needs to be ran. And since the user can't just type this into the terminal, it needs to be handled by the frontend of the GUI.
Does anyone have any other ideas on how to incorporate this feature?

You can use pkexec.
For example:
proc = subprocess.Popen(['/usr/bin/pkexec', command])

Related

How to get past a window prompt while calling a subprocess

I have a jar file that I want to run in the command line and collect it's stdout with a python script.
I make the call as a subprocess like:
def get_output():
process = subprocess.run(['java', '-jar', 'myjar.jar', 'myfileargument'])
But a warning prompt comes up that I am unable to disable, which pauses execution until a user clicks 'OK' or presses enter. Is there a way to essentially 'click ok' in the prompt window that comes up via code and let the python script continue?
If there is no way for you, only using environment variables and parameters to the subprocess, to disable that warning, there is no easy way to do it.
Either you will have to go the road of UI automation, as mentionned by #furas in the comments. It may be relatively easy to do so given the multiple tools/frameworks there is to do that.
Or you may "patch" the jar to not require this warning. If you can replace the annoying .class file by another which will not require to accept the warning, it may be somewhat efficient. Or else you could install a custom ClassLoader in the java program, but it may prove to be difficult.

Disable subprocess.Popen echo to command prompt window title in Python

I'm trying to use a Python's subprocess.Popen to build up a module for Python bindings to a command line interface; pretty much there as far as the CLI-bindings go, but I really want to be able to mask some "private" arguments.
The CLI uses account information, and I want to hide the account credentials from a command prompt title. Below is a screen capture of what appears when I use the login method for my CLI-bindings class.
I know that I'm using plain text for the password here ('TAIL') but I wanted to simply show the usage of what's going on. See from the image that the full command "sent" using the subprocess.Popen is displayed in the prompt's title.
I recently found that there is a way to programmatically change the title using either os or ctypes, so I could effectively mask, or cover-up, the "private" credentials I don't want shown on the command prompt title like shown here:
but is there a better way of disabling "echo-to-title" (for lack of a better name) with subprocess.Popen?
in fact passwords should never be passed as command line arguments to an executable.
Reason:
anybody being able to look at running processes and their parameters can see the password.
One solution is, that the parent process. puts the password in an environment variable and the program to be called fetches the parameter from an environment variable.
so the caller would be something like:
import os
os.environ["ACRTAC_PASSWORD"] = "TAIL"
subprocess.Popen([...])
and the acrtac.py
import os
password = os.environ["ACRTAC_PASSWORD"]

Automating Configuration commands that require input from the user using the Fabric module

I am currently in the process of developing a python code that connects to a remote brocade switch using the fabric module and issue some configuration commands. The problem I am facing is when it comes to commands that require an input from the user (i.e. yes/no).
I read several posts that have advised to use Fabric's native settings methods as well as wexpect but none have been successful.
I checked the following links but none were able to help with my code:
how to handle interactive shell in fabric python
How to answer to prompts automatically with python fabric?
Python fabric respond to prompts in output
Below is an example of the command output that requires to be automated:
DS300B_Autobook:admin> cfgsave
You are about to save the Defined zoning configuration. This
action will only save the changes on Defined configuration.
If the update includes changes to one or more traffic isolation
zones, you must issue the 'cfgenable' command for the changes
to take effect.
Do you want to save the Defined zoning configuration only? (yes, y, no, n): [no]
The code that I have written for this is show below (tried to make it exactly the same as the output the command provides):
with settings(prompts={"DS300B_Autobook:admin> cfgsave\n"
"You are about to save the Defined zoning configuration. This\n"
"action will only save the changes on Defined configuration.\n"
"If the update includes changes to one or more traffic isolation\n"
"zones, you must issue the 'cfgenable' command for the changes\n"
"to take effect.\n"
"Do you want to save the Defined zoning configuration only? (yes, y, no, n): [no] " : "yes"}):
c.run('cfgsave')
If there is a way to have it display the output of the command to the screen and prompt me to provide the input that would also be reasonable solution.

Su - root with python fabric

How can I "su -" and pass the root password with fabric? My current job doesn't give us sudoers, but instead uses su - to root(stupid in my opinion). On googling I haven't found a simple(or any working) answer to this.
My normal code for fabric is like:
from fabric.api import *
env.host_string="10.10.10.10"
env.user="mahuser"
env.password="mahpassword"
run('whoami')
Need to be able to
run('su -')
and have it pass my password.
I hear you saying that your policy does not permit use of "sudo" command. Understood.
But what HAPPENS when you try using Fabric sudo()? Please try it and report back.
I don't think sudo() "requires" a sudo prompt at the other end. What sudo() is is a run() command which anticipates a password prompt and attempts to respond to it. That's all.
So in your case, "sudo('su -')". If it fails, try "sudo('su - -c whoami') to see if you have any temporary success at all.
The point I want to make is run() and sudo()sudo() and run() are nearly identical EXCEPT that sudo() will anticipate a server prompt, then answer it. That's the difference.
Conversely, I had a different problem recently, where I was trying to suppress the prompt for sudo() using SSH keys. I couldn't get my head around why Fabric was prompting for the password when bash+ssh wasn't. The docs weren't clear, but eventually I realized that the prompt was MY doing because I thought that sudo level commands required sudo(). Untrue. If your command requires no prompt, use run() and if your command requires password input, use sudo().
Worst case, if sudo() doesn't work for you, it will have still created an AttributeObject of the SSH connection. You may or may not be able to then push some "input" into the stdin attribute of that object (I'm not sure this is correct, it's untested. But that's what you'd do with Paramiko, blindly send text down the connection's STDIN and it gets picked up by the prompt).
Absolute worst case, call sudo()/run() on "expect" command which WILL work, but may not be the simplest cleanest solution.

Executing shell commands as given UID in Python

I need a way to execute the os.system() module as different UID's. It would need to behave similar to the following BASH code (note these are not the exact commands I am executing):
su user1
ls ~
mv file1
su user2
ls ~
mv file1
The target platform is GNU Linux Generic.
Of course I could just pass these to the os.system module, but how to send the password? Of course I could run the script as root, but that's sloppy and insecure.
Preferably I would like to do with without requiring any passwords to be in plain text.
I think that's not trivial: you can do that with a shell because each command is launched into its own process, which has its own id. But with python, everything will have the uid of the python interpreted process (of course, assuming you don't launch subprocesses using the subprocess module and co). I don't know a way of changing the user of a process - I don't know if that's even possible - even if it were, you would at least need admin privileges.
What are you trying to do exactly ? This does not sound like the right thing to do for admin purpose, for example. Generally, admin scripts run in a priviledge user - because nobody knows the password of user 2 except user 2 (in theory). Being root means su user always work for a 'normal' user, without requesting password.
maybe sudo can help you here, otherwise you must be root to execute os.setuid
alternatively if you want to have fun you can use pexpect to do things
something like this, you can improve over this
p = pexpect.spawn("su guest")
p.logfile = sys.stdout
p.expect('Password:')
p.sendline("guest")
The function you're looking for is called os.seteuid. I'm afraid you probably won't escape executing the script as root, in any case, but I think you can use the capabilities(7) framework to 'fence in' the execution a little, so that it can change users--but not do any of the other things the superuser can.
Alternatively, you might be able to do this with PAM. But generally speaking, there's no 'neat' way to do this, and David Cournapeau is absolutely right that it's traditional for admin scripts to run with privileges.
Somewhere along the line, some process or other is going to need an effective UID of 0 (root), because only such a process can set the effective UID to an arbitrary other UID.
At the shell, the su command is a SUID root program; it is appropriately privileged (POSIX jargon) and can set the real and effective UID. Similarly, the sudo command can do the same job. With sudo, you can also configure which commands and UID are allowed. The crucial difference is that su requires the target user's password to let you in; sudo requires the password of the user running it.
There is, of course, the issue of whether a user should know the passwords of other users. In general, no user should know any other user's password.
Scripting UID changes is hard. You can do:
su altuser -c "commands to execute as altuser"
sudo -u altuser commands to execute as altuser
However, su will demand a password from the controlling terminal (and will fail if there is no controlling terminal). If you use sudo, it will cache credentials (or can be configured to do so) so you only get asked once for a password - but it will prompt the first time just like su does.
Working around the prompting is hard. You can use tools parallel to expect which handle pseudo-ttys for you. However, you are then faced with storing passwords in scripts (not a good idea) or somehow stashing them out of sight.
The tool I use for the job is one I wrote, called asroot. It allows me to control precisely the UID and GID attributes that the child process should have. But it is designed to only allow me to use it - that is, at compile time, the authorized username is specified (of course, that can be changed). However, I can do things like:
asroot -u someone -g theirgrp -C -A othergrp -m 022 -- somecmd arg1 ...
This sets the real and effective UID to 'someone', sets the primary group to 'theirgrp', removes all auxilliary groups, and adds 'othergrp' (so the process belongs to just two groups) and sets the umask to 0222; it then executes 'somecmd' with the arguments given.
For a specific user who needs limited (or not so limited) access to other user accounts, this works well. As a general solution, it is not so hot; sudo is better in most respects, but still requires a password (which asroot does not).

Categories

Resources