x11与paramiko转发 [英] x11 forwarding with paramiko

查看:158
本文介绍了x11与paramiko转发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用paramiko运行一个命令,该命令应该能够打开X窗口.我正在使用的脚本将如下所示:

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()

不幸的是,当我运行上面的脚本时,得到了以下输出:

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

如果我在终端中运行以下命令:

ssh -X user@192.168.122.55 'env; xterm'

然后,我得到了相同的环境变量(尽管更改了某些端口),所以我会说我的环境是正确的.但是,我仍然缺少使paramiko与x11转发一起工作的东西.

我尝试过的几件事是:

  • request_x11中使用handler参数:除了打印值之外,除了默认处理程序外,我什么也没得到.
  • request_x11中使用auth_cookie参数:尝试对根据xauth list输出使用的cookie值进行硬编码.这样做的目的是避免根据paramiko本身中的文档字符串可能发生的问题:

如果省略auth_cookie,则新的安全随机128位值将为 生成,使用和返回.您将需要使用此值来 验证传入的x11请求并将其替换为实际的本地 x11 cookie(需要一些x11协议的知识).

还有其他方法可以使它正常工作或解决问题吗?

注意: 以前曾在以下位置询问过此问题:

  • superuser :唯一的回答指向我已经尝试使用的request_x11文档,但无济于事.
  • stackoverflow :可接受的响应建议使用handler参数,但这是错误的.
  • github :一年多没有答案.

解决方案

  • x11请求可能使用了您可能未正确处理的MIT-MAGIC-COOKIE-1
  • 直接使用ssh,我看到它需要确认x11请求(Cookie挑战?)
  • .Xauthority文件也可能是一个问题
  • 您可以尝试strace ssh进程并查看正常流程
  • 在脚本中,您可以将xterm替换为strace xterm并与上述内容进行比较.

一些链接:

解决方案

  • the x11 request may use a MIT-MAGIC-COOKIE-1 that you may not handled properly
  • using ssh directly I saw it needed to confirm the x11 request (cookie challenge?)
  • the .Xauthority file may also be an issue
  • you can try to strace ssh process and see a normal flow
  • in your script, you can replace xterm with strace xterm and compare with the above.

some links:

good luck.

EDIT: building on top of Gary's answer, with multiple x11 connections.

#!/usr/bin/env python

import os
import select
import sys
import getpass
import paramiko
import socket
import logging
import Xlib.support.connect as xlib_connect
LOGGER = logging.getLogger(__name__)

# connection settings
host = '192.168.122.55'
user = 'user'
password = getpass.getpass()

ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(host, username=user, password=password)
del password

# maintain map
# { fd: (channel, remote channel), ... }
channels = {}

poller = select.poll()
def x11_handler(channel, (src_addr, src_port)):
    '''handler for incoming x11 connections
    for each x11 incoming connection,
    - get a connection to the local display
    - maintain bidirectional map of remote x11 channel to local x11 channel
    - add the descriptors to the poller
    - queue the channel (use transport.accept())'''
    x11_chanfd = channel.fileno()
    local_x11_socket = xlib_connect.get_socket(*local_x11_display[:3])
    local_x11_socket_fileno = local_x11_socket.fileno()
    channels[x11_chanfd] = channel, local_x11_socket
    channels[local_x11_socket_fileno] = local_x11_socket, channel
    poller.register(x11_chanfd, select.POLLIN)
    poller.register(local_x11_socket, select.POLLIN)
    LOGGER.debug('x11 channel on: %s %s', src_addr, src_port)
    transport._queue_incoming_channel(channel)

def flush_out(session):
    while session.recv_ready():
        sys.stdout.write(session.recv(4096))
    while session.recv_stderr_ready():
        sys.stderr.write(session.recv_stderr(4096))

# get local disply
local_x11_display = xlib_connect.get_display(os.environ['DISPLAY'])
# start x11 session
transport = ssh_client.get_transport()
session = transport.open_session()
session.request_x11(handler=x11_handler)
session.exec_command('xterm')
session_fileno = session.fileno()
poller.register(session_fileno, select.POLLIN)
# accept first remote x11 connection
transport.accept()

# event loop
while not session.exit_status_ready():
    poll = poller.poll()
    # accept subsequent x11 connections if any
    if len(transport.server_accepts) > 0:
        transport.accept()
    if not poll: # this should not happen, as we don't have a timeout.
        break
    for fd, event in poll:
        if fd == session_fileno:
            flush_out(session)
        # data either on local/remote x11 socket
        if fd in channels.keys():
            channel, counterpart = channels[fd]
            try:
                # forward data between local/remote x11 socket.
                data = channel.recv(4096)
                counterpart.sendall(data)
            except socket.error:
                channel.close()
                counterpart.close()
                del channels[fd]

print 'Exit status:', session.recv_exit_status()
flush_out(session)
session.close()

这篇关于x11与paramiko转发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆