x11 forwarding with paramiko

前端 未结 5 1192
抹茶落季
抹茶落季 2020-12-30 03:15

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 par         


        
5条回答
  •  佛祖请我去吃肉
    2020-12-30 03:44

    • 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:

    • http://en.wikipedia.org/wiki/X_Window_authorization
    • http://tech.groups.yahoo.com/group/ssh/message/6747
    • http://answers.tectia.com/questions/523/how-do-i-enable-x11-forwarding-for-users-without-a-home-directory

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

提交回复
热议问题