Julionabi
Julionabi

Reputation: 83

ssh-keygen raise password too short error when called with subprocess

I would like to know if I need to do something differently when I call ssh-keygenin a script by usingsubprocessor 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

Answers (1)

Mad Physicist
Mad Physicist

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

Related Questions