http://www.perlmonks.org?node_id=886133


in reply to Re: passwords with special characters are trying to kill me... no seriously!
in thread passwords with special characters are trying to kill me... no seriously!

my $set_password = '/usr/bin/ssh ' . $master_host . " 'echo \Q$new_pas +sword\E | /usr/bin/passwd --stdin \Q$username\E'";

Unfortunately, that won't work if the password contains, for example, a single quote.

my $master_host = 'localhost'; my $username = 'foo'; my $new_password = 'a\'b$c"d|e'; print "pwd: ",$new_password; my $set_password = '/usr/bin/ssh ' . $master_host . " 'echo \Q$new_pas +sword\E | /usr/bin/passwd --stdin \Q$username\E'"; print "cmd: ",$set_password; system $set_password; __END__ pwd: a'b$c"d|e cmd: /usr/bin/ssh localhost 'echo a\'b\$c\"d\|e | /usr/bin/passwd --st +din foo' sh: Syntax error: Unterminated quoted string

In other words, a simple quotemeta (\Q) is not the appropriate tool to quote arbitrary strings for the shell. You'd have to use more sophisticated techniques.

Replies are listed 'Best First'.
Re^3: passwords with special characters are trying to kill me... no seriously!
by ikegami (Patriarch) on Feb 04, 2011 at 17:55 UTC

    It's easy if you build the command in stages.

    sub text_to_shell_lit(_) { return $_[0] if $_[0] =~ /^[a-zA-Z0-9_\-]+\z/; my $s = $_[0]; $s =~ s/'/'\\''/g; return "'$s'"; } my $user = 'bob'; my $passwd = 'test$ing'; my $echo_cmd = join ' ', map text_to_shell_lit, echo => $passwd; my $passwd_cmd = join ' ', map text_to_shell_lit, passwd => '--', $user; my $ssh_cmd = join ' ', map text_to_shell_lit, ssh => 'hostname', "$echo_cmd | $passwd_cmd";
    ssh hostname 'echo '\''test$ing'\'' | passwd -- bob'

    Note that command lines are readable by anyone on the machine. It is not safe to pass passwords in command lines. Yet another reason why opening a pipe to ssh is better.