try out john's win_pageant code
This commit is contained in:
parent
62c9588365
commit
016060388a
|
@ -55,10 +55,19 @@ class Agent:
|
||||||
@raise SSHException: if an SSH agent is found, but speaks an
|
@raise SSHException: if an SSH agent is found, but speaks an
|
||||||
incompatible protocol
|
incompatible protocol
|
||||||
"""
|
"""
|
||||||
|
self.keys = ()
|
||||||
if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
|
if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
|
||||||
conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
conn.connect(os.environ['SSH_AUTH_SOCK'])
|
conn.connect(os.environ['SSH_AUTH_SOCK'])
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
|
elif sys.platform == 'win32':
|
||||||
|
import win_pageant
|
||||||
|
if win_pageant.can_talk_to_agent():
|
||||||
|
self.conn = win_pageant.PageantConnection()
|
||||||
|
else:
|
||||||
|
# no agent support
|
||||||
|
return
|
||||||
|
|
||||||
ptype, result = self._send_message(chr(SSH2_AGENTC_REQUEST_IDENTITIES))
|
ptype, result = self._send_message(chr(SSH2_AGENTC_REQUEST_IDENTITIES))
|
||||||
if ptype != SSH2_AGENT_IDENTITIES_ANSWER:
|
if ptype != SSH2_AGENT_IDENTITIES_ANSWER:
|
||||||
raise SSHException('could not get keys from ssh-agent')
|
raise SSHException('could not get keys from ssh-agent')
|
||||||
|
@ -67,8 +76,6 @@ class Agent:
|
||||||
keys.append(AgentKey(self, result.get_string()))
|
keys.append(AgentKey(self, result.get_string()))
|
||||||
result.get_string()
|
result.get_string()
|
||||||
self.keys = tuple(keys)
|
self.keys = tuple(keys)
|
||||||
else:
|
|
||||||
self.keys = ()
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
# Copyright (C) 2005 John Arbash-Meinel <john@arbash-meinel.com>
|
||||||
|
#
|
||||||
|
# This file is part of paramiko.
|
||||||
|
#
|
||||||
|
# Paramiko is free software; you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
#
|
||||||
|
# Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
# details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Functions for communicating with Pageant, the basic windows ssh agent program.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
# if you're on windows, you should have these, i guess?
|
||||||
|
try:
|
||||||
|
import win32ui
|
||||||
|
import win32api
|
||||||
|
import win32con
|
||||||
|
import mmapfile
|
||||||
|
_has_win32all = True
|
||||||
|
except ImportError:
|
||||||
|
_has_win32all = False
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ctypes
|
||||||
|
_has_ctypes = True
|
||||||
|
except ImportError:
|
||||||
|
_has_ctypes = False
|
||||||
|
else:
|
||||||
|
class _COPYDATASTRUCT(ctypes.Structure):
|
||||||
|
"""This is a mapping to the Win32 COPYDATASTRUCT.
|
||||||
|
|
||||||
|
typedef struct tagCOPYDATASTRUCT {
|
||||||
|
ULONG_PTR dwData;
|
||||||
|
DWORD cbData;
|
||||||
|
PVOID lpData;
|
||||||
|
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
|
||||||
|
"""
|
||||||
|
_fields_ = [ ('dwData', ctypes.c_ulong) #I think this is right
|
||||||
|
, ('cbData', ctypes.c_ulong)
|
||||||
|
, ('lpData', ctypes.c_void_p)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
_AGENT_COPYDATA_ID = 0x804e50ba
|
||||||
|
_AGENT_MAX_MSGLEN = 8192
|
||||||
|
|
||||||
|
|
||||||
|
def can_talk_to_agent():
|
||||||
|
"""
|
||||||
|
Check to see if there is a "Pageant" agent we can talk to.
|
||||||
|
|
||||||
|
This checks both if we have the required libraries (win32all)
|
||||||
|
and if there is a Pageant currently running.
|
||||||
|
"""
|
||||||
|
if not _has_win32all or not _has_ctypes:
|
||||||
|
return False
|
||||||
|
hwnd = win32ui.FindWindow('Pageant', 'Pageant')
|
||||||
|
if not hwnd:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _query_pageant(msg):
|
||||||
|
hwnd = win32ui.FindWindow('Pageant', 'Pageant')
|
||||||
|
if not hwnd:
|
||||||
|
# Raise a failure to connect exception
|
||||||
|
return None
|
||||||
|
|
||||||
|
# I have a feeling that GetCurrentThreadId is just a
|
||||||
|
# way to ensure that we have a unique map name
|
||||||
|
mapname = 'PageantRequest%08x' % (win32api.GetCurrentThreadId())
|
||||||
|
# Created a named memory map
|
||||||
|
map = mmapfile.mmapfile('', mapname, _AGENT_MAX_MSGLEN)
|
||||||
|
try:
|
||||||
|
map.write(msg)
|
||||||
|
|
||||||
|
cds = _COPYDATASTRUCT(_AGENT_COPYDATA_ID, 1 + len(mapname), ctypes.c_char_p(mapname))
|
||||||
|
|
||||||
|
response = hwnd.SendMessage(win32con.WM_COPYDATA, None, ctypes.byref(cds))
|
||||||
|
if response > 0:
|
||||||
|
retlen = 4 + struct.unpack('i', map.read(4))
|
||||||
|
return map.read(retlen)
|
||||||
|
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
# This may be done automatically.
|
||||||
|
map.close()
|
||||||
|
|
||||||
|
|
||||||
|
class PageantConnection (object):
|
||||||
|
"""
|
||||||
|
Mock "connection" to an agent which roughly approximates the behavior of
|
||||||
|
a unix local-domain socket (as used by Agent). Requests are sent to the
|
||||||
|
pageant daemon via special Windows magick, and responses are buffered back
|
||||||
|
for subsequent reads.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._response = None
|
||||||
|
|
||||||
|
def send(self, data):
|
||||||
|
self._response = _query_pageant(data)
|
||||||
|
|
||||||
|
def recv(self, n):
|
||||||
|
if self._response is None:
|
||||||
|
return ''
|
||||||
|
ret = self._response[:n]
|
||||||
|
self._response = self._response[n:]
|
||||||
|
if self._response == '':
|
||||||
|
self._response = None
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
pass
|
Loading…
Reference in New Issue