~davide-cst00/uftp/0.2

« back to all changes in this revision

Viewing changes to paramiko/win_pageant.py

  • Committer: Davide Costa
  • Date: 2018-09-14 12:21:37 UTC
  • Revision ID: davide.cst00@gmail.com-20180914122137-j0ycqb4tk9z2r1k5
Xenial release 0.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 John Arbash-Meinel <john@arbash-meinel.com>
 
2
# Modified up by: Todd Whiteman <ToddW@ActiveState.com>
 
3
#
 
4
# This file is part of paramiko.
 
5
#
 
6
# Paramiko is free software; you can redistribute it and/or modify it under the
 
7
# terms of the GNU Lesser General Public License as published by the Free
 
8
# Software Foundation; either version 2.1 of the License, or (at your option)
 
9
# any later version.
 
10
#
 
11
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
 
12
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 
13
# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 
14
# details.
 
15
#
 
16
# You should have received a copy of the GNU Lesser General Public License
 
17
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
 
18
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 
19
 
 
20
"""
 
21
Functions for communicating with Pageant, the basic windows ssh agent program.
 
22
"""
 
23
 
 
24
import array
 
25
import ctypes.wintypes
 
26
import platform
 
27
import struct
 
28
from paramiko.common import zero_byte
 
29
from paramiko.py3compat import b
 
30
 
 
31
try:
 
32
    import _thread as thread  # Python 3.x
 
33
except ImportError:
 
34
    import thread  # Python 2.5-2.7
 
35
 
 
36
from . import _winapi
 
37
 
 
38
 
 
39
_AGENT_COPYDATA_ID = 0x804e50ba
 
40
_AGENT_MAX_MSGLEN = 8192
 
41
# Note: The WM_COPYDATA value is pulled from win32con, as a workaround
 
42
# so we do not have to import this huge library just for this one variable.
 
43
win32con_WM_COPYDATA = 74
 
44
 
 
45
 
 
46
def _get_pageant_window_object():
 
47
    return ctypes.windll.user32.FindWindowA(b'Pageant', b'Pageant')
 
48
 
 
49
 
 
50
def can_talk_to_agent():
 
51
    """
 
52
    Check to see if there is a "Pageant" agent we can talk to.
 
53
 
 
54
    This checks both if we have the required libraries (win32all or ctypes)
 
55
    and if there is a Pageant currently running.
 
56
    """
 
57
    return bool(_get_pageant_window_object())
 
58
 
 
59
 
 
60
if platform.architecture()[0] == '64bit':
 
61
    ULONG_PTR = ctypes.c_uint64
 
62
else:
 
63
    ULONG_PTR = ctypes.c_uint32
 
64
 
 
65
 
 
66
class COPYDATASTRUCT(ctypes.Structure):
 
67
    """
 
68
    ctypes implementation of
 
69
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms649010%28v=vs.85%29.aspx
 
70
    """
 
71
    _fields_ = [
 
72
        ('num_data', ULONG_PTR),
 
73
        ('data_size', ctypes.wintypes.DWORD),
 
74
        ('data_loc', ctypes.c_void_p),
 
75
    ]
 
76
 
 
77
 
 
78
def _query_pageant(msg):
 
79
    """
 
80
    Communication with the Pageant process is done through a shared
 
81
    memory-mapped file.
 
82
    """
 
83
    hwnd = _get_pageant_window_object()
 
84
    if not hwnd:
 
85
        # Raise a failure to connect exception, pageant isn't running anymore!
 
86
        return None
 
87
 
 
88
    # create a name for the mmap
 
89
    map_name = 'PageantRequest%08x' % thread.get_ident()
 
90
 
 
91
    pymap = _winapi.MemoryMap(map_name, _AGENT_MAX_MSGLEN,
 
92
        _winapi.get_security_attributes_for_user(),
 
93
        )
 
94
    with pymap:
 
95
        pymap.write(msg)
 
96
        # Create an array buffer containing the mapped filename
 
97
        char_buffer = array.array("b", b(map_name) + zero_byte)  # noqa
 
98
        char_buffer_address, char_buffer_size = char_buffer.buffer_info()
 
99
        # Create a string to use for the SendMessage function call
 
100
        cds = COPYDATASTRUCT(_AGENT_COPYDATA_ID, char_buffer_size,
 
101
            char_buffer_address)
 
102
 
 
103
        response = ctypes.windll.user32.SendMessageA(hwnd,
 
104
            win32con_WM_COPYDATA, ctypes.sizeof(cds), ctypes.byref(cds))
 
105
 
 
106
        if response > 0:
 
107
            pymap.seek(0)
 
108
            datalen = pymap.read(4)
 
109
            retlen = struct.unpack('>I', datalen)[0]
 
110
            return datalen + pymap.read(retlen)
 
111
        return None
 
112
 
 
113
 
 
114
class PageantConnection(object):
 
115
    """
 
116
    Mock "connection" to an agent which roughly approximates the behavior of
 
117
    a unix local-domain socket (as used by Agent).  Requests are sent to the
 
118
    pageant daemon via special Windows magick, and responses are buffered back
 
119
    for subsequent reads.
 
120
    """
 
121
 
 
122
    def __init__(self):
 
123
        self._response = None
 
124
 
 
125
    def send(self, data):
 
126
        self._response = _query_pageant(data)
 
127
 
 
128
    def recv(self, n):
 
129
        if self._response is None:
 
130
            return ''
 
131
        ret = self._response[:n]
 
132
        self._response = self._response[n:]
 
133
        if self._response == '':
 
134
            self._response = None
 
135
        return ret
 
136
 
 
137
    def close(self):
 
138
        pass