Calling an application from inside a python script Take 1

Donn Cave donn at u.washington.edu
Fri Jan 5 12:54:16 EST 2001


Quoth Chris Watson <chris at voodooland.net>:
(Quoting myself)
|> The easiest thing to write is
|> 
|>     import os
|>     ...
|>     os.system('ssh -l root %s vi /usr/local/etc/apache.conf' % host)
|> 
|> 
|> It's also about as dangerous as anything you can do in Python.  It
|> puts you completely at the mercy of whoever typed in that text at
|> the "Enter a hostname: " prompt.  Intentionally or not, a space
|> or a semi-colon etc. could yield very different results than you
|> intend.
|
| Someone else pointed out the exact same way. However they also described
| it was bad h0h0 magic to do it that way. So...
|
|> Luckily, with Python 2.0 we're getting to the point where you can
|> do this in a safer way without writing all the fork & exec stuff
|> yourself.  The function, os.spawnv(), is apparently here for
|> compatibility with Windows!  but it seems to be what we need;
|> you can look at the os module to see how it works if you want.
|> 
|>     import os
|>     os.spawnv(os.P_WAIT, '/usr/local/bin/ssh', ('ssh', '-l', 'root',
|>         host, 'vi', '/usr/local/etc/apache.conf'))
|> 
|> That last argument is a tuple of the argument list to ssh, starting
|> with argv[0].  In the system() function, we would eventually invoke
|> the shell to parse the string into these arguments, and that's where
|> the unexpected metacharacters wreak their havoc.  By passing the
|> arguments directly to the ssh process, we avoid that.
|
| I had thought about this briefly as well. And decided on an earlier
| repliers advice it would be wiser to copy the file to the local machine
| instead of editing it remotely.
|
|> Now, for this particular command, ssh, you might as well fold the
|> 'vi' and the file together, because ssh is going to do that for
|> the remote shell to parse back out.  So don't think you can get
|> a sanitary calculated argument list through to the remote shell -
|> that can't happen.  Your example is OK, because the remote command
|> is constant.
|
| Well what I finally came up with, and I am no coder by any means, was the
| following:
|
| #!/usr/local/bin/python
|
| import os
|
| host = raw_input("Enter a hostname: ");
|
| # Copy the file from the remote server to the local machine.
| os.system("scp user@%s:/home/user/TESTFILE /tmp/TESTFILE" % host) 
|
| # Edit the local copy.
| os.system("vi /tmp/TESTFILE")
|
| # "Push" the new config file from the local machine to the remote machine
| # using a secure ssh transport
| os.system("rsync -v -P -p -e ssh /tmp/TESTFILE user@%s:/home/user/TESTFILE" % host)

So picture what happens if the input isn't legit.

  os.system("scp user@%s:/home/user/TESTFILE /tmp/TESTFILE" % "; rm -r /*; ")
--> scp user@; rm -r /*; :/home/user/TESTFILE /tmp/TESTFILE

Want to try that and see what happens?  That's an intentionally hostile
input (don't try it, really.)  Accidental input errors might be harmless,
or might not.

I didn't see anything wrong with the ssh in your initial post, the
problem was system().  system() + user-supplied input = unpredictable
results.  Use spawnv().

	Donn Cave, donn at u.washington.edu



More information about the Python-list mailing list