Shutting down computer from a python script in apache - python

I have a headless Raspberry Pi which I want to have an easy means for my child to power down. I tried the following script in the apache web server:
import os
sss = os.popen('echo password | sudo -S shutdown -hP now')
print sss.read()
But nothing happens.
Then I tried:
from subprocess import Popen, PIPE, STDOUT
p = Popen('echo password | sudo -S shutdown -hP now', shell=True, stdOUT=PIPE, stderr=STDOUT)
print p.stdout.read()
Also, nothing was output and no work appears to have been done.
How can I do a shutdown from a web page?

For security reasons Apache user cannot run sudo command.
Usually this is an almost mandatory rule to save you from attacks but for a Raspberry PI installation you may not have this problem so you can just add Apache user to sudoers (or, better, uso visudo to edit that file).
Something else? Yes you may simply add shutdown permissions to Apache user, follow this tutorial. In short you have to change /etc/sudoers with:
%groupName ALL= NOPASSWD: /sbin/shutdown

Related

script does not switch to another user

I am working on a script that at a certain point needs to switch to the root user (executing "sudo rootsh" is the only accepted way to switch to root on our servers,) after which it will execute a certain command.
I am not sure what I am missing, but the script simply ignores the part when it should switch to root and continues executing the commands with the user that started the script.
If you check the generated whoami.txt file, you will notice that the user is not root. Please keep in mind that the user executing the script can switch to root without any issue while executing the sudo rootsh command.
Here is the code I am using:
import subprocess
def switch_user():
commands = '''
sudo rootsh
whoami > whoami.txt
sysctl -a | grep kernel.msgmni'''
process = subprocess.Popen('/bin/bash', stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
out, err = process.communicate(commands.encode('utf-8'))
switch_user()
Any idea what I am doing wrong? Thanks.
Instead of Popening a subprocess to run bash, and from that opening a separate privileged shell, Popen the command sudo rootsh directly. If that succeeds (requires that the user be permitted to sudo rootsh without providing a password) then deliver the rest of the commands by communicating with the subprocess.
That would be something along these lines:
import subprocess
def switch_user():
# These shell commands will be used as input to the root shell
commands = '''whoami > whoami.txt
sysctl -a | grep kernel.msgmni'''
# Launch the root shell
process = subprocess.Popen('/usr/bin/sudo rootsh',
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
# Send the shell's input to it and receive back its output
out, err = process.communicate(commands.encode('utf-8'))
switch_user()
You may need to modify that for your purposes. In particular, if your sudo command lives at a different location then you may need to modify the path to it. And I emphasize again that this approach depends on being able to obtain a root shell without providing a password. Sudo can be configured that way, but it is not the default.
I finally managed to make this work after doing a more thorough investigation with the guys from the OS team. I'll post this, maybe it would be useful for somebody in the future:
import os
os.system("sudo rootsh -i -u root 'sysctl -a | grep kernel.msgmni' > parameter_value.txt")
The key was to insert the -i and -u options:
-i [command]
The -i (simulate initial login) option runs the shell specified by the password database entry of the target user as a login
shell.
This means that login-specific resource files such as .profile or .login will be read by the shell. If a command is
specified, it is
passed to the shell for execution via the shell's -c option. If no command is specified, an interactive shell is executed.
sudo
attempts to change to that user's home directory before running the shell. The security policy shall initialize the
environment to a
minimal set of variables, similar to what is present when a user logs in. The Command Environment section in the
sudoers(5) manual documents how the -i option affects the environment in which a command is run when the sudoers policy is in use.
-u user
The -u (user) option causes sudo to run the specified command as a user other than root. To specify a uid instead
of a user name, #uid.
When running commands as a uid, many shells require that the # be escaped with a backslash ('\'). Security policies may
restrict uids
to those listed in the password database. The sudoers policy allows uids that are not in the password database as
long as the targetpw
option is not set. Other security policies may not support this.
Thank you all for your answers :)

useradd via ssh to remote server - how to elevate rights ?sudo?

I want to create a user on a remote machine. I can reach only via ssh. useradd requires sudo, but the below script did not prompt me for my password and did not create the user. How do I elevate rights on the remote machine?
#!/usr/bin/python3
import os
import subprocess
HOST="192.168.1.71"
#useradd is linux - adduser is perl
addusertoremote = subprocess.Popen(["ssh", "%s" %HOST, "sudo useradd --disabled-login deletetom"],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
resulta = addusertoremote.stdout.readlines()
if resulta == []:
errora = addusertoremote.stderr.readlines()
print(errora)
else:
print(resulta)
You can use paramiko module for SSH in python.
import paramiko
sshsession = paramiko.SSHClient()
sshsession.set_missing_host_key_policy(paramiko.AutoAddPolicy())
sshsession.connect("hostname",username="username",password="password")
stdin, stdout, stderr = sshsession.exec_command('su')
stdin.write("password for root here")
sshsession.exec_command("sudo useradd --disabled-login deletetom")
#other commands here
sshsession.close()
This worked for me, though I wouldn't recommend doing it.
proc = subprocess.Popen(["ssh", "dummy", "-t", "sudo -S touch test.txt"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
proc.stdin.write(password.encode("utf8"));
proc.stdin.write("\r\n".encode("utf8"))
print(proc.communicate())
After I logged into the host, the file had been created as root. Also, I am using keys to login so ssh doesn't ask for my password, but sudo does.
I have done quite a bit of research on this and have come to the following conclusion.
Neither Python, nor Paramiko inside python has a method to elevate the rights on the reached machine.
One must ssh in AS root to the machine you want to create a user on - this way you already ARE root and no prompt is generated.
So, in my case (which I shall test soon), I would ssh into the machine that has the python script as myself, then su -s and become root and run the python script which will have root ssh into other machines to create accounts as root.

Execute a command after successfully SSH connection

I think I may of been googling this stuff wrong, however I was wondering if I could have my raspberry Pi execute a command after I connect to it via SSH.
Workflow:
1) SSH into Pi via terminal
2) Once logged in, the Pi executes a command to display the current temperature (I already know of this command)
The pi already outputs
Linux raspberrypi 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Jul 11 15:11:35 2014
I could be misunderstanding this all together, perhaps even have the command executed and shown in the dialog above.
What you're looking for is the motd which is quite common on various linux distros. This is not in python (but can be). The motd runs multiple commands on login via SSH and constructs a message which it outputs to the user. More information on this (which actually has temperature listed) can be found here: Rapberry Pi Welcome Message. The problem is this will likely change slightly depending on linux distros. A good git repo which has a nice message can also be found here: Raspberry Pi Motd
Yup, this can been done. The method that I am aware of utilizes subprocess https://docs.python.org/2/library/subprocess.html. As long as you know the name of the python script and the arguments (if any) you can pass them into subprocess. Here is an example of how to connect via python ssh script (taken from http://python-for-system-administrators.readthedocs.org/en/latest/ssh.html):
import subprocess
import sys
HOST="www.example.org"
# Ports are handled in ~/.ssh/config since we use OpenSSH
COMMAND="uname -a"
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
Just append the command to the ssh-command.
ssh user#server "echo test"
"echo test" is executed on the remote machine.
You can execute a command from bash without actually logging into the other computer by placing the command after the shh command:
$ ssh pi#pi_addr touch wat.txt
Would create the text file ~/wat.txt.
This is a little cumbersome for automation however since as password must be provided so you can set a public/private RSA-key on your computer in order to be able to login to your pi remotely without a password. Simply do the following:
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/a/.ssh/id_rsa):
Created directory '/home/a/.ssh'.
Enter passphase (empty for no passphrase):
Enter the same passphrase again:
$ssh pi#pi_addr mkdir -p .ssh
$cat .ssh/id_rsa.pub | ssh pi#pi_addr 'cat >> .ssh/authorized_keys'
Don't enter a passphrase and leave everything default when running ssh-keygen. Now you will be able to rn ssh pi#pi_addr without enter a password.
Example python file:
import subprocess
SERVER = "pi#pi_addr"
subprocess.call("ssh pi#pi_addr touch wat.txt")

Running sudo command via CGI (Python)

I am writing a test suite for a web application using Selenium.
In the course of which I need to test behaviour of the app in case a certain service is running or not.
I wanted to create a cgi call to a Python script turning that service on and off.
I know that the cgi call is in the context of the webserver (Apache) however thought that issuing sudo calls like so:
import subprocess
import os
command = 'sudo -S launchctl unload /Library/LaunchAgents/com.my.daemon.plist'
pwd = 'pwd123'
test1 = subprocess.Popen( command, shell=True, stdin=subprocess.PIPE)
test1.communicate(input=pwd)
test2 = os.system( 'echo %s|%s' % (pwd,command) )
would do the trick, well they don't I get return code 256.
What can I do to have this call be executed w/o touching the context in which Apache runs?
As for security: this will only run on a test machine.
The user that Apache runs as needs to be in the /etc/sudoers file, or belong to the sudo group, which I guess it usually doesn't. You also need to make it not ask for a password, which is configured in /etc/sudoers
For Ubuntu, check these out: https://askubuntu.com/questions/7477/how-can-i-add-a-new-user-as-sudoer-using-the-command-line
https://askubuntu.com/questions/147241/execute-sudo-without-password
It could potentially be a pathing issue..
Have you tried writing out the full path like this:
command = '/usr/bin/sudo -S launchctl unload /Library/LaunchAgents/com.my.daemon.plist'
command should be a list, not a string. Try with:
command = ['sudo', '-S', 'launchctl', 'unload', '/Library/LaunchAgents/com.my.daemon.plist']
Cant run sudo this way -- sudo needs a controlling terminal to run.

how to run sudo command in paramiko module in python scripts in remote machine

My scenario is I need to login to a remote machine and then do a sudo to another account like (sudo su anotheract) and then run the other required command.
But I am able to successfully connect to remote machine using below script. But the scripts hangs in the line where I am executing the sudo command(sudo su anotheract)
Can you please help me find the fix for this code?
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(
paramiko.AutoAddPolicy())
ssh.connect(hostname='XX.XXX.XX.XX',port=22, username='myname',password='XXXXX')
ssh.exec_command=("sudo su anotheract")
stdout,stdin,stderr=ssh.exec_command("java -jar /usr/share/XXX/LogR.jar")
print stdout.readlines()
One (not very safe) way to do it is to pipe the password in. The caveat is that the user that you are using to connect to the box using paramiko should have sudo rights.
For example:
supass = 'some_pass'
stdout, stdin, stderr = ssh.exec_command('echo %s | sudo -S anotheract' % supass)
Again, this is not a very safe implementation but gets the job done in a jiffy.
import pxssh
ssh = pxssh.pxssh()
ssh.login('host', 'user', 'password')
ssh.sendline("sudo su anotheract")
ssh.prompt('yourrootpassword')
And in paramiko on most linux systems you cant do sudo commands thats because sudo expect commands from tty and then it isnt raise exception, but you can try method invokeshell, but I used paramiko many years ago I dont remember what was been wrong with it. If you want send various commands on shell you could use pxssh.
It can hangen because sudo waits for password. Try to add NOPASSWD: statement to the /etc/sudoers.
user ALL = NOPASSWD: /bin/true
Also it is impossible to change user using su and then continue do to something after su is finished. When su is finished, you are back to your original shell of the original user.
So you need to run all commands with sudo:
stdout,stdin,stderr = ssh.exec_command=("sudo -u anotheract java -jar /usr/share/XXX/LogR.jar")

Categories

Resources