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 user@192.168.122.55 '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:
- Use the
handler
parameter inrequest_x11
: aside from printing values, I didn't get any further than with the default handler. - Use the
auth_cookie
parameter inrequest_x11
: tried to hardcode a cookie value that was being used according to thexauth list
output. The idea of doing this was to avoid problems that might happen according to the documentation string inparamiko
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:
- superuser: the only response points to the
request_x11
documentation I've already tried to use to no avail. - stackoverflow: the accepted response suggests to use the
handler
parameter, but it's wrong. - github: no answer provided for more than a year.
Given that you asked for a minimal version, which I understand as make it as easy to to use as possible. Here is a version based in both codes, but this separate the x11 session commands from the general code, making the main program simple and the session code reusable:
I know you could do it by yourself. However, but just by copying the function
run
anybody could use it without hassle.The right answer is https://stackoverflow.com/a/12903844/278878. This example is to make it easier for newcomers.
Thanks Gary van der Merwe and dnozay for their code. The code below heavily relies on it and serves for running X programs on Windows. The notable difference is using select.select instead of poll, as poll is not available in Windows. Any improvements or corrections are welcome.
x11
request may use aMIT-MAGIC-COOKIE-1
that you may not handled properly.Xauthority
file may also be an issuestrace
ssh process and see a normal flowxterm
withstrace xterm
and compare with the above.some links:
good luck.
EDIT: building on top of Gary's answer, with multiple x11 connections.
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:
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 thelogging
module. You can view this by configuring the logging module:For those working in Mac OS X Leopard, there is no select.poll(). Here is a modified version of dnozay's answer using kqueue instead of poll. Any improvements/corrections on this would be appreciated.