Reputation: 83
I would like to know if I need to do something differently when I call ssh-keygen
in a script by usingsubprocess
or not .
I'm running in a Linux Environment.
Here is my code:
cfg_r = configparser.ConfigParser()
cfg_r.read('ssh_config.cfg')
p_mail=cfg_r.get('Company', 'mail')
bashCo m mand="ssh-keygen -t rsa -f /home/pi/.ssh/id_rsa - C \"{}\" -q -N \"\"".format(p_mail)
print(bashCommand.split())
proc = subprocess.Popen(bashCommand.split(),
stdout=subprocess.PIPE,
stderr=open('logfile_Get_conf.log', 'a'),
preexec_fn=os.setpgrp
)
outpu.stdout.read().decode('utf-8')
I use configparser
to read email other than this, nothing special.
bashCommand
is as it should be:
ssh-keygen -t rsa -f /home/pi/.ssh/id_rsa -C "[email protected]" -q -N ""
bashCommand.split()
is as it should be too:
['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', '"[email protected]"', '-q', '-N', '""']
The thing that's very weird is when I run this bashCommand
in the shell, no problems occur:
ssh-keygen -t rsa -f /home/pi/.ssh/id_rsa -C "[email protected]" -q -N ""
But in my log file I still have this error:
Saving key "/home/pi/.ssh/id_rsa" failed: passphrase is too short (minimum five characters)
Where is the problem?
Upvotes: 1
Views: 837
Reputation: 114310
I am assuming that you are running in a Unix-like environment with a shell like bash
or similar (as the variable bashCommand
implies). Things work very differently in Windows.
When you run the command you show in the shell, the arguments passed to ssh-keygen
as argv
are (in Python syntax):
['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', '[email protected]', '-q', '-N', '']
The shell expands out the strings, and strips off any quotes. When you split your command, the arguments are passed as-is, since you did not specify shell=True
to Popen
. That means that ssh-keygen
's argv
will be
['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', '"[email protected]"', '-q', '-N', '""']
Hopefully you can see the difference. The argument to -N
is no longer empty. It is a two-character string ""
, which is clearly less than five characters.
You do not need the string bashCommand
. It is much more convenient to use lists, and pass things to Popen
directly that way:
bashCommand = ['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', p_mail, '-q', '-N', '']
proc = subprocess.Popen(bashCommand, ...)
Notice that this way, you don't need to do any string interpolation, fancy splitting, quoting, escaping, or other modifications to the command line.
I had mentioned that things work very differently on Windows. That's because on Windows, shell=True
is always set, and there is nothing you can do about it. Windows does not pass argv
to a program like Unix does. Instead, programs are responsible for parsing their own command line strings, so having the quotes is mandatory. Using shell=True
is generally frowned upon, so I don't recommend using it as a solution for the Unix-like case (but it would work).
As mentioned in the comments, there are other issues with robustness, maintainability, and aesthetics in your code. However, none of them should prevent it from functioning correctly.
Upvotes: 2