diff -r b2ac21068794 agent.py
--- a/agent.py	Sun Nov 26 16:55:54 2006 +0100
+++ b/agent.py	Sun Nov 26 19:05:21 2006 +0100
@@ -56,9 +56,14 @@ class Agent:
             incompatible protocol
         """
         self.keys = ()
-        if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
-            conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-            conn.connect(os.environ['SSH_AUTH_SOCK'])
+        if 'SSH_AUTH_SOCK' in os.environ:
+            if sys.platform == 'win32':
+                import cygwin
+                conn = cygwin.connect_unix_socket(os.environ['SSH_AUTH_SOCK'])
+            else:
+                conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+                conn.connect(os.environ['SSH_AUTH_SOCK'])
+                
             self.conn = conn
         elif sys.platform == 'win32':
             import win_pageant
diff -r b2ac21068794 cygwin.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cygwin.py	Sun Nov 26 19:05:21 2006 +0100
@@ -0,0 +1,157 @@
+"""Cygwin unix domain socket client for python.
+"""
+import binascii
+import getpass
+import os
+import re
+import socket
+import struct
+
+
+class CygError(Exception):
+    pass
+
+def _find_cygpath():
+    #Read from environment
+    if 'PARAMIKO_CYGPATH' in os.environ:
+        return os.environ['PARAMIKO_CYGPATH']
+        
+    raise CygError('Cannot locate cygwin installation')
+
+
+_CYGPATH = _find_cygpath()
+    
+def get_cygpath():
+    return _CYGPATH
+    
+    
+class UserInfo:
+    def __init__(self):
+        self.name = None
+        self.uid = None
+        self.gid = None
+    
+def _read_passwd():
+    """Read the password file and return a sequence of UserInfo."""
+    path = os.path.join(get_cygpath(), 'etc/passwd')
+    f = open(path)
+    entries = []
+    try:
+        for line in f:
+            line = line.splitlines()[0]
+            parts = line.split(':')
+            
+            uinfo = UserInfo()
+            uinfo.name = parts[0]
+            uinfo.uid = int(parts[2])
+            uinfo.gid = int(parts[3])
+            entries.append(uinfo)
+            
+        return entries            
+    finally:
+        f.close()
+        
+#Cache user-information at module loading
+_USERINFO = _read_passwd()
+
+def _get_uinfo(user=None):
+    if user is None:
+        user = getpass.getuser()
+    for uinfo in _USERINFO:
+        if uinfo.name==user:
+            return uinfo
+    raise CygError('Cannot retrieve user information for %s' % user)
+
+
+def get_uid(user=None):
+    return _get_uinfo(user).uid
+        
+    
+def get_gid(user=None):
+    return _get_uinfo(user).gid
+    
+
+class SocketSecret:
+    """Wrap a cygwin socket secret structure (for integers). It writes like
+    'C4545C66-BD1E06C3-804AB069-A75ED786' in ASCII.
+    """
+    def __init__(self, secret):
+        """'secret' can be a 16-bytes binary secret or the 36-bytes string
+        representation.
+        """
+        if len(secret)==16:
+            #Binary version
+            self._secret = [secret[4*i:4*i+4] for i in range(4)]
+        elif len(secret)==(8*4+3):
+            #String representation
+            self._secret = [secret[8*i+i:8*(i+1)+i] for i in range(4)]
+            self._secret = [binascii.unhexlify(p) for p in self._secret]
+            self._secret = [p[::-1] for p in self._secret]
+        else:
+            raise CygError('Invalid secret string')
+            
+    def binary(self):
+        return ''.join(self._secret)
+    
+    def ascii(self):
+        parts = [binascii.hexlify(p[::-1]).upper() for p in self._secret]
+        return '-'.join(parts)
+        
+    def __str__(self):
+        return self.ascii()
+        
+        
+_RE_SOCKET_SECRET = re.compile(r'^\!<socket >(\d+)\s+(s|d)\s+(\w{8}-\w{8}-\w{8}-\w{8})')
+        
+def _read_secret_file(path):
+    """Read the secret file located at 'path' and return a tuple (port, type, secret)
+    where type is the socket type (can be 's' for streaming or 'd' for datagram) and
+    'secret' is a SocketSecret instance.
+    """
+    f = open(path, 'rb')
+    try:
+        content = f.read(128)
+    finally:
+        f.close()
+    m = _RE_SOCKET_SECRET.search(content)
+    if m is None:
+        raise CygError('Invalid unix domain socket secret file')
+    
+    port, socktype, secret = m.groups()
+    return int(port), socktype, SocketSecret(secret)
+    
+        
+def connect_unix_socket(path):
+    """Return a cygwin unix domain socket connected to 'path'. It is the caller
+    responsibility to close it after usage.
+    """
+    #Read server socket secret file
+    path = path.strip('/')
+    path = os.path.join(get_cygpath(), path)
+    port, socket_type, secret = _read_secret_file(path)
+    
+    if socket_type!='s':
+        raise CygError('Cygwin unix sockets are only supported in streaming mode')
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    
+    #Connect and perform the handshake
+    s.connect(('127.0.0.1', port))
+    try:
+        #Send local secret
+        s.sendall(secret.binary())
+        #Receive remote secret
+        remote_secret = ''
+        while len(remote_secret)<16:
+            remote_secret += s.recv(16-len(remote_secret))
+        
+        #Send half-faked local credentials
+        cred = struct.pack('iii', os.getpid(), get_uid(), get_gid())
+        s.sendall(cred)
+        #Receive remote credentials
+        remote_cred = ''
+        while len(remote_cred)<12:
+            remote_cred += s.recv(12-len(remote_cred))
+        return s
+    except:
+        s.close()
+        raise
