Application is not prompting confirmation message during runtime via popen in python - python

I have a application which I have to load via POpen in python.During runtime,application will prompt a confirmation message stating "Can I continue?".Over here,we have to provide yes/no option.
The POpen executes the command properly but the application doesn't prompt for "Can I continue" message.It just stops at that point.If I run the application manually,application prompts for confirmation message.
proc=subprocess.Popen(['app.exe -start'],shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
Let me know in case I am missing some parameters.

If you pass the stdout=subprocess.PIPE option, the output is redirected to a PIPE and not displayed. You can compare those two functions :
p1 = subprocess.Popen(["ls"])
p2 = subprocess.Popen(["ls"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
The first one prints the output of the command, the second does not. But you can access it with p2.stdout.read().
So if you want to see the output of your script (and to manually type the confirmation), use
proc = subprocess.Popen(['app.exe -start'], shell=True)
Else, you have to interact with proc.stdin and proc.stdout
PS : The use of shell=True is discouraged, remove it if you can. It is especially important if the command you want to run contains some user input.

Related

How to capture stdout of shell after switching users

I'm making a shell with python. So far I have gotten cd to work (not pretty I know, but it's all I need for now). When I su root (for example) I get a root shell, but I can't capture the output I receive after running a command. However the shell does accept my commands, as when I type exit it exits. Is there a way to capture the output of a 'new' shell?
import os, subprocess
while True:
command = input("$ ")
if len(command.split(" ")) >= 2:
print(command.split(" ")[0]) #This line is for debugging
if command.split(" ")[0] == "cd" or command.split(" ")[1] == "cd":
os.chdir(command.split(" ")[command.split(" ").index("cd") + 1])
continue
process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, universal_newlines=True)
output, error = process.communicate()
print(output.strip("\n"))
EDIT: To make my request a bit more precise, I'd like a way to authenticate as another user from a python script, basically catching the authentication, doing it in the background and then starting a new subprocess.
You really need to understand how subprocess.Popen works. This command executes a new sub-process (on a Unix machine, calls fork and then exec). The new sub-process is a separate process. Your code just calls communicate once and then discards of it.
If you just create a new shell by calling subprocess.Popen and then running su <user> inside of it, the shell will be closed right after that and the next time, you'll be running the command using the same (original) user again.
What you want is probably to create a single subprocess at the beginning of your application and then be a sort of a proxy between the user and the underlying process, and then just keep writing to its stdin and reading from stdout.
Here's an example:
import os, subprocess
process = subprocess.Popen(["bash"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, universal_newlines=True)
while True:
command = input("$ ")
process.stdin.write(command + "\n")
process.stdin.flush()
output = process.stdout.readline()
print(output.strip("\n"))
(I removed the cd command parsing bit because it wasn't constructive to understanding the solution here, but you can definitely add specific handlers for specific inputs that wrap the underlying shell)

How i can interact with some CLI runned in terminal?

For now i have some Command-Line Interface which one i need to interact. (e.g. run this CLI in terminal, then execute few comands inside of it).
In terminal it looks the next way:
blabla-cli
some-comand
%response%
next-command
And all of it i want to automate with python.
Almost all what i could fing in the Google is about using Popen and comunicate or process.stdin to do what i want.
But in case of using provided code i can't send any comand to process, i mean "help" wont be sended to terminal
args = ["blabla-cli"]
process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8')
process.wait()
process.stdin.writelines('help')
process.wait()
print(process.stdout.readlines())
I expect to send some command to terminal via python code, get some response and get some actions with recieved response.

Pyinstaller executable doesn't run processes when hidden

I'm trying to run a single-file python executable packaged with PyInstaller. The script contains system commands that need to be executed. However, when I attempt to run them (on windows) they do not execute. The thing is, they only fail to execute when the PyInstaller option no-console is used, which hides the console and runs it in the background.
I am using the following options: --noconsole and -F.
I have not only tried the subprocess.open function, but also os.popen(), both of which do not work.
Also, I need console output, so os.system() will not be an option... please answer with this in mind. Although, this function did actually execute the commands, so I think getting output is the issue. I am assuming that I have to change the standard output or something, or maybe if a command is executed without a console, the output is lost or never generated in the first place. Sorry if I sound inexperienced.
I do not have any antivirus software running on my computer, and no Windows Defender, etc. messages are appearing. I understand that this is a precarious combination - running system commands whilst hidden - I only wish to make a non-malicious program that kills another program every minute. Sorry if there is anything left unclarified... just ask if anything is unclear. Thanks :)
EDIT
Here's some code to help
command = data['command']
command_split = command.split(" ")
p = subprocess.Popen(command_split, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
result = out.decode() if out else err.decode()
io.emit("client:console_output", {
'output':result,
'adminID':data['adminID']
})
EDIT 2
Understand that this function is working when the console is not hidden; therefore, it is nothing to do with the logic or code, it is solely because it is being hidden. Here is the output anyway.
x = "taskkill /im chrome.exe /f"
print(x.split(" "))
-> ['taskkill', '/im', 'chrome.exe', '/f']
You need to use subprocess.PIPE to redirect the process output to a variable. You also need to handle subprocess stdin and close it manually.
Then you can simply disable console with -w or --noconsole flag.
import subprocess
p = subprocess.Popen(["ipconfig"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
out, err = p.communicate()
p.stdin.close()
result = out.decode() if out else err.decode()

How to pass 2 consecutive arguments using POpen communicate()

I am trying to execute a linux command through Python.
Here, for one of the command (cryptsetup luksChangeKey) I need to pass two keys [current key and new key] when prompted by the command through STDIN.
I tried using communicate() for the same and not able to pass both the keys.
Is there any other option available in python for the above scenario ?
Sample Code:
import subprocess
cmd = 'cryptsetup --batch-mode --key-file - luksChangeKey
/dev/multiplelv_pool_VG_13341/lv4'
process = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.stdin.write("old123\nnew123\n")
process.communicate()
process.stdin.close()
If we manually execute the cryptsetup command, then it will prompt for old key and then the new key to be provided.
I am trying to simulate the same through the Python code.
Here current password is old123 and new password is new123.
My expectation of using '\n' in stdin.write was to split the password into two lines. However, POpen is taking the entire
line as current password and resulting in error
I am using Python 2.7
This work for me:
other.py
a = input()
b = input()
print(a, b)
program.py
import subprocess
cmd = r'python other.py'
process = subprocess.Popen(cmd, stdin=subprocess.PIPE)
process.communicate("input1\ninput2".encode('utf-8'))
process.stdin.close()
# print: >>> input1 input2
The subprocess documentation warns about the use of stdin.write.
Also, I don't know how your code doesn't throw an error, since you are passing a string to stdin and not a bytes-like object? This is what happens for me with your code:
TypeError: a bytes-like object is required, not 'str'
This is not a Python problem but a cryptsetup limitation. It is explicit in the manpage (emphasize mine):
--key-file, -d<br/>
use file as key material.
... If the key file is "-", stdin will be used. With the "-" key file reading will not stop when new line character is detected.
and later:
Notes on Password Processing
...
From stdin: Reading will continue until EOF
Workarounds:
According to this post on SuperUser, it used to be possible to pass both the old and new passwords in the same keyfile, but it would no longer be possible. A trick would be to use stdin for the old key, and stdout for the new one. Python will refuse to write on a process.stdout file because it is only opened for reading, but it is still possible to write on it at the fileno level. Code would become:
import subprocess
cmd = 'cryptsetup --batch-mode --key-file - luksChangeKey
/dev/multiplelv_pool_VG_13341/lv4 /dev/fd/1' # read the new key from /dev/fd/1
process = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
os.write(process.stdout.fileno(), 'new123')
process.communicate('old123')
Beware: untested because I currently have no Linux system with LUKS.
A way to trick cryptsetup would be to use the pexpect-module (needs to be installed separately). This runs a subprocess faking a controlling terminal. It then allows to wait for prompts and issue user input when prompted. This is e.g. a way to control SSH and enter a password instead of having to resort to public keys etc.

How to use Popen with an interactive command? nslookup, ftp

Is there any way to use Popen with interactive commands? I mean nslookup, ftp, powershell... I read the whole subprocess documentation several times but I can't find the way.
What I have (removing the parts of the project which aren't of interest here) is:
from subprocess import call, PIPE, Popen
command = raw_input('>>> ')
command = command.split(' ')
process = Popen(command, stdout=PIPE, stderr=PIPE, shell=True)
execution = process.stdout.read()
error = process.stderr.read()
output = execution + error
process.stderr.close()
process.stdout.close()
print(output)
Basically, when I try to print the output with a command like dir, the output is a string, so I can work with the .read() on it. But when I try to use nslookup for example, the output isn't a string, so it can't be read, and the script enters in a deadlock.
I know that I can invoke nslookup in non-interactive mode, but that's not the point. I want to remove all the chances of a deadlock, and make it works with every command you can run in a normal cmd.
The real way the project works is through sockets, so the raw_input is a s.recv() and the output is sending back the output, but I have simplified it to focus on the problem.

Categories