telnetlib write() some command not working in Python - python

I'm using Python's telnetlib.write() function for quite some time without issues, but in this case the command that I want to send does nothing. While the same command sent through SecureCRT works fine.
Here's more or less what I have:
import telnetlib
tn = telnetlib.Telnet(HOST)
tn.read_until('login: ')
tn.write(user + '\n')
if pswrd:
tn.read_until('Password: ')
tn.write(pswrd + '\n')
tn.write('echo "" > /path/to/file.log' + '\n')
tn.write('exit\n')
tn.close()
What this should do is clear the contents of file.log, but the file remains the same. Why is this happening?
If it's worth mentioning, the telnet server is running SunOS. Thanks!

Your problem is almost certainly a timing error.
Without being able to debug it, or seeing the results of you debugging it, it's hard to be sure exactly what the problem is, but my guess is something like this:
The SunOS machine's telnetd server has a relatively small buffer, say 16 bytes. So, if you send it that whole command before the shell has started, it's only going to send 16 bytes of it to the shell. Which will, of course, not do what you want. But if you wait until the shell has started, it'll get the whole command, and therefore work.
By adding tn_setdebuglevel(1) to your program, you're changing the timing—the extra time it takes to print out the debugging information is just enough to (usually) give the shell time to start before you've filled up the buffer, so it happens to work.
The password prompt probably has the same problem, which you solved by using `tn.read_until('Password: '). You just need to do the same thing here. For example (depending on what the expected prompt is):
# ...
tn.read_until('$')
tn.write('echo "" > /path/to/file.log\n')
tn.read_until('$')
tn.write('exit\n')
tn.close()

Related

Why is Pycharm failing to convert string to integer?

num = 0
for i in range(5):
ask = int(input())
if abs(ask) > 0:
num = ask
print(num)
When I run the code, it lets me input the first string. But once I enter the second string, the program crashes and says "pythonProject\main.py", line 3, in
ask = int(input())
ValueError: invalid literal for int() with base 10: ''"
What's going on?
My input: I just type 1, press enter, type 2, press enter and then it crashes. I am sure it is not an error where I click enter too quickly, or I accidentally type in an empty string because I've ran the code multiple times.
What have I tried so far?
Creating a new project and pasting the code -> didn't work
Asking my friend to copy the code onto his PyCharm and run it -> worked fine on his computer
'Edit configurations', uncheck 'emulate code in output console' -> didn't work, it was already unchecked
Checked that I was running the correct file in the project -> didn't work, I was running the right file
EDIT:
FIXED, just needed to check 'Emulate code in output console' rather than uncheck it. Not sure why this works though, or how I can keep it checked for all future projects - rather than having to manually check it every time.
FIXED, just needed to check 'Emulate code in output console' rather than uncheck it. Not sure why this works though, or how I can keep it checked for all future projects - rather than having to manually check it every time.
The problem is with the input, as you are either pressing enter without any input (empty string) or you are entering a float value. This thread might help you in this case. The code is working fine when I input an integer and gives the same error when entered empty string or a float value.
To get it work you need to check "Emulate code in output console".
I've answered in the comments section and I'm glad it worked out, here is an explanation:
You need to know a concept of "terminal emulator" to understand why and how this works. When a program is ran (at least on UNIX-like operating systems), it has three I/O streams: stdin, stdout and stderr. The stdin is used to input data, and two others are for output.
Input or output stream is just a buffer used to communicate with the program back and forth. Once something is written to the buffer, it can be read from there. If the buffer is empty, an attempt to read from there will cause stall until the buffer has something in it. More about stdio: https://en.wikipedia.org/wiki/Standard_streams
When the program is ran through the terminal emulator, I/O streams are connected to this emulator, so whatever you type in the terminal window is written to your stdin by default. Whatever your program writes to the stdout and stderr is displayed on the screen. (However, this behavior may be changed using pipes, so you can pass data from some file to the stdin and also you can redirect the output to the file)
Here is the history behind terminal emulators, to understand, why is it implemented this way: https://en.wikipedia.org/wiki/Terminal_emulator#Computer_terminals
For example, you have a simple program:
s = input('Enter string: ')
print(f'stdout: {s}')
If you run it from the terminal and type "TEST":
$ python3 test.py
TEST
stdout: TEST
But you also can, for example, pass data directly to stdin, and redirect output to the file:
$ echo "ABCDEF" | python3 test.py > OUTPUT.txt
there will be no text in the terminal, but OUPUT.txt will appear. It will contain:
stdout: ABCDEF
Now, about PyCharm:
By default, when it runs your script, it does not automatically emulate terminal in the output window. It simply does not send anything to the stdin and it won't react to pressed keys. When your program gets to the line with input(), it starts to read the stdin stream until it gets \n character from the stream (indicating that user has pressed Return key). As nothing gets sent to the stream, it will wait infinitely.
Useful tip: for testing, instead of just typing something into the terminal every time, you can also check "Redirect input from:" and choose an input file.

using python to ssh fully into server

I've been trying to automate ssh'ing into my server however cannot find a way to fully automate the process. To be specific, getting around this input has been the struggle: root#example's password:
My code:
import subprocess
import time
server_ip = 'server'
pwd = b'password'
p = subprocess.Popen(['ssh', 'root#{}'.format(server_ip)],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
if p == "root#example's password: ":
p.communicate(input= "{}".format(pwd))
else:
time.sleep(2)
if p == "root#example's password: ":
p.communicate(input= "{}".format(pwd))
else:
pass
What it returns:
Pseudo-terminal will not be allocated because stdin is not a terminal.
root#example's password:
user#computer ~ % Permission denied, please try again.
root#example's password:
Permission denied, please try again.
root#example's password:
root#example: Permission denied (publickey,password).
I know my code is very scuffed but it is the furthest I've got to getting in and submitting the password entry request.
Any help is appreciated!
if p == "root#example's password: ": can never be true; p is a subprocess.Popen object, not a string.
You can get a string by reading from the object's standard output, but of course, ssh prints the prompt message on the tty, so you can't easily capture it from Python.
Notice also that without an encoding keyword argument or text=True, you can't send or receive strings; the output you receive will be a b'...' byte string which cannot be compared to a regular string.
... But even if you managed to sort out these problems, taking it from there to a fully working interactive SSH session is still quite some distance to go. I would definitely recommend that you try pexpect or Paramiko instead of rolling your own, especially if you are new to Python.
Tangentially, else: pass is completely unnecessary; there is no reason to add an else: block in the first place if you don't have anything useful to put in it.
And
As "{}".format(pwd) is a really hairy way to write what can be more easily expressed as pwd, or str(pwd) if it's not already a string.

Mysterious behavior with pySerial

I got the following problem:
I have a Arduino here which is connected to my Mac.
The Arduino is reading and responding to serial data.
I made a little python3-script which takes user input and uses
pySerial to write commands like 'set(13, 255)~' to the Arduino.
That is just working fine:
while 1:
cmd = input("<<< ")
cmd += '~'
if cmd != "~":
serialPort.write(cmd.encode())
output = str(serialPort.readline()).upper()[2:-5]
if output != " ":
print(">>> ", output)
Here's the Problem:
If I want to send some "automated" commands within the script, e.g. in a loop, the Arduino is not responding anymore, even the commands send are
the same, also encoded and of type "byte".
for i in range[0, 256]:
cmd = 'set(13, '
cmd += str(i)
cmd += ')~'
serialPort.write(cmd.encode())
time.sleep(0.1)
The strange thing is, if i first declare the variable (cmd) as an input, its also working fine, but that means a manual interrupt every time the command is send.
cmd = input()
cmd = 'set(13, '
cmd += str(i)
cmd += ')~'
After some hours of research i absolutely have no idea what the problem might be. As I said, the datatype is always byte after encoding.
I don't know about PySerial, but I suspect it's because the write call don't send the data immediately.
When you use the input, it will add a newline to the buffer, which may trigger the write call to flush automatically.
In the other piece of code you have, you don't add a newline to the buffer and it won't flush the data, before the buffer is big enough.
So with a flush() call it should force send it.
Hope it makes sense
Well, I just had to make a longer interrupt after connecting to the port.
(Has not been a problem since I had to give some input so far)

Sending variables to bash from python

I have tried my best to research and I have got to the point where I am using subprocess and subprocess.call to help me send my python variables to bash. I managed to get my python variables from bash output but now I need these variables to be in sync. I looked around couldn't learn how to use subprocess.call effectively. I have been using subprocess.check_output to obtain bash output into python variables flawlessly. I am having troubles understand how subprocess.call accepts arguments and how to use it properly. I tried following what I believed to be the correct format.
Here is my code. P.S I am brand new to joining this forum although I have been using it for tons of usefull information over the years. I dont know how to format my code input to look nice like how I see all over here. Regardless im sure you can forgive me as I tried the "Code" "Blockquotes" etc buttons.
###BEGINING OF CODE###
#! /usr/bin/env python2
import os,time,subprocess
#GRAB DATA
os.system('ifconfig > /tmp/ifconfig.txt;clear;cat /tmp/ifconfig.txt|grep "wlan"|cut -c 1-5 > /tmp/dev.lst;clear;')
#SET allwlan
allwlan=subprocess.check_output("cat /tmp/dev.lst", shell=True)
#SET max_index VARIABLE
max_index=subprocess.check_output("wc -l < /tmp/dev.lst", shell=True)
#SET curwlan WLAN LINE
#os.system(echo 2 > /tmp/curline.lst)
#STRIP DATA FOR curwlan
subprocess.call(['head', '-2', '/tmp/dev.lst', stdout=subprocess.PIPE, shell=True'])
#NEED#HELP#HERE# subprocess.call(['tail', '-1', > /tmp/curwlan.lst;')
#SET curwlan VARIABLE
curwlan=subprocess.check_output("cat /tmp/curwlan.lst", shell=True)
##STRIP EXCESS CHARACTERS/EMPTY LINES FROM VARIABLES##
curwlan=str(curwlan)
splitted=curwlan.split()
curwlan=splitted[0]
allwlan=allwlan[:-1]
splitted=max_index.split()
max_ index=splitted[0]
max_index=int(max_index)
##DEBUG MODE
print("Welcome, ")
print(" to debug mode. wireless adapter decting algorithm")
print
print("ALLWLAN:")
print(allwlan)
print
print("CURWLAN:")
print(curwlan)
print
print("MAX_INDEX:")
print(max_index)
print
input("PRESS ENTER TO EXIT")
####END OF CODE####*
The error in my code is under
#STRIP DATA FOR curwlan
Here is the output of that before I added the subprocess.call command.
Welcome,
to debug mode. wireless adapter decting algorithm
ALLWLAN:
wlan0
wlan3
CURWLAN:
wlan2
MAX_INDEX:
2
PRESS ENTER TO EXIT
I would love to learn how to have my python and bash parts communicate their variables together and I know I am on the right track with subprocess.call and ive been struggling for a few days now. I am trying to make my own algorithm to detect my wireless cards and be able to use each one (how ever many that may be or regardless what they may be named) as a variable for my
older scripts which now are struggling because of my constantly changing wireless card names. Thanks in advance I don't understand if what i'm asking subprocess.call to do is unrealistic or not.
You will want to avoid external processes as much as possible. Most of what you are doing is easy to do in just Python, and will be much more compact as well as more efficient if implemented natively.
Also, you are mixing the obsolete os.system() with subprocess where the latter is generally to be preferred, as also pointed out in the os.system() documentation.
subprocess.call() is only really appropriate when you don't expect any output from a command. The instance where you tried to use it, subprocess.check_output() would be the proper call to use. However, the places where you (as I understand, needlessly) ran shell commands with output to temporary files, you could have used subprocess.call(), trivially.
You need to understand when and where a shell is useful and necessary. Many places where you have shell=True would be more secure, faster, simpler, and more straightforward without a shell. Where you only run a simple hard-coded command with no redirection or globbing, switching from subprocess.whatever('command with args', shell=True) to subprocess.whatever(['command', 'with', 'args']) will instantly reduce your time and memory footprint with no ill effects. If you need redirection, pipelines, or globbing, maybe you want shell=True; but in many cases, doing those things in Python will be simple and straightforward. For example, here is how the head command could have been written without a shell:
with open('/tmp/randomfile', 'w') as outputfile:
subprocess.call(['head', '-n', '2', '/tmp/dev.lst'], stdout=outputfile)
Anyway, with these things out of the way, here is how I would do what (I think) you are attempting:
#!/usr/bin/env python2
import subprocess
allwlan = []
ifconfig = subprocess.check_output(['ifconfig'])
for line in ifconfig.split('\n'):
if "wlan" in line:
allwlan.append(line[0:5].strip())
max_index=len(allwlan)
curwlan=allwlan[1]
This was hastily thrown together, but I believe I captured at least most of what your current pretzel logic code does; though I have assumed that sprinkling the /tmp file system with random output files was not an essential feature of your script.
Thank you all for your advice. My script has come along way; Here is what this part looks like, over 1 year later,
def detmon():
try:
subprocess.call(['clear'])
item = []
items = []
the_choice = []
iwconfig = subprocess.check_output(['iwconfig'])
for line in iwconfig.split():
if "mon" in line:
items.append(line.strip(':'))
subprocess.call(['clear'])
max_index=len(items)-1
#items=items[counter]
#Print Files List
for item in items:
print(" ", items.index(item), ": ", item)
os.system('echo "\n"')
print(len(items))
try:
if len(items) >= 0:
counter = 0
allmon = []
ifconfig = subprocess.check_output(['iwconfig'])
for line in ifconfig.split():
if "mon" in line:
allmon.append(line.strip(':'))
subprocess.call(['clear'])
max_index=len(allmon)
curmon=allmon[counter]
while counter <= max_index:
curmon=allmon[counter]
subprocess.call(['airmon-ng', 'stop', curmon])
counter += 1
else:
print("No more 'mon' interfaces are found")
except:
print("No more 'mon' interfaces are found")
except KeyboardInterrupt:
pass

Paramiko exec command failure based on time

I have been searching and fooling around with this problem for 2 days now. Firstly, some context in the form of (summarised) code.
def setService(self, ...
ssh_client = self.conn.get_ssh_client(hostname, username=username, password=password)
setCommand = str('service ' + service_name + ' ' + status)
stdin, stdout, stderr = ssh_client.exec_command(setCommand)
# time.sleep(2)
return ...
Secondly. The whole codeset uses the same code, and everything works except for this "service foobar stop" and "service foobar start" command. It causes a Read Error (in ssh/auth.log) and does not actually effect the command. All other commands using this setup works fine (we do about 10 different commands). It happens on all target machines, from both dev machines, so I am ruling out ssh configs.
But, if I add any time delaying code after the exec_command(in the comment position), it works. A sleep(2), or a loop doing some debug printing, makes it work fine. Read Errors disappear from the auth.log and service start/stop as they should. Removing the sleep, or whatever it may be, breaks it again.
We "hack" fixed it by leaving a sleep in there, but I do not understand completely why it happens, or why stalling in the function fixes it.
Are we returning too quickly, before the exec was finished on the remote side? I do not think so, it seems to be blocking (returning into stdin, stderr, stdout).
Any advice on this would be highly appreciated.
Note: exec_command(command) is non-blocking..
I usually try to read the output from the buffer(which consumes some time - before returning), or I use a time.sleep which you've used in this case.
If you use(should) stdout.read()/readlines(), it forces your script to return the output in the stdout buffer, and in turn wait for exec_command to finish.

Categories

Resources