1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 SSH Agent interface
21 """
22
23 import os
24 import socket
25 import struct
26 import sys
27 import threading
28 import time
29 import tempfile
30 import stat
31 from select import select
32 from paramiko.common import asbytes, io_sleep
33 from paramiko.py3compat import byte_chr
34
35 from paramiko.ssh_exception import SSHException
36 from paramiko.message import Message
37 from paramiko.pkey import PKey
38 from paramiko.util import retry_on_signal
39
40 cSSH2_AGENTC_REQUEST_IDENTITIES = byte_chr(11)
41 SSH2_AGENT_IDENTITIES_ANSWER = 12
42 cSSH2_AGENTC_SIGN_REQUEST = byte_chr(13)
43 SSH2_AGENT_SIGN_RESPONSE = 14
44
45
48 self._conn = None
49 self._keys = ()
50
52 """
53 Return the list of keys available through the SSH agent, if any. If
54 no SSH agent was running (or it couldn't be contacted), an empty list
55 will be returned.
56
57 :return:
58 a tuple of `.AgentKey` objects representing keys available on the
59 SSH agent
60 """
61 return self._keys
62
73
75
76 self._conn = None
77 self._keys = ()
78
80 msg = asbytes(msg)
81 self._conn.send(struct.pack('>I', len(msg)) + msg)
82 l = self._read_all(4)
83 msg = Message(self._read_all(struct.unpack('>I', l)[0]))
84 return ord(msg.get_byte()), msg
85
87 result = self._conn.recv(wanted)
88 while len(result) < wanted:
89 if len(result) == 0:
90 raise SSHException('lost ssh-agent')
91 extra = self._conn.recv(wanted - len(result))
92 if len(extra) == 0:
93 raise SSHException('lost ssh-agent')
94 result += extra
95 return result
96
97
99 """
100 Class in charge of communication between two channels.
101 """
103 threading.Thread.__init__(self, target=self.run)
104 self._agent = agent
105 self._exit = False
106
108 try:
109 (r, addr) = self.get_connection()
110 self.__inr = r
111 self.__addr = addr
112 self._agent.connect()
113 self._communicate()
114 except:
115
116 raise
117
119 import fcntl
120 oldflags = fcntl.fcntl(self.__inr, fcntl.F_GETFL)
121 fcntl.fcntl(self.__inr, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
122 while not self._exit:
123 events = select([self._agent._conn, self.__inr], [], [], 0.5)
124 for fd in events[0]:
125 if self._agent._conn == fd:
126 data = self._agent._conn.recv(512)
127 if len(data) != 0:
128 self.__inr.send(data)
129 else:
130 self._close()
131 break
132 elif self.__inr == fd:
133 data = self.__inr.recv(512)
134 if len(data) != 0:
135 self._agent._conn.send(data)
136 else:
137 self._close()
138 break
139 time.sleep(io_sleep)
140
142 self._exit = True
143 self.__inr.close()
144 self._agent._conn.close()
145
146
148 """
149 Class to be used when wanting to ask a local SSH Agent being
150 asked from a remote fake agent (so use a unix socket for ex.)
151 """
154
156 """
157 Return a pair of socket object and string address.
158
159 May block!
160 """
161 conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
162 try:
163 conn.bind(self._agent._get_filename())
164 conn.listen(1)
165 (r, addr) = conn.accept()
166 return r, addr
167 except:
168 raise
169
170
172 """
173 Class to be used when wanting to ask a remote SSH Agent
174 """
178
180 return self.__chan, None
181
182
184 """
185 Class proxying request as a client:
186
187 #. client ask for a request_forward_agent()
188 #. server creates a proxy and a fake SSH Agent
189 #. server ask for establishing a connection when needed,
190 calling the forward_agent_handler at client side.
191 #. the forward_agent_handler launch a thread for connecting
192 the remote fake agent and the local agent
193 #. Communication occurs ...
194 """
196 self._conn = None
197 self.__chanR = chanRemote
198 self.thread = AgentRemoteProxy(self, chanRemote)
199 self.thread.start()
200
203
205 """
206 Method automatically called by ``AgentProxyThread.run``.
207 """
208 if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
209 conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
210 try:
211 retry_on_signal(lambda: conn.connect(os.environ['SSH_AUTH_SOCK']))
212 except:
213
214 return
215 elif sys.platform == 'win32':
216 import paramiko.win_pageant as win_pageant
217 if win_pageant.can_talk_to_agent():
218 conn = win_pageant.PageantConnection()
219 else:
220 return
221 else:
222
223 return
224 self._conn = conn
225
227 """
228 Close the current connection and terminate the agent
229 Should be called manually
230 """
231 if hasattr(self, "thread"):
232 self.thread._exit = True
233 self.thread.join(1000)
234 if self._conn is not None:
235 self._conn.close()
236
237
239 """
240 :param .Transport t: Transport used for SSH Agent communication forwarding
241
242 :raises SSHException: mostly if we lost the agent
243 """
245 AgentSSH.__init__(self)
246 self.__t = t
247 self._dir = tempfile.mkdtemp('sshproxy')
248 os.chmod(self._dir, stat.S_IRWXU)
249 self._file = self._dir + '/sshproxy.ssh'
250 self.thread = AgentLocalProxy(self)
251 self.thread.start()
252
255
262
264 """
265 Terminate the agent, clean the files, close connections
266 Should be called manually
267 """
268 os.remove(self._file)
269 os.rmdir(self._dir)
270 self.thread._exit = True
271 self.thread.join(1000)
272 self._close()
273
275 """
276 Helper for the environnement under unix
277
278 :return:
279 a dict containing the ``SSH_AUTH_SOCK`` environnement variables
280 """
281 return {'SSH_AUTH_SOCK': self._get_filename()}
282
285
286
289 self._conn = None
290 self.__chanC = chanClient
291 chanClient.request_forward_agent(self._forward_agent_handler)
292 self.__clientProxys = []
293
296
299
301 for p in self.__clientProxys:
302 p.close()
303
304
306 """
307 Client interface for using private keys from an SSH agent running on the
308 local machine. If an SSH agent is running, this class can be used to
309 connect to it and retreive `.PKey` objects which can be used when
310 attempting to authenticate to remote SSH servers.
311
312 Upon initialization, a session with the local machine's SSH agent is
313 opened, if one is running. If no agent is running, initialization will
314 succeed, but `get_keys` will return an empty tuple.
315
316 :raises SSHException:
317 if an SSH agent is found, but speaks an incompatible protocol
318 """
320 AgentSSH.__init__(self)
321
322 if ('SSH_AUTH_SOCK' in os.environ) and (sys.platform != 'win32'):
323 conn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
324 try:
325 conn.connect(os.environ['SSH_AUTH_SOCK'])
326 except:
327
328 return
329 elif sys.platform == 'win32':
330 from . import win_pageant
331 if win_pageant.can_talk_to_agent():
332 conn = win_pageant.PageantConnection()
333 else:
334 return
335 else:
336
337 return
338 self._connect(conn)
339
341 """
342 Close the SSH agent connection.
343 """
344 self._close()
345
346
348 """
349 Private key held in a local SSH agent. This type of key can be used for
350 authenticating to a remote server (signing). Most other key operations
351 work as expected.
352 """
357
360
363
366
377