1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 L{SSHClient}.
21 """
22
23 from binascii import hexlify
24 import getpass
25 import os
26 import socket
27 import warnings
28
29 from paramiko.agent import Agent
30 from paramiko.common import *
31 from paramiko.dsskey import DSSKey
32 from paramiko.hostkeys import HostKeys
33 from paramiko.resource import ResourceManager
34 from paramiko.rsakey import RSAKey
35 from paramiko.ssh_exception import SSHException, BadHostKeyException
36 from paramiko.transport import Transport
37
38
40 """
41 Interface for defining the policy that L{SSHClient} should use when the
42 SSH server's hostname is not in either the system host keys or the
43 application's keys. Pre-made classes implement policies for automatically
44 adding the key to the application's L{HostKeys} object (L{AutoAddPolicy}),
45 and for automatically rejecting the key (L{RejectPolicy}).
46
47 This function may be used to ask the user to verify the key, for example.
48 """
49
51 """
52 Called when an L{SSHClient} receives a server key for a server that
53 isn't in either the system or local L{HostKeys} object. To accept
54 the key, simply return. To reject, raised an exception (which will
55 be passed to the calling application).
56 """
57 pass
58
59
61 """
62 Policy for automatically adding the hostname and new host key to the
63 local L{HostKeys} object, and saving it. This is used by L{SSHClient}.
64 """
65
72
73
75 """
76 Policy for automatically rejecting the unknown hostname & key. This is
77 used by L{SSHClient}.
78 """
79
84
85
87 """
88 Policy for logging a python-style warning for an unknown host key, but
89 accepting it. This is used by L{SSHClient}.
90 """
94
95
97 """
98 A high-level representation of a session with an SSH server. This class
99 wraps L{Transport}, L{Channel}, and L{SFTPClient} to take care of most
100 aspects of authenticating and opening channels. A typical use case is::
101
102 client = SSHClient()
103 client.load_system_host_keys()
104 client.connect('ssh.example.com')
105 stdin, stdout, stderr = client.exec_command('ls -l')
106
107 You may pass in explicit overrides for authentication and server host key
108 checking. The default mechanism is to try to use local key files or an
109 SSH agent (if one is running).
110
111 @since: 1.6
112 """
113
115 """
116 Create a new SSHClient.
117 """
118 self._system_host_keys = HostKeys()
119 self._host_keys = HostKeys()
120 self._host_keys_filename = None
121 self._log_channel = None
122 self._policy = RejectPolicy()
123 self._transport = None
124
126 """
127 Load host keys from a system (read-only) file. Host keys read with
128 this method will not be saved back by L{save_host_keys}.
129
130 This method can be called multiple times. Each new set of host keys
131 will be merged with the existing set (new replacing old if there are
132 conflicts).
133
134 If C{filename} is left as C{None}, an attempt will be made to read
135 keys from the user's local "known hosts" file, as used by OpenSSH,
136 and no exception will be raised if the file can't be read. This is
137 probably only useful on posix.
138
139 @param filename: the filename to read, or C{None}
140 @type filename: str
141
142 @raise IOError: if a filename was provided and the file could not be
143 read
144 """
145 if filename is None:
146
147 filename = os.path.expanduser('~/.ssh/known_hosts')
148 try:
149 self._system_host_keys.load(filename)
150 except IOError:
151 pass
152 return
153 self._system_host_keys.load(filename)
154
156 """
157 Load host keys from a local host-key file. Host keys read with this
158 method will be checked I{after} keys loaded via L{load_system_host_keys},
159 but will be saved back by L{save_host_keys} (so they can be modified).
160 The missing host key policy L{AutoAddPolicy} adds keys to this set and
161 saves them, when connecting to a previously-unknown server.
162
163 This method can be called multiple times. Each new set of host keys
164 will be merged with the existing set (new replacing old if there are
165 conflicts). When automatically saving, the last hostname is used.
166
167 @param filename: the filename to read
168 @type filename: str
169
170 @raise IOError: if the filename could not be read
171 """
172 self._host_keys_filename = filename
173 self._host_keys.load(filename)
174
176 """
177 Save the host keys back to a file. Only the host keys loaded with
178 L{load_host_keys} (plus any added directly) will be saved -- not any
179 host keys loaded with L{load_system_host_keys}.
180
181 @param filename: the filename to save to
182 @type filename: str
183
184 @raise IOError: if the file could not be written
185 """
186 f = open(filename, 'w')
187 f.write('# SSH host keys collected by paramiko\n')
188 for hostname, keys in self._host_keys.iteritems():
189 for keytype, key in keys.iteritems():
190 f.write('%s %s %s\n' % (hostname, keytype, key.get_base64()))
191 f.close()
192
194 """
195 Get the local L{HostKeys} object. This can be used to examine the
196 local host keys or change them.
197
198 @return: the local host keys
199 @rtype: L{HostKeys}
200 """
201 return self._host_keys
202
204 """
205 Set the channel for logging. The default is C{"paramiko.transport"}
206 but it can be set to anything you want.
207
208 @param name: new channel name for logging
209 @type name: str
210 """
211 self._log_channel = name
212
214 """
215 Set the policy to use when connecting to a server that doesn't have a
216 host key in either the system or local L{HostKeys} objects. The
217 default policy is to reject all unknown servers (using L{RejectPolicy}).
218 You may substitute L{AutoAddPolicy} or write your own policy class.
219
220 @param policy: the policy to use when receiving a host key from a
221 previously-unknown server
222 @type policy: L{MissingHostKeyPolicy}
223 """
224 self._policy = policy
225
226 - def connect(self, hostname, port=22, username=None, password=None, pkey=None,
227 key_filename=None, timeout=None, allow_agent=True, look_for_keys=True):
228 """
229 Connect to an SSH server and authenticate to it. The server's host key
230 is checked against the system host keys (see L{load_system_host_keys})
231 and any local host keys (L{load_host_keys}). If the server's hostname
232 is not found in either set of host keys, the missing host key policy
233 is used (see L{set_missing_host_key_policy}). The default policy is
234 to reject the key and raise an L{SSHException}.
235
236 Authentication is attempted in the following order of priority:
237
238 - The C{pkey} or C{key_filename} passed in (if any)
239 - Any key we can find through an SSH agent
240 - Any "id_rsa" or "id_dsa" key discoverable in C{~/.ssh/}
241 - Plain username/password auth, if a password was given
242
243 If a private key requires a password to unlock it, and a password is
244 passed in, that password will be used to attempt to unlock the key.
245
246 @param hostname: the server to connect to
247 @type hostname: str
248 @param port: the server port to connect to
249 @type port: int
250 @param username: the username to authenticate as (defaults to the
251 current local username)
252 @type username: str
253 @param password: a password to use for authentication or for unlocking
254 a private key
255 @type password: str
256 @param pkey: an optional private key to use for authentication
257 @type pkey: L{PKey}
258 @param key_filename: the filename of an optional private key to use
259 for authentication
260 @type key_filename: str
261 @param timeout: an optional timeout (in seconds) for the TCP connect
262 @type timeout: float
263 @param allow_agent: set to False to disable connecting to the SSH agent
264 @type allow_agent: bool
265 @param look_for_keys: set to False to disable searching for discoverable
266 private key files in C{~/.ssh/}
267 @type look_for_keys: bool
268
269 @raise BadHostKeyException: if the server's host key could not be
270 verified
271 @raise AuthenticationException: if authentication failed
272 @raise SSHException: if there was any other error connecting or
273 establishing an SSH session
274 @raise socket.error: if a socket error occurred while connecting
275 """
276 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
277 if timeout is not None:
278 try:
279 sock.settimeout(timeout)
280 except:
281 pass
282
283 sock.connect((hostname, port))
284 t = self._transport = Transport(sock)
285
286 if self._log_channel is not None:
287 t.set_log_channel(self._log_channel)
288 t.start_client()
289 ResourceManager.register(self, t)
290
291 server_key = t.get_remote_server_key()
292 keytype = server_key.get_name()
293
294 our_server_key = self._system_host_keys.get(hostname, {}).get(keytype, None)
295 if our_server_key is None:
296 our_server_key = self._host_keys.get(hostname, {}).get(keytype, None)
297 if our_server_key is None:
298
299 self._policy.missing_host_key(self, hostname, server_key)
300
301 our_server_key = server_key
302
303 if server_key != our_server_key:
304 raise BadHostKeyException(hostname, server_key, our_server_key)
305
306 if username is None:
307 username = getpass.getuser()
308
309 self._auth(username, password, pkey, key_filename, allow_agent, look_for_keys)
310
312 """
313 Close this SSHClient and its underlying L{Transport}.
314 """
315 if self._transport is None:
316 return
317 self._transport.close()
318 self._transport = None
319
321 """
322 Execute a command on the SSH server. A new L{Channel} is opened and
323 the requested command is executed. The command's input and output
324 streams are returned as python C{file}-like objects representing
325 stdin, stdout, and stderr.
326
327 @param command: the command to execute
328 @type command: str
329 @param bufsize: interpreted the same way as by the built-in C{file()} function in python
330 @type bufsize: int
331 @return: the stdin, stdout, and stderr of the executing command
332 @rtype: tuple(L{ChannelFile}, L{ChannelFile}, L{ChannelFile})
333
334 @raise SSHException: if the server fails to execute the command
335 """
336 chan = self._transport.open_session()
337 chan.exec_command(command)
338 stdin = chan.makefile('wb', bufsize)
339 stdout = chan.makefile('rb', bufsize)
340 stderr = chan.makefile_stderr('rb', bufsize)
341 return stdin, stdout, stderr
342
344 """
345 Start an interactive shell session on the SSH server. A new L{Channel}
346 is opened and connected to a pseudo-terminal using the requested
347 terminal type and size.
348
349 @param term: the terminal type to emulate (for example, C{"vt100"})
350 @type term: str
351 @param width: the width (in characters) of the terminal window
352 @type width: int
353 @param height: the height (in characters) of the terminal window
354 @type height: int
355 @return: a new channel connected to the remote shell
356 @rtype: L{Channel}
357
358 @raise SSHException: if the server fails to invoke a shell
359 """
360 chan = self._transport.open_session()
361 chan.get_pty(term, width, height)
362 chan.invoke_shell()
363 return chan
364
366 """
367 Open an SFTP session on the SSH server.
368
369 @return: a new SFTP session object
370 @rtype: L{SFTPClient}
371 """
372 return self._transport.open_sftp_client()
373
375 """
376 Return the underlying L{Transport} object for this SSH connection.
377 This can be used to perform lower-level tasks, like opening specific
378 kinds of channels.
379
380 @return: the Transport for this connection
381 @rtype: L{Transport}
382 """
383 return self._transport
384
385 - def _auth(self, username, password, pkey, key_filename, allow_agent, look_for_keys):
386 """
387 Try, in order:
388
389 - The key passed in, if one was passed in.
390 - Any key we can find through an SSH agent (if allowed).
391 - Any "id_rsa" or "id_dsa" key discoverable in ~/.ssh/ (if allowed).
392 - Plain username/password auth, if a password was given.
393
394 (The password might be needed to unlock a private key.)
395 """
396 saved_exception = None
397
398 if pkey is not None:
399 try:
400 self._log(DEBUG, 'Trying SSH key %s' % hexlify(pkey.get_fingerprint()))
401 self._transport.auth_publickey(username, pkey)
402 return
403 except SSHException, e:
404 saved_exception = e
405
406 if key_filename is not None:
407 for pkey_class in (RSAKey, DSSKey):
408 try:
409 key = pkey_class.from_private_key_file(key_filename, password)
410 self._log(DEBUG, 'Trying key %s from %s' % (hexlify(key.get_fingerprint()), key_filename))
411 self._transport.auth_publickey(username, key)
412 return
413 except SSHException, e:
414 saved_exception = e
415
416 if allow_agent:
417 for key in Agent().get_keys():
418 try:
419 self._log(DEBUG, 'Trying SSH agent key %s' % hexlify(key.get_fingerprint()))
420 self._transport.auth_publickey(username, key)
421 return
422 except SSHException, e:
423 saved_exception = e
424
425 keyfiles = []
426 rsa_key = os.path.expanduser('~/.ssh/id_rsa')
427 dsa_key = os.path.expanduser('~/.ssh/id_dsa')
428 if os.path.isfile(rsa_key):
429 keyfiles.append((RSAKey, rsa_key))
430 if os.path.isfile(dsa_key):
431 keyfiles.append((DSSKey, dsa_key))
432
433 rsa_key = os.path.expanduser('~/ssh/id_rsa')
434 dsa_key = os.path.expanduser('~/ssh/id_dsa')
435 if os.path.isfile(rsa_key):
436 keyfiles.append((RSAKey, rsa_key))
437 if os.path.isfile(dsa_key):
438 keyfiles.append((DSSKey, dsa_key))
439
440 if not look_for_keys:
441 keyfiles = []
442
443 for pkey_class, filename in keyfiles:
444 try:
445 key = pkey_class.from_private_key_file(filename, password)
446 self._log(DEBUG, 'Trying discovered key %s in %s' % (hexlify(key.get_fingerprint()), filename))
447 self._transport.auth_publickey(username, key)
448 return
449 except SSHException, e:
450 saved_exception = e
451 except IOError, e:
452 saved_exception = e
453
454 if password is not None:
455 try:
456 self._transport.auth_password(username, password)
457 return
458 except SSHException, e:
459 saved_exception = e
460
461
462 if saved_exception is not None:
463 raise saved_exception
464 raise SSHException('No authentication methods available')
465
466 - def _log(self, level, msg):
467 self._transport._log(level, msg)
468