Python subprocess stdout.readlines() getting stuck - python

I am trying to use to python subprocess module in order to ssh to a server and then switch to a super user and then ls and print the folders in the terminal.
My Code:
def sudo_Test():
HOST = 'Host'
PORT = '227'
USER = 'user'
cmd='sudo su - ec2-user;ls'
process = subprocess.Popen(['ssh','-tt','{}#{}'.format(USER, HOST),
'-p',PORT,cmd],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
process.stdin.write("my_password\r\n")
print "stuck here VVV"
result = process.stdout.readlines()
print "finished it"
if not result:
print "Im an error"
err = process.stderr.readlines()
print('ERROR: {}'.format(err))
else:
print "I'm a success"
print result
print sudo_Test()
Console output when I run this:
dredbounds-computer:folder dredbound$ python terminal_test.py
stuck here VVV
For some reason the code gets stuck on the line result = process.stdout.readlines(). I have to cntrl+c to exit out of the terminal session when this happens. It works fine if I just do cmd='sudo; ls' instead of cmd='sudo su - ec2-user;ls'.Anyone know what I'm doing wrong or how I can get this to work?
Update:
I changed cmd='sudo su - ec2-user;ls' -> cmd='sudo su - ec2-user ls' in the code above. Now I am getting the following error:
['password\r\n', '\r\n', '/bin/ls: /bin/ls: cannot execute binary file\r\n']
I'm not sure why it thinks ls is a binary file now, but is there anyway i can tell it that it is just a terminal command so it returns a list of directories?

The problem is here:
sudo su - ec2-user;ls
sudo su - ec2-user opens a shell and waits for input. You need to send the shell an exit command (or close its stdin) before the shell exits and the ls command is run.
If your goal was to run ls as user ec2-user, then try:
sudo -u ec2-user ls
In other words, replace
cmd='sudo su - ec2-user;ls'
With:
cmd='sudo -u ec2-user ls'

Related

How to execute 'su' command using parallel-ssh

I want to log in to two hosts using parallel-ssh and execute su command. Then I want to confirm that I am the root user by printing out whoami
Code:
hosts = ['myHost1', 'myHost2']
client = ParallelSSHClient(hosts, user='myUser', password='myPassword')
output = client.run_command('su')
for host in output:
stdin = output[host].stdin
stdin.write('rootPassword\n')
stdin.flush()
client.join(output)
output = client.run_command('whoami')
for host, host_output in output.items():
for line in host_output.stdout:
print("Host [%s] - %s" % (host, line))
Result:
Host [myHost1] - myUser
Host [myHost2] - myUser
Obviously, I expect root in the output. I am following the documentation.
I've tried using all different line endings instead of \n and nothing has changed.
How can I execute su command using parallel-ssh?
Try this:
**def exec_command(hosts):
strr = ""
client = ParallelSSHClient(hosts, user='admin', password='admin_password')
cmd = 'echo root_password |su -c "commmand" root'
output = client.run_command(cmd)
client.join()
for host_out in output:
for line in host_out.stdout:
strr+=line+" "
return strr
**
'echo root_password |su -c "command" root'
try to put sudo=True at the end of run_command
output = client.run_command(<..>, sudo=True)
like in docs
It turns out that what I am trying to do is not achievable.
The first problem
I found in this post that all commands are in their own channel. That means that even if su would be successful it wouldn't affect the second command. The author of the post recommends running
su -c whoami - root
The second problem
I managed to debug the problem even further by changing host_output.stdout to host_output.stderr It turned out that I receive an error which previously was not being shown on the terminal:
standard in must be a tty
Possible solutions to this problem are here . They didn't work for me but might work for you.
For me workaround was to allow on all my hosts root login. And then in parallel-ssh I log in as a root already with all the rights in place.

Run program from command line what prompts password and automatically provide password for it (cmd.exe, python)

I have command line program what prompts password:
> cwrsync root#NN.NN.NN.NN:/src /cygdrive/c/dst
Output (when i run it from cmd.exe command line):
root#NN.NN.NN.NN's password:
When i input password manually, all OK. Output:
skipping directory src
I want to provide password for it from command line or python script automatically.
I tried:
One. From command line:
> echo pass|cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst
Not working. Output:
root#NN.NN.NN.NN's password:
Two. From python script. test.py:
import subprocess
cmd = "cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst"
proc = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
std1, std2 = proc.communicate("pass")
print std1print std2
Not workin. Output:
Permission denied, please try again.
Permission denied, please try again.
Permission denied (publickey,password).
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: unexplained error (code 255) at io.c(235) [Receiver=3.1.1]
It is common that security oriented programs ask for password on direct io instead of reading stdin. And as :
echo pass|cwrsync -r root#NN.NN.NN.NN:/src /cygdrive/c/dst
did ask password, I presume that csrsync directly reads from console.
In that case you cannot automate it without some work and low level programming, because you will have to simulate keyboard actions. You should instead search the documentations, because as it looks like it uses an underlying ssh, it is likely to accept a public key pair. If it accept one without passphrase, you should be able to automate it.
Try sending a newline in your stdin string communicate call like so:
import subprocess
cmd = ['cwrsync', '-r', 'root#NN.NN.NN.NN:/src', '/cygdrive/c/dst']
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
shell=True)
std1, std2 = proc.communicate("pass\r\n\r\n")
print std1
print std2
You should also see if it works with shell=False (from subprocess docs):
Using shell=True can be a security hazard. See the warning under Frequently Used Arguments for details.

Python redirecting output from an LSF command

I am trying to run an LSF command , 'bjobs' inside a python code using subprocess and I am unable to get the output into a variable
Ways I have already tried and failed are as follows:
proc = subprocess.Popen(['bjobs'],stdout=subprocess.PIPE)
print proc.stdout.read() ## Not working
stdout,stderr = subprocess.Popen(['bjobs'],stdout=subprocess.PIPE).communicate()
print stdout # prints empty line
I do not want to redirect that to a physical file.
So please help me to find a way to directly capture them to a variable
As pointed out by a comment above, the "No unfinished job found" message is printed to stderr:
[~]$ bjobs > /dev/null
No unfinished job found
[~]$ bjobs >& /dev/null
[~]$
If you want all bjobs output you should redirect subprocess stderr to stdout:
proc = subprocess.Popen(["bjobs"],stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
print proc.stdout.read()

run Python file with root permission via php

I'm trying to run Python file with root access with php index
in php there is :
passthru('python /home/register/register.py '. $_POST['username'] . ' example.com ' . $_POST['password'] . ' ' . $_POST['email'] . ' ' . $ip . ' 1 2>&1');
and in Python file there is:
os.popen("sudo -u root -p password /sbin/ejabberdctl register %s %s %s" % (user,domain,password)).read()
is there any command with Python to login with root user then do command like : ls or mkdir
thnx.
from subprocess import PIPE,Popen
p = Popen(["sudo", "-s", "-S"], stdin=PIPE, stdout=PIPE, universal_newlines=True)
p.stdin.write("password\n")
p.stdin.write("mkdir foo\n")
p.stdin.write("id -u")
To see output use communicate:
from subprocess import PIPE,Popen
p = Popen(["sudo", "-s", "-S"], stdin=PIPE, stdout=PIPE, universal_newlines=True)
p.stdin.write("password\n")
p.stdin.write("ls -la\n")
p.stdin.write("/usr/bin/pip list\n")
p.stdin.write("id -u")
print(p.communicate()[0])
But be very sure you know what commands you are running.
I recently published a project that allows PHP to obtain and interact with a real Bash shell (as user: apache/www-data or root if needed). Get it here: https://github.com/merlinthemagic/MTS
After downloading you would simply use the following code:
//Setting the second argument in getShell():
//true will return a shell with root
//false will return a shell with the php execution user
$shell = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1 = $shell->exeCmd("mkdir -p /some/path");
$return2 = $shell->exeCmd("ls --color=none /some/path");
notice the ls command has a switch called --color=none, that is needed because the bash shell will return color information as odd chars, the switch prevents it.

How can I make my custom shell work with ssh?

I'm making a custom shell in Python for a very limited user on a server, who is logged in via ssh with a public key authentication. They need to be able to run ls, find -type d, and cat in specific directories with certain limitations. This works fine if you run something like ssh user#server -i keyfile, because you see the interactive prompt, and can run those commands. However, something like ssh user#server -i keyfile "ls /var/log" doesn't. ssh simply hangs, with no response. By using the -v switch I've found that the connection is succeeding, so the problem is in my shell. I'm also fairly certain that the script isn't even being started, since print sys.argv at the beginning of the program does nothing. Here's the code:
#!/usr/bin/env python
import subprocess
import re
import os
with open(os.devnull, 'w') as devnull:
proc = lambda x: subprocess.Popen(x, stdout=subprocess.PIPE, stderr=devnull)
while True:
try:
s = raw_input('> ')
except:
break
try:
cmd = re.split(r'\s+', s)
if len(cmd) != 2:
print 'Not permitted.'
continue
if cmd[0].lower() == 'l':
# Snip: verify directory
cmd = proc(['ls', cmd[1]])
print cmd.stdout.read()
elif cmd[0].lower() == 'r':
# Snip: verify directory
cmd = proc(['cat', cmd[1]])
print cmd.stdout.read()
elif cmd[0].lower() == 'll':
# Snip: verify directory
cmd = proc(['find', cmd[1], '-type', 'd'])
print cmd.stdout.read()
else:
print 'Not permitted.'
except OSError:
print 'Unknown error.'
And here's the relevant line from ~/.ssh/authorized_keys:
command="/path/to/shell $SSH_ORIGINAL_COMMAND" ssh-rsa [base-64-encoded-key] user#host
How can I make the shell script when the command is passed on the command line so it can be used in scripts without starting an interactive shell?
The problem with ssh not responding is related to the fact that ssh user#host cmd does not open a terminal for the command being run. Try calling ssh user#host -t cmd.
However, even if you pass the -t option, you'd still have another problem with your script: it only works interactively and totally ignores the $SSH_ORIGINAL_PROGRAM being passed. A naive solution would be to check sys.argv and if its bigger than 1 you don't loop forever, and instead only execute whatever command you have in it.

Categories