0

So, I am trying to pass parameters to a bash shell script across a python TCP socket connection. The script being executed in the bash shell always bombs out even though when I print the variable being passed to os.system() or subprocess.call() it looks correct. Any ideas? Small chunk of the code that is giving me issues.

while 1:
    conn, addr = s.accept()
    print 'Connected with ' + addr[0] + ':' + str(addr[1])    
    data = conn.recv(1024)
    if not data:
        break
    data2 = data.rstrip('\n')
    cmd = 'ls ' + data2
    #os.system(cmd)  
    subprocess.call([cmd], shell=True)
    print cmd
Brian White
  • 8,332
  • 2
  • 43
  • 67
  • You need to be specific about how it "bombs out". What _does_ happen, exactly? – Brian White Apr 06 '15 at 13:42
  • similar question [here](http://stackoverflow.com/questions/15869158/python-socket-listening/16512082#16512082) – Noelkd Apr 06 '15 at 13:51
  • Hi Brian, The program can locate the binary and runs it successfully in a bash shell however when attempting to add parameters in order to be passed to the bash binary, the binary does not interpret the parameters correctly causing it to return whatever error code that was programed for "invalid parameter" Using "ls" as an example: running "ls" works, passing "-l" to it fails when I print the variable cmd it returns what i would expect to work "ls -l" – user2740987 Apr 06 '15 at 16:35

1 Answers1

1

Python's subprocess call (doc) takes a single string to execute or a list of arguments. You're passing a string as a single argument and thus the entire thing is interpreted as the command to execute, which of course cannot be found.

subprocess.call(cmd, shell=True) or subprocess.call(['ls', data2])

The latter is preferred as it means a malicious caller cannot create arbitrary shell actions by passing "foo; rm -rf / &" down the socket.

Note: Better to use call(('ls', data2)) (parentheses instead of brackets) to create a simple Python "tuple" rather than a dynamic list for passing to call(...).

Brian White
  • 8,332
  • 2
  • 43
  • 67
  • Hi Bran, Thank you for the thoughts! I will try this out and let you know my results. – user2740987 Apr 06 '15 at 16:38
  • Hi Brian, Trying your suggested method `subprocess.call(('ls', data2))` leaves me still a bit broken. my output is: Connected with 127.0.0.1:36085 's: invalid option -- ' Try `ls --help' for more information. If I take the socket connection out of the equation and just try and pass the parameters to the script from statically assigned variables, it works great. I am thinking there is something to do with how the variable is created containing the information passed via the socket – user2740987 Apr 06 '15 at 21:21
  • What's the value of `data2`? Does it start with a dash? Also, you wrote "s: invalid option --"... was that supposed to be "ls: invalid option"? Sockets are raw 8-bit connections so as long as you're passing the exact characters that make up the destination filename, you should be fine. – Brian White Apr 07 '15 at 00:16
  • The value of `data2` does start with a dash. I have tried sending "-l" for "ls -l" and "--blue" for "blink1-tool --blue". Oddly enough, the error message is exactly how I typed it. Missing its first character. – user2740987 Apr 07 '15 at 01:20
  • Perhaps the issue is with how the data is being transferred. I am using telnet as a client. As a test I setup a number of IF statements directly after I receive the data on the server. Basically `if data == 1: print data else: print "fail"` On the client I sent "1" however it always falls through the first test and prints fail – user2740987 Apr 07 '15 at 02:15
  • Ok, got it to work. My test statements were missing the double quotes to test correctly. The way it works now. Client sends data to the server and the server runs through various `if elif else` to determine if the data sent matches a desired function. If the data sent matches, the `data2` variable is set to the correct value and passed to `subprocess.call()` This works great. Still does not explain why I cant set the `data2` variable directly from info received from the client. – user2740987 Apr 07 '15 at 02:49
  • Sounds like it was but, as you said, "the value of data2 does start with a dash" which means that the `ls` command would interpret it as an option. You could try `subprocess.call(('ls', '--', data2))`; the "--" argument will tell most GNU commands that everything that follows are _not_ options/flags. – Brian White Apr 08 '15 at 00:45