I'm trying to run a command with paramiko
that should be able to open an X window. The script I'm using would something as follows:
import paramiko
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect('192.168.122.55', username='user', password='password')
transport = ssh_client.get_transport()
session = transport.open_session()
session.request_x11()
stdin = session.makefile('wb')
stdout = session.makefile('rb')
stderr = session.makefile_stderr('rb')
session.exec_command('env; xterm')
transport.accept()
print 'Exit status:', session.recv_exit_status()
print 'stdout:\n{}'.format(stdout.read())
print 'stderr:\n{}'.format(stderr.read())
session.close()
Unfortunately, when I run the script above, I get this output:
Exit status: 1
stdout:
SHELL=/bin/bash
XDG_SESSION_COOKIE=8025e1ba5e6c47be0d2f3ad6504a25ee-1347286654.617967-1932974971
SSH_CLIENT=192.168.122.1 58654 22
USER=user
MAIL=/var/mail/user
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PWD=/home/user
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/user
LOGNAME=user
SSH_CONNECTION=192.168.122.1 58654 192.168.122.55 22
DISPLAY=localhost:10.0
_=/usr/bin/env
stderr:
xterm: Xt error: Can't open display: localhost:10.0
If I run the following command in a terminal:
ssh -X [email protected] 'env; xterm'
then I get the same environment variables (some ports changed, though), so I'd say that my environment is correct. However, I'm still missing something to make paramiko
work with x11 forwarding.
A couple of things I tried are:
handler
parameter in request_x11
: aside from printing values, I didn't get any further than with the default handler.auth_cookie
parameter in request_x11
: tried to hardcode a cookie value that was being used according to the xauth list
output. The idea of doing this was to avoid problems that might happen according to the documentation string in paramiko
itself:If you omit the auth_cookie, a new secure random 128-bit value will be generated, used, and returned. You will need to use this value to verify incoming x11 requests and replace them with the actual local x11 cookie (which requires some knoweldge of the x11 protocol).
Is there some other thing I could do to make it work or troubleshoot the problem?
Note: This has been previously asked in:
request_x11
documentation I've already tried to use to no avail.handler
parameter, but it's wrong.Paramiko helps you automate repetitive system administration tasks on remote servers. More advanced Paramiko programs send the lines of a script one at a time. It does this rather than transacting all of a command, such as df or last , synchronously to completion.
Is paramiko safe to use? The python package paramiko was scanned for known vulnerabilities and missing license, and no issues were found. Thus the package was deemed as safe to use.
Paramiko is a Python library that makes a connection with a remote device through SSh. Paramiko is using SSH2 as a replacement for SSL to make a secure connection between two devices. It also supports the SFTP client and server model.
Paramiko Expect provides an expect-like extension for the Paramiko SSH library which allows scripts to fully interact with hosts via a true SSH connection. The class is constructed with an SSH Client object (this will likely be extended to support a transport in future for more flexibility).
Reading the paramiko code, I realized that paramiko only implements a way to establish an x11 channel. It does not connect the channel to the local x11 display. That is left to you.
Here is a small implementation that I have just written:
#!/usr/bin/env python
import os
import select
import sys
import paramiko
import Xlib.support.connect as xlib_connect
local_x11_display = xlib_connect.get_display(os.environ['DISPLAY'])
local_x11_socket = xlib_connect.get_socket(*local_x11_display[:3])
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect('server', username='username', password='password')
transport = ssh_client.get_transport()
session = transport.open_session()
session.request_x11(single_connection=True)
session.exec_command('xterm')
x11_chan = transport.accept()
session_fileno = session.fileno()
x11_chan_fileno = x11_chan.fileno()
local_x11_socket_fileno = local_x11_socket.fileno()
poller = select.poll()
poller.register(session_fileno, select.POLLIN)
poller.register(x11_chan_fileno, select.POLLIN)
poller.register(local_x11_socket, select.POLLIN)
while not session.exit_status_ready():
poll = poller.poll()
if not poll: # this should not happen, as we don't have a timeout.
break
for fd, event in poll:
if fd == session_fileno:
while session.recv_ready():
sys.stdout.write(session.recv(4096))
while session.recv_stderr_ready():
sys.stderr.write(session.recv_stderr(4096))
if fd == x11_chan_fileno:
local_x11_socket.sendall(x11_chan.recv(4096))
if fd == local_x11_socket_fileno:
x11_chan.send(local_x11_socket.recv(4096))
print 'Exit status:', session.recv_exit_status()
while session.recv_ready():
sys.stdout.write(session.recv(4096))
while session.recv_stderr_ready():
sys.stdout.write(session.recv_stderr(4096))
session.close()
Some notes:
I'm using some helper functions from python-Xlib. This is a pure python implementation of Xlib. See this question for details on installing it: How do you install Python Xlib with pip?
Some of the details of how I have implemented this make me believe it will only work for 1 x11 connection (hence session.request_x11(single_connection=True)
.) I would like to keep working at this to get it to handle multiple connections, but that will have to wait for another day.
This code essentially connects the following channels/sockets together in a async fashion using select.poll
:
session.stdout
-> sys.stdout
session.stderr
-> sys.stderr
x11channel
-> local_x11_socket
local_x11_socket
- > x11channel
The paramiko
module outputs alot of usefull debuging info to the logging
module. You can view this by configuring the logging module:
import logging
logging.basicConfig(level=logging.DEBUG)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With