From be5542c05e46b500e47b94bc8a6254cae8335a8b Mon Sep 17 00:00:00 2001 From: "Jeremy T. Bouse" Date: Sun, 29 May 2011 08:16:54 -0400 Subject: Imported Upstream version 1.7.7.1 --- docs/paramiko.transport-pysrc.html | 2985 ++++++++++++++++++------------------ 1 file changed, 1472 insertions(+), 1513 deletions(-) (limited to 'docs/paramiko.transport-pysrc.html') diff --git a/docs/paramiko.transport-pysrc.html b/docs/paramiko.transport-pysrc.html index 0a560e0..de00079 100644 --- a/docs/paramiko.transport-pysrc.html +++ b/docs/paramiko.transport-pysrc.html @@ -101,261 +101,263 @@ 45 from paramiko.sftp_client import SFTPClient 46 from paramiko.ssh_exception import SSHException, BadAuthenticationType, ChannelException 47 - 48 # these come from PyCrypt - 49 # http://www.amk.ca/python/writing/pycrypt/ - 50 # i believe this on the standards track. - 51 # PyCrypt compiled for Win32 can be downloaded from the HashTar homepage: - 52 # http://nitace.bsd.uchicago.edu:8080/hashtar - 53 from Crypto.Cipher import Blowfish, AES, DES3, ARC4 - 54 from Crypto.Hash import SHA, MD5 - 55 try: - 56 from Crypto.Util import Counter - 57 except ImportError: - 58 from paramiko.util import Counter - 59 - 60 - 61 # for thread cleanup - 62 _active_threads = [] -
63 -def _join_lingering_threads(): -
64 for thr in _active_threads: - 65 thr.stop_thread() -
66 import atexit - 67 atexit.register(_join_lingering_threads) - 68 - 69 -
70 -class SecurityOptions (object): -
71 """ - 72 Simple object containing the security preferences of an ssh transport. - 73 These are tuples of acceptable ciphers, digests, key types, and key - 74 exchange algorithms, listed in order of preference. - 75 - 76 Changing the contents and/or order of these fields affects the underlying - 77 L{Transport} (but only if you change them before starting the session). - 78 If you try to add an algorithm that paramiko doesn't recognize, - 79 C{ValueError} will be raised. If you try to assign something besides a - 80 tuple to one of the fields, C{TypeError} will be raised. - 81 """ - 82 __slots__ = [ 'ciphers', 'digests', 'key_types', 'kex', 'compression', '_transport' ] - 83 -
84 - def __init__(self, transport): -
85 self._transport = transport -
86 -
87 - def __repr__(self): -
88 """ - 89 Returns a string representation of this object, for debugging. - 90 - 91 @rtype: str - 92 """ - 93 return '<paramiko.SecurityOptions for %s>' % repr(self._transport) -
94 -
95 - def _get_ciphers(self): -
96 return self._transport._preferred_ciphers -
97 -
98 - def _get_digests(self): -
99 return self._transport._preferred_macs -
100 -
101 - def _get_key_types(self): -
102 return self._transport._preferred_keys -
103 -
104 - def _get_kex(self): -
105 return self._transport._preferred_kex -
106 -
107 - def _get_compression(self): -
108 return self._transport._preferred_compression -
109 -
110 - def _set(self, name, orig, x): -
111 if type(x) is list: - 112 x = tuple(x) - 113 if type(x) is not tuple: - 114 raise TypeError('expected tuple or list') - 115 possible = getattr(self._transport, orig).keys() - 116 forbidden = filter(lambda n: n not in possible, x) - 117 if len(forbidden) > 0: - 118 raise ValueError('unknown cipher') - 119 setattr(self._transport, 48 from Crypto import Random + 49 from Crypto.Cipher import Blowfish, AES, DES3, ARC4 + 50 from Crypto.Hash import SHA, MD5 + 51 try: + 52 from Crypto.Util import Counter + 53 except ImportError: + 54 from paramiko.util import Counter + 55 + 56 + 57 # for thread cleanup + 58 _active_threads = [] +
60 for thr in _active_threads: + 61 thr.stop_thread() +
62 import atexit + 63 atexit.register(_join_lingering_threads) + 64 + 65 +
66 -class SecurityOptions (object): +
67 """ + 68 Simple object containing the security preferences of an ssh transport. + 69 These are tuples of acceptable ciphers, digests, key types, and key + 70 exchange algorithms, listed in order of preference. + 71 + 72 Changing the contents and/or order of these fields affects the underlying + 73 L{Transport} (but only if you change them before starting the session). + 74 If you try to add an algorithm that paramiko doesn't recognize, + 75 C{ValueError} will be raised. If you try to assign something besides a + 76 tuple to one of the fields, C{TypeError} will be raised. + 77 """ + 78 __slots__ = [ 'ciphers', 'digests', 'key_types', 'kex', 'compression', '_transport' ] + 79 +
80 - def __init__(self, transport): +
81 self._transport = transport +
82 +
83 - def __repr__(self): +
84 """ + 85 Returns a string representation of this object, for debugging. + 86 + 87 @rtype: str + 88 """ + 89 return '<paramiko.SecurityOptions for %s>' % repr(self._transport) +
90 +
91 - def _get_ciphers(self): +
92 return self._transport._preferred_ciphers +
93 +
94 - def _get_digests(self): +
95 return self._transport._preferred_macs +
96 +
97 - def _get_key_types(self): +
98 return self._transport._preferred_keys +
99 +
100 - def _get_kex(self): +
101 return self._transport._preferred_kex +
102 +
103 - def _get_compression(self): +
104 return self._transport._preferred_compression +
105 +
106 - def _set(self, name, orig, x): +
107 if type(x) is list: + 108 x = tuple(x) + 109 if type(x) is not tuple: + 110 raise TypeError('expected tuple or list') + 111 possible = getattr(self._transport, orig).keys() + 112 forbidden = filter(lambda n: n not in possible, x) + 113 if len(forbidden) > 0: + 114 raise ValueError('unknown cipher') + 115 setattr(self._transport, name, x) -
120 -
121 - def _set_ciphers(self, x): -
122 self._set('_preferred_ciphers', '_cipher_info', x) -
123 -
124 - def _set_digests(self, x): -
125 self._set('_preferred_macs', '_mac_info', x) -
126 -
127 - def _set_key_types(self, x): -
128 self._set('_preferred_keys', '_key_info', x) -
129 -
130 - def _set_kex(self, x): -
131 self._set('_preferred_kex', '_kex_info', x) -
132 -
133 - def _set_compression(self, x): -
134 self._set('_preferred_compression', '_compression_info', x) -
135 - 136 ciphers = property(_get_ciphers, _set_ciphers, None, - 137 "Symmetric encryption ciphers") - 138 digests = property(_get_digests, _set_digests, None, - 139 "Digest (one-way hash) algorithms") - 140 key_types = property(_get_key_types, _set_key_types, None, - 141 "Public-key algorithms") - 142 kex = property(_get_kex, _set_kex, None, "Key exchange algorithms") - 143 compression = property(_get_compression, _set_compression, None, - 144 "Compression algorithms") -
145 - 146 -
147 -class ChannelMap (object): -
148 - def __init__(self): -
149 # (id -> Channel) - 150 self._map = weakref.WeakValueDictionary() - 151 self._lock = threading.Lock() -
152 -
153 - def put(self, chanid, chan): -
154 self._lock.acquire() - 155 try: - 156 self._map[chanid] = chan - 157 finally: - 158 self._lock.release() -
159 -
160 - def get(self, chanid): -
161 self._lock.acquire() - 162 try: - 163 return self._map. 116 +
117 - def _set_ciphers(self, x): +
118 self._set('_preferred_ciphers', '_cipher_info', x) +
119 +
120 - def _set_digests(self, x): +
121 self._set('_preferred_macs', '_mac_info', x) +
122 +
123 - def _set_key_types(self, x): +
124 self._set('_preferred_keys', '_key_info', x) +
125 +
126 - def _set_kex(self, x): +
127 self._set('_preferred_kex', '_kex_info', x) +
128 +
129 - def _set_compression(self, x): +
130 self._set('_preferred_compression', '_compression_info', x) +
131 + 132 ciphers = property(_get_ciphers, _set_ciphers, None, + 133 "Symmetric encryption ciphers") + 134 digests = property(_get_digests, _set_digests, None, + 135 "Digest (one-way hash) algorithms") + 136 key_types = property(_get_key_types, _set_key_types, None, + 137 "Public-key algorithms") + 138 kex = property(_get_kex, _set_kex, None, "Key exchange algorithms") + 139 compression = property(_get_compression, _set_compression, None, + 140 "Compression algorithms") +
141 + 142 +
143 -class ChannelMap (object): +
144 - def __init__(self): +
145 # (id -> Channel) + 146 self._map = weakref.WeakValueDictionary() + 147 self._lock = threading.Lock() +
148 +
149 - def put(self, chanid, chan): +
150 self._lock.acquire() + 151 try: + 152 self._map[chanid] = chan + 153 finally: + 154 self._lock.release() +
155 +
156 - def get(self, chanid): +
157 self._lock.acquire() + 158 try: + 159 return self._map.get(chanid, None) - 164 finally: - 165 self._lock.release() -
166 -
167 - def delete(self, chanid): -
168 self._lock.acquire() - 169 try: - 170 try: - 171 del self._map[chanid] - 172 except KeyError: - 173 pass - 174 finally: - 175 self._lock.release() -
176 -
177 - def values(self): -
178 self._lock.acquire() - 179 try: - 180 return self._map. 160 finally: + 161 self._lock.release() +
162 +
163 - def delete(self, chanid): +
164 self._lock.acquire() + 165 try: + 166 try: + 167 del self._map[chanid] + 168 except KeyError: + 169 pass + 170 finally: + 171 self._lock.release() +
172 +
173 - def values(self): +
174 self._lock.acquire() + 175 try: + 176 return self._map.values() - 181 finally: - 182 self._lock.release() -
183 -
184 - def __len__(self): -
185 self._lock.acquire() - 186 try: - 187 return len(self._map) - 188 finally: - 189 self._lock.release() -
190 - 191 -
192 -class Transport (threading.Thread): -
193 """ - 194 An SSH Transport attaches to a stream (usually a socket), negotiates an - 195 encrypted session, authenticates, and then creates stream tunnels, called - 196 L{Channel}s, across the session. Multiple channels can be multiplexed - 197 across a single session (and often are, in the case of port forwardings). - 198 """ - 199 - 200 _PROTO_ID = '2.0' - 201 _CLIENT_ID = 'paramiko_1.7.6' - 202 - 203 _preferred_ciphers = ( 'aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc', 'aes256-cbc', '3des-cbc', - 204 'arcfour128', 'arcfour256' ) - 205 _preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' ) - 206 _preferred_keys = ( 'ssh-rsa', 'ssh-dss' ) - 207 _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' ) - 208 _preferred_compression = ( 'none', ) - 209 - 210 _cipher_info = { - 211 'aes128-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16 }, - 212 'aes256-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32 }, - 213 'blowfish-cbc': { 'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16 }, - 214 'aes128-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16 }, - 215 'aes256-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32 }, - 216 '3des-cbc': { 'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24 }, - 217 'arcfour128': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16 }, - 218 'arcfour256': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32 }, - 219 } - 220 - 221 _mac_info = { - 222 'hmac-sha1': { 'class': SHA, 'size': 20 }, - 223 'hmac-sha1-96': { 'class': SHA, 'size': 12 }, - 224 'hmac-md5': { 'class': MD5, 'size': 16 }, - 225 'hmac-md5-96': { 'class': MD5, 'size': 12 }, - 226 } - 227 - 228 _key_info = { - 229 'ssh-rsa': RSAKey, - 230 'ssh-dss': DSSKey, - 231 } - 232 - 233 _kex_info = { - 234 'diffie-hellman-group1-sha1': KexGroup1, - 235 'diffie-hellman-group-exchange-sha1': KexGex, - 236 } - 237 - 238 _compression_info = { - 239 # zlib@openssh.com is just zlib, but only turned on after a successful - 240 # authentication. openssh servers may only offer this type because - 241 # they've had troubles with security holes in zlib in the past. - 242 'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ), - 243 'zlib': ( ZlibCompressor, ZlibDecompressor ), - 244 'none': ( None, None ), - 245 } - 246 - 247 - 248 _modulus_pack = None - 249 -
250 - def __init__(self, sock): -
251 """ - 252 Create a new SSH session over an existing socket, or socket-like - 253 object. This only creates the Transport object; it doesn't begin the - 254 SSH session yet. Use L{connect} or L{start_client} to begin a client - 255 session, or L{start_server} to begin a server session. - 256 - 257 If the object is not actually a socket, it must have the following - 258 methods: - 259 - C{send(str)}: Writes from 1 to C{len(str)} bytes, and - 260 returns an int representing the number of bytes written. Returns - 261 0 or raises C{EOFError} if the stream has been closed. - 262 - C{recv(int)}: Reads from 1 to C{int} bytes and returns them as a - 263 string. Returns 0 or raises C{EOFError} if the stream has been - 264 closed. - 265 - C{close()}: Closes the socket. - 266 - C{settimeout(n)}: Sets a (float) timeout on I/O operations. - 267 - 268 For ease of use, you may also pass in an address (as a tuple) or a host - 269 string as the C{sock} argument. (A host string is a hostname with an - 270 optional port (separated by C{":"}) which will be converted into a - 271 tuple of C{(hostname, port)}.) A socket will be connected to this - 272 address and used for communication. Exceptions from the C{socket} call - 273 may be thrown in this case. - 274 - 275 @param sock: a socket or socket-like object to create the session over. - 276 @type sock: socket - 277 """ - 278 if isinstance(sock, (str, unicode)): - 279 # convert "host:port" into (host, port) - 280 hl = sock.split(':', 1) - 281 if len(hl) == 1: - 282 sock = (hl[0], 22) - 283 else: - 284 sock = (hl[0], int(hl[1])) - 285 if type(sock) is tuple: - 286 # connect to the given (host, port) - 287 hostname, port = sock - 288 for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM): - 289 if socktype == socket.SOCK_STREAM: - 290 af = family - 291 addr = sockaddr - 292 break - 293 else: - 294 raise SSHException('No suitable address family for %s' % hostname) - 295 sock = socket.socket(af, socket.SOCK_STREAM) - 296 sock.connect((hostname, port)) - 297 # okay, normal socket-ish flow here... - 298 threading.Thread. 177 finally: + 178 self._lock.release() +
179 +
180 - def __len__(self): +
181 self._lock.acquire() + 182 try: + 183 return len(self._map) + 184 finally: + 185 self._lock.release() +
186 + 187 +
188 -class Transport (threading.Thread): +
189 """ + 190 An SSH Transport attaches to a stream (usually a socket), negotiates an + 191 encrypted session, authenticates, and then creates stream tunnels, called + 192 L{Channel}s, across the session. Multiple channels can be multiplexed + 193 across a single session (and often are, in the case of port forwardings). + 194 """ + 195 + 196 _PROTO_ID = '2.0' + 197 _CLIENT_ID = 'paramiko_1.7.7.1' + 198 + 199 _preferred_ciphers = ( 'aes128-ctr', 'aes256-ctr', 'aes128-cbc', 'blowfish-cbc', 'aes256-cbc', '3des-cbc', + 200 'arcfour128', 'arcfour256' ) + 201 _preferred_macs = ( 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96' ) + 202 _preferred_keys = ( 'ssh-rsa', 'ssh-dss' ) + 203 _preferred_kex = ( 'diffie-hellman-group1-sha1', 'diffie-hellman-group-exchange-sha1' ) + 204 _preferred_compression = ( 'none', ) + 205 + 206 _cipher_info = { + 207 'aes128-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 16 }, + 208 'aes256-ctr': { 'class': AES, 'mode': AES.MODE_CTR, 'block-size': 16, 'key-size': 32 }, + 209 'blowfish-cbc': { 'class': Blowfish, 'mode': Blowfish.MODE_CBC, 'block-size': 8, 'key-size': 16 }, + 210 'aes128-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 16 }, + 211 'aes256-cbc': { 'class': AES, 'mode': AES.MODE_CBC, 'block-size': 16, 'key-size': 32 }, + 212 '3des-cbc': { 'class': DES3, 'mode': DES3.MODE_CBC, 'block-size': 8, 'key-size': 24 }, + 213 'arcfour128': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 16 }, + 214 'arcfour256': { 'class': ARC4, 'mode': None, 'block-size': 8, 'key-size': 32 }, + 215 } + 216 + 217 _mac_info = { + 218 'hmac-sha1': { 'class': SHA, 'size': 20 }, + 219 'hmac-sha1-96': { 'class': SHA, 'size': 12 }, + 220 'hmac-md5': { 'class': MD5, 'size': 16 }, + 221 'hmac-md5-96': { 'class': MD5, 'size': 12 }, + 222 } + 223 + 224 _key_info = { + 225 'ssh-rsa': RSAKey, + 226 'ssh-dss': DSSKey, + 227 } + 228 + 229 _kex_info = { + 230 'diffie-hellman-group1-sha1': KexGroup1, + 231 'diffie-hellman-group-exchange-sha1': KexGex, + 232 } + 233 + 234 _compression_info = { + 235 # zlib@openssh.com is just zlib, but only turned on after a successful + 236 # authentication. openssh servers may only offer this type because + 237 # they've had troubles with security holes in zlib in the past. + 238 'zlib@openssh.com': ( ZlibCompressor, ZlibDecompressor ), + 239 'zlib': ( ZlibCompressor, ZlibDecompressor ), + 240 'none': ( None, None ), + 241 } + 242 + 243 + 244 _modulus_pack = None + 245 +
246 - def __init__(self, sock): +
247 """ + 248 Create a new SSH session over an existing socket, or socket-like + 249 object. This only creates the Transport object; it doesn't begin the + 250 SSH session yet. Use L{connect} or L{start_client} to begin a client + 251 session, or L{start_server} to begin a server session. + 252 + 253 If the object is not actually a socket, it must have the following + 254 methods: + 255 - C{send(str)}: Writes from 1 to C{len(str)} bytes, and + 256 returns an int representing the number of bytes written. Returns + 257 0 or raises C{EOFError} if the stream has been closed. + 258 - C{recv(int)}: Reads from 1 to C{int} bytes and returns them as a + 259 string. Returns 0 or raises C{EOFError} if the stream has been + 260 closed. + 261 - C{close()}: Closes the socket. + 262 - C{settimeout(n)}: Sets a (float) timeout on I/O operations. + 263 + 264 For ease of use, you may also pass in an address (as a tuple) or a host + 265 string as the C{sock} argument. (A host string is a hostname with an + 266 optional port (separated by C{":"}) which will be converted into a + 267 tuple of C{(hostname, port)}.) A socket will be connected to this + 268 address and used for communication. Exceptions from the C{socket} call + 269 may be thrown in this case. + 270 + 271 @param sock: a socket or socket-like object to create the session over. + 272 @type sock: socket + 273 """ + 274 if isinstance(sock, (str, unicode)): + 275 # convert "host:port" into (host, port) + 276 hl = sock.split(':', 1) + 277 if len(hl) == 1: + 278 sock = (hl[0], 22) + 279 else: + 280 sock = (hl[0], int(hl[1])) + 281 if type(sock) is tuple: + 282 # connect to the given (host, port) + 283 hostname, port = sock + 284 reason = 'No suitable address family' + 285 for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM): + 286 if socktype == socket.SOCK_STREAM: + 287 af = family + 288 addr = sockaddr + 289 sock = socket.socket(af, socket.SOCK_STREAM) + 290 try: + 291 sock.connect((hostname, port)) + 292 except socket.error, e: + 293 reason = str(e) + 294 else: + 295 break + 296 else: + 297 raise SSHException( + 298 'Unable to connect to %s: %s' % (hostname, reason)) + 299 # okay, normal socket-ish flow here... + 300 threading.Thread.__init__(self) - 299 self.setDaemon(True) - 300 self.randpool = randpool - 301 self.sock = sock - 302 # Python < 2.3 doesn't have the settimeout method - RogerB - 303 try: - 304 # we set the timeout so we can check self.active periodically to - 305 # see if we should bail. socket.timeout exception is never - 306 # propagated. - 307 self.sock. 301 self.setDaemon(True) + 302 self.rng = rng + 303 self.sock = sock + 304 # Python < 2.3 doesn't have the settimeout method - RogerB + 305 try: + 306 # we set the timeout so we can check self.active periodically to + 307 # see if we should bail. socket.timeout exception is never + 308 # propagated. + 309 self.sock.settimeout(0.1) - 308 except AttributeError: - 309 pass - 310 - 311 # negotiated crypto parameters - 312 self.packetizer = Packetizer(sock) - 313 self.local_version = 'SSH-' + self._PROTO_ID + '-' + self._CLIENT_ID - 314 self.remote_version = '' - 315 self.local_cipher = self.remote_cipher = '' - 316 self.local_kex_init = self.remote_kex_init = None - 317 self.local_mac = self.remote_mac = None - 318 self.local_compression = self.remote_compression = None - 319 self.session_id = None - 320 self.host_key_type = None - 321 self.host_key = None - 322 - 323 # state used during negotiation - 324 self.kex_engine = None - 325 self.H = None - 326 self.K = None - 327 - 328 self.active = False - 329 self.initial_kex_done = False - 330 self.in_kex = False - 331 self.authenticated = False - 332 self._expected_packet = tuple() - 333 self.lock = threading.Lock() # synchronization (always higher level than write_lock) - 334 - 335 # tracking open channels - 336 self._channels = ChannelMap() - 337 self.channel_events = { } # (id -> Event) - 338 self.channels_seen = { } # (id -> True) - 339 self._channel_counter = 1 - 340 self.window_size = 65536 - 341 self.max_packet_size = 34816 - 342 self._x11_handler = None - 343 self._tcp_handler = None - 344 - 345 self.saved_exception = None - 346 self.clear_to_send = threading.Event() - 347 self.clear_to_send_lock = threading.Lock() - 348 self.clear_to_send_timeout = 30.0 - 349 self.log_name = 'paramiko.transport' - 350 self.logger = util.get_logger(self.log_name) - 351 self.packetizer.set_log(self.logger) - 352 self.auth_handler = None - 353 self.global_response = None # response Message from an arbitrary global request - 354 self.completion_event = None # user-defined event callbacks - 355 self.banner_timeout = 15 # how long (seconds) to wait for the SSH banner - 356 - 357 # server mode: - 358 self.server_mode = False - 359 self.server_object = None - 360 self.server_key_dict = { } - 361 self.server_accepts = [ ] - 362 self.server_accept_cv = threading.Condition(self.lock) - 363 self.subsystem_table = { } -
364 -
365 - def __repr__(self): -
366 """ - 367 Returns a string representation of this object, for debugging. - 368 - 369 @rtype: str - 370 """ - 371 out = '<paramiko.Transport at %s' % hex(long(id(self)) & 0xffffffffL) - 372 if not self.active: - 373 out += ' (unconnected)' - 374 else: - 375 if self.local_cipher != '': - 376 out += ' (cipher %s, %d bits)' % (self.local_cipher, - 377 self._cipher_info[self.local_cipher]['key-size'] * 8) - 378 if self.is_authenticated(): - 379 out += ' (active; %d open channel(s))' % len(self._channels) - 380 elif self.initial_kex_done: - 381 out += ' (connected; awaiting auth)' - 382 else: - 383 out += ' (connecting)' - 384 out += '>' - 385 return out -
386 -
387 - def atfork(self): -
388 """ - 389 Terminate this Transport without closing the session. On posix - 390 systems, if a Transport is open during process forking, both parent - 391 and child will share the underlying socket, but only one process can - 392 use the connection (without corrupting the session). Use this method - 393 to clean up a Transport object without disrupting the other process. - 394 - 395 @since: 1.5.3 - 396 """ - 397 self.sock. 310 except AttributeError: + 311 pass + 312 + 313 # negotiated crypto parameters + 314 self.packetizer = Packetizer(sock) + 315 self.local_version = 'SSH-' + self._PROTO_ID + '-' + self._CLIENT_ID + 316 self.remote_version = '' + 317 self.local_cipher = self.remote_cipher = '' + 318 self.local_kex_init = self.remote_kex_init = None + 319 self.local_mac = self.remote_mac = None + 320 self.local_compression = self.remote_compression = None + 321 self.session_id = None + 322 self.host_key_type = None + 323 self.host_key = None + 324 + 325 # state used during negotiation + 326 self.kex_engine = None + 327 self.H = None + 328 self.K = None + 329 + 330 self.active = False + 331 self.initial_kex_done = False + 332 self.in_kex = False + 333 self.authenticated = False + 334 self._expected_packet = tuple() + 335 self.lock = threading.Lock() # synchronization (always higher level than write_lock) + 336 + 337 # tracking open channels + 338 self._channels = ChannelMap() + 339 self.channel_events = { } # (id -> Event) + 340 self.channels_seen = { } # (id -> True) + 341 self._channel_counter = 1 + 342 self.window_size = 65536 + 343 self.max_packet_size = 34816 + 344 self._x11_handler = None + 345 self._tcp_handler = None + 346 + 347 self.saved_exception = None + 348 self.clear_to_send = threading.Event() + 349 self.clear_to_send_lock = threading.Lock() + 350 self.clear_to_send_timeout = 30.0 + 351 self.log_name = 'paramiko.transport' + 352 self.logger = util.get_logger(self.log_name) + 353 self.packetizer.set_log(self.logger) + 354 self.auth_handler = None + 355 self.global_response = None # response Message from an arbitrary global request + 356 self.completion_event = None # user-defined event callbacks + 357 self.banner_timeout = 15 # how long (seconds) to wait for the SSH banner + 358 + 359 # server mode: + 360 self.server_mode = False + 361 self.server_object = None + 362 self.server_key_dict = { } + 363 self.server_accepts = [ ] + 364 self.server_accept_cv = threading.Condition(self.lock) + 365 self.subsystem_table = { } +
366 +
367 - def __repr__(self): +
368 """ + 369 Returns a string representation of this object, for debugging. + 370 + 371 @rtype: str + 372 """ + 373 out = '<paramiko.Transport at %s' % hex(long(id(self)) & 0xffffffffL) + 374 if not self.active: + 375 out += ' (unconnected)' + 376 else: + 377 if self.local_cipher != '': + 378 out += ' (cipher %s, %d bits)' % (self.local_cipher, + 379 self._cipher_info[self.local_cipher]['key-size'] * 8) + 380 if self.is_authenticated(): + 381 out += ' (active; %d open channel(s))' % len(self._channels) + 382 elif self.initial_kex_done: + 383 out += ' (connected; awaiting auth)' + 384 else: + 385 out += ' (connecting)' + 386 out += '>' + 387 return out +
388 +
389 - def atfork(self): +
390 """ + 391 Terminate this Transport without closing the session. On posix + 392 systems, if a Transport is open during process forking, both parent + 393 and child will share the underlying socket, but only one process can + 394 use the connection (without corrupting the session). Use this method + 395 to clean up a Transport object without disrupting the other process. + 396 + 397 @since: 1.5.3 + 398 """ + 399 self.sock.close() - 398 self. 400 self.close() -
399 -
400 - def get_security_options(self): -
401 """ - 402 Return a L{SecurityOptions} object which can be used to tweak the - 403 encryption algorithms this transport will permit, and the order of - 404 preference for them. - 405 - 406 @return: an object that can be used to change the preferred algorithms - 407 for encryption, digest (hash), public key, and key exchange. - 408 @rtype: L{SecurityOptions} - 409 """ - 410 return SecurityOptions(self) -
411 -
412 - def start_client(self, event=None): -
413 """ - 414 Negotiate a new SSH2 session as a client. This is the first step after - 415 creating a new L{Transport}. A separate thread is created for protocol - 416 negotiation. - 417 - 418 If an event is passed in, this method returns immediately. When - 419 negotiation is done (successful or not), the given C{Event} will - 420 be triggered. On failure, L{is_active} will return C{False}. - 421 - 422 (Since 1.4) If C{event} is C{None}, this method will not return until - 423 negotation is done. On success, the method returns normally. - 424 Otherwise an SSHException is raised. - 425 - 426 After a successful negotiation, you will usually want to authenticate, - 427 calling L{auth_password <Transport.auth_password>} or - 428 L{auth_publickey <Transport.auth_publickey>}. - 429 - 430 @note: L{connect} is a simpler method for connecting as a client. +
401 +
402 - def get_security_options(self): +
403 """ + 404 Return a L{SecurityOptions} object which can be used to tweak the + 405 encryption algorithms this transport will permit, and the order of + 406 preference for them. + 407 + 408 @return: an object that can be used to change the preferred algorithms + 409 for encryption, digest (hash), public key, and key exchange. + 410 @rtype: L{SecurityOptions} + 411 """ + 412 return SecurityOptions(self) +
413 +
414 - def start_client(self, event=None): +
415 """ + 416 Negotiate a new SSH2 session as a client. This is the first step after + 417 creating a new L{Transport}. A separate thread is created for protocol + 418 negotiation. + 419 + 420 If an event is passed in, this method returns immediately. When + 421 negotiation is done (successful or not), the given C{Event} will + 422 be triggered. On failure, L{is_active} will return C{False}. + 423 + 424 (Since 1.4) If C{event} is C{None}, this method will not return until + 425 negotation is done. On success, the method returns normally. + 426 Otherwise an SSHException is raised. + 427 + 428 After a successful negotiation, you will usually want to authenticate, + 429 calling L{auth_password <Transport.auth_password>} or + 430 L{auth_publickey <Transport.auth_publickey>}. 431 - 432 @note: After calling this method (or L{start_server} or L{connect}), - 433 you should no longer directly read from or write to the original - 434 socket object. - 435 - 436 @param event: an event to trigger when negotiation is complete - 437 (optional) - 438 @type event: threading.Event - 439 - 440 @raise SSHException: if negotiation fails (and no C{event} was passed - 441 in) - 442 """ - 443 self.active = True - 444 if event is not None: - 445 # async, return immediately and let the app poll for completion - 446 self.completion_event = event - 447 self.start() - 448 return - 449 - 450 # synchronous, wait for a result - 451 self.completion_event = event = threading.Event() - 452 self.start() - 453 while True: - 454 event.wait(0.1) - 455 if not self.active: - 456 e = self.get_exception() - 457 if e is not None: - 458 raise e - 459 raise SSHException('Negotiation failed.') - 460 if event.isSet(): - 461 break -
462 -
463 - def start_server(self, event=None, server=None): -
464 """ - 465 Negotiate a new SSH2 session as a server. This is the first step after - 466 creating a new L{Transport} and setting up your server host key(s). A - 467 separate thread is created for protocol negotiation. - 468 - 469 If an event is passed in, this method returns immediately. When - 470 negotiation is done (successful or not), the given C{Event} will - 471 be triggered. On failure, L{is_active} will return C{False}. - 472 - 473 (Since 1.4) If C{event} is C{None}, this method will not return until - 474 negotation is done. On success, the method returns normally. - 475 Otherwise an SSHException is raised. - 476 - 477 After a successful negotiation, the client will need to authenticate. - 478 Override the methods - 479 L{get_allowed_auths <ServerInterface.get_allowed_auths>}, - 480 L{check_auth_none <ServerInterface.check_auth_none>}, - 481 L{check_auth_password <ServerInterface.check_auth_password>}, and - 482 L{check_auth_publickey <ServerInterface.check_auth_publickey>} in the - 483 given C{server} object to control the authentication process. - 484 - 485 After a successful authentication, the client should request to open - 486 a channel. Override - 487 L{check_channel_request <ServerInterface.check_channel_request>} in the - 488 given C{server} object to allow channels to be opened. - 489 - 490 @note: After calling this method (or L{start_client} or L{connect}), - 491 you should no longer directly read from or write to the original - 492 socket object. - 493 - 494 @param event: an event to trigger when negotiation is complete. - 495 @type event: threading.Event - 496 @param server: an object used to perform authentication and create - 497 L{Channel}s. - 498 @type server: L{server.ServerInterface} - 499 - 500 @raise SSHException: if negotiation fails (and no C{event} was passed - 501 in) - 502 """ - 503 if server is None: - 504 server = ServerInterface() - 505 self.server_mode = True - 506 self.server_object = server - 507 self.active = True - 508 if event is not None: - 509 # async, return immediately and let the app poll for completion - 510 self.completion_event = event - 511 self.start() - 512 return - 513 - 514 # synchronous, wait for a result - 515 self.completion_event = event = threading.Event() - 516 self.start() - 517 while True: - 518 event.wait(0.1) - 519 if not self.active: - 520 e = self.get_exception() - 521 if e is not None: - 522 raise e - 523 raise SSHException('Negotiation failed.') - 524 if event.isSet(): - 525 break -
526 -
527 - def add_server_key(self, key): -
528 """ - 529 Add a host key to the list of keys used for server mode. When behaving - 530 as a server, the host key is used to sign certain packets during the - 531 SSH2 negotiation, so that the client can trust that we are who we say - 532 we are. Because this is used for signing, the key must contain private - 533 key info, not just the public half. Only one key of each type (RSA or - 534 DSS) is kept. - 535 - 536 @param key: the host key to add, usually an L{RSAKey <rsakey.RSAKey>} or - 537 L{DSSKey <dsskey.DSSKey>}. - 538 @type key: L{PKey <pkey.PKey>} - 539 """ - 540 self.server_key_dict[key. 432 @note: L{connect} is a simpler method for connecting as a client. + 433 + 434 @note: After calling this method (or L{start_server} or L{connect}), + 435 you should no longer directly read from or write to the original + 436 socket object. + 437 + 438 @param event: an event to trigger when negotiation is complete + 439 (optional) + 440 @type event: threading.Event + 441 + 442 @raise SSHException: if negotiation fails (and no C{event} was passed + 443 in) + 444 """ + 445 self.active = True + 446 if event is not None: + 447 # async, return immediately and let the app poll for completion + 448 self.completion_event = event + 449 self.start() + 450 return + 451 + 452 # synchronous, wait for a result + 453 self.completion_event = event = threading.Event() + 454 self.start() + 455 Random.atfork() + 456 while True: + 457 event.wait(0.1) + 458 if not self.active: + 459 e = self.get_exception() + 460 if e is not None: + 461 raise e + 462 raise SSHException('Negotiation failed.') + 463 if event.isSet(): + 464 break +
465 +
466 - def start_server(self, event=None, server=None): +
467 """ + 468 Negotiate a new SSH2 session as a server. This is the first step after + 469 creating a new L{Transport} and setting up your server host key(s). A + 470 separate thread is created for protocol negotiation. + 471 + 472 If an event is passed in, this method returns immediately. When + 473 negotiation is done (successful or not), the given C{Event} will + 474 be triggered. On failure, L{is_active} will return C{False}. + 475 + 476 (Since 1.4) If C{event} is C{None}, this method will not return until + 477 negotation is done. On success, the method returns normally. + 478 Otherwise an SSHException is raised. + 479 + 480 After a successful negotiation, the client will need to authenticate. + 481 Override the methods + 482 L{get_allowed_auths <ServerInterface.get_allowed_auths>}, + 483 L{check_auth_none <ServerInterface.check_auth_none>}, + 484 L{check_auth_password <ServerInterface.check_auth_password>}, and + 485 L{check_auth_publickey <ServerInterface.check_auth_publickey>} in the + 486 given C{server} object to control the authentication process. + 487 + 488 After a successful authentication, the client should request to open + 489 a channel. Override + 490 L{check_channel_request <ServerInterface.check_channel_request>} in the + 491 given C{server} object to allow channels to be opened. + 492 + 493 @note: After calling this method (or L{start_client} or L{connect}), + 494 you should no longer directly read from or write to the original + 495 socket object. + 496 + 497 @param event: an event to trigger when negotiation is complete. + 498 @type event: threading.Event + 499 @param server: an object used to perform authentication and create + 500 L{Channel}s. + 501 @type server: L{server.ServerInterface} + 502 + 503 @raise SSHException: if negotiation fails (and no C{event} was passed + 504 in) + 505 """ + 506 if server is None: + 507 server = ServerInterface() + 508 self.server_mode = True + 509 self.server_object = server + 510 self.active = True + 511 if event is not None: + 512 # async, return immediately and let the app poll for completion + 513 self.completion_event = event + 514 self.start() + 515 return + 516 + 517 # synchronous, wait for a result + 518 self.completion_event = event = threading.Event() + 519 self.start() + 520 while True: + 521 event.wait(0.1) + 522 if not self.active: + 523 e = self.get_exception() + 524 if e is not None: + 525 raise e + 526 raise SSHException('Negotiation failed.') + 527 if event.isSet(): + 528 break +
529 +
530 - def add_server_key(self, key): +
531 """ + 532 Add a host key to the list of keys used for server mode. When behaving + 533 as a server, the host key is used to sign certain packets during the + 534 SSH2 negotiation, so that the client can trust that we are who we say + 535 we are. Because this is used for signing, the key must contain private + 536 key info, not just the public half. Only one key of each type (RSA or + 537 DSS) is kept. + 538 + 539 @param key: the host key to add, usually an L{RSAKey <rsakey.RSAKey>} or + 540 L{DSSKey <dsskey.DSSKey>}. + 541 @type key: L{PKey <pkey.PKey>} + 542 """ + 543 self.server_key_dict[key.get_name()] = key -
541 -
542 - def get_server_key(self): -
543 """ - 544 Return the active host key, in server mode. After negotiating with the - 545 client, this method will return the negotiated host key. If only one - 546 type of host key was set with L{add_server_key}, that's the only key - 547 that will ever be returned. But in cases where you have set more than - 548 one type of host key (for example, an RSA key and a DSS key), the key - 549 type will be negotiated by the client, and this method will return the - 550 key of the type agreed on. If the host key has not been negotiated - 551 yet, C{None} is returned. In client mode, the behavior is undefined. - 552 - 553 @return: host key of the type negotiated by the client, or C{None}. - 554 @rtype: L{PKey <pkey.PKey>} - 555 """ - 556 try: - 557 return self.server_key_dict[self.host_key_type] - 558 except KeyError: - 559 pass - 560 return None -
561 -
562 - def load_server_moduli(filename=None): -
563 """ - 564 I{(optional)} - 565 Load a file of prime moduli for use in doing group-exchange key - 566 negotiation in server mode. It's a rather obscure option and can be - 567 safely ignored. - 568 - 569 In server mode, the remote client may request "group-exchange" key - 570 negotiation, which asks the server to send a random prime number that - 571 fits certain criteria. These primes are pretty difficult to compute, - 572 so they can't be generated on demand. But many systems contain a file - 573 of suitable primes (usually named something like C{/etc/ssh/moduli}). - 574 If you call C{load_server_moduli} and it returns C{True}, then this - 575 file of primes has been loaded and we will support "group-exchange" in - 576 server mode. Otherwise server mode will just claim that it doesn't - 577 support that method of key negotiation. - 578 - 579 @param filename: optional path to the moduli file, if you happen to - 580 know that it's not in a standard location. - 581 @type filename: str - 582 @return: True if a moduli file was successfully loaded; False - 583 otherwise. - 584 @rtype: bool - 585 - 586 @note: This has no effect when used in client mode. - 587 """ - 588 Transport._modulus_pack = ModulusPack(randpool) - 589 # places to look for the openssh "moduli" file - 590 file_list = [ '/etc/ssh/moduli', '/usr/local/etc/moduli' ] - 591 if filename is not None: - 592 file_list.insert(0, filename) - 593 for fn in file_list: - 594 try: - 595 Transport._modulus_pack.read_file(fn) - 596 return True - 597 except IOError: - 598 pass - 599 # none succeeded - 600 Transport._modulus_pack = None - 601 return False -
602 load_server_moduli = staticmethod(load_server_moduli) - 603 -
604 - def close(self): -
605 """ - 606 Close this session, and any open channels that are tied to it. - 607 """ - 608 if not self.active: - 609 return - 610 self.active = False - 611 self.packetizer.get_name()] = key +
544 +
545 - def get_server_key(self): +
546 """ + 547 Return the active host key, in server mode. After negotiating with the + 548 client, this method will return the negotiated host key. If only one + 549 type of host key was set with L{add_server_key}, that's the only key + 550 that will ever be returned. But in cases where you have set more than + 551 one type of host key (for example, an RSA key and a DSS key), the key + 552 type will be negotiated by the client, and this method will return the + 553 key of the type agreed on. If the host key has not been negotiated + 554 yet, C{None} is returned. In client mode, the behavior is undefined. + 555 + 556 @return: host key of the type negotiated by the client, or C{None}. + 557 @rtype: L{PKey <pkey.PKey>} + 558 """ + 559 try: + 560 return self.server_key_dict[self.host_key_type] + 561 except KeyError: + 562 pass + 563 return None +
564 +
565 - def load_server_moduli(filename=None): +
566 """ + 567 I{(optional)} + 568 Load a file of prime moduli for use in doing group-exchange key + 569 negotiation in server mode. It's a rather obscure option and can be + 570 safely ignored. + 571 + 572 In server mode, the remote client may request "group-exchange" key + 573 negotiation, which asks the server to send a random prime number that + 574 fits certain criteria. These primes are pretty difficult to compute, + 575 so they can't be generated on demand. But many systems contain a file + 576 of suitable primes (usually named something like C{/etc/ssh/moduli}). + 577 If you call C{load_server_moduli} and it returns C{True}, then this + 578 file of primes has been loaded and we will support "group-exchange" in + 579 server mode. Otherwise server mode will just claim that it doesn't + 580 support that method of key negotiation. + 581 + 582 @param filename: optional path to the moduli file, if you happen to + 583 know that it's not in a standard location. + 584 @type filename: str + 585 @return: True if a moduli file was successfully loaded; False + 586 otherwise. + 587 @rtype: bool + 588 + 589 @note: This has no effect when used in client mode. + 590 """ + 591 Transport._modulus_pack = ModulusPack(rng) + 592 # places to look for the openssh "moduli" file + 593 file_list = [ '/etc/ssh/moduli', '/usr/local/etc/moduli' ] + 594 if filename is not None: + 595 file_list.insert(0, filename) + 596 for fn in file_list: + 597 try: + 598 Transport._modulus_pack.read_file(fn) + 599 return True + 600 except IOError: + 601 pass + 602 # none succeeded + 603 Transport._modulus_pack = None + 604 return False +
605 load_server_moduli = staticmethod(load_server_moduli) + 606 +
607 - def close(self): +
608 """ + 609 Close this session, and any open channels that are tied to it. + 610 """ + 611 if not self.active: + 612 return + 613 self.active = False + 614 self.packetizer.close() - 612 self.join() - 613 for chan in self._channels.values(): - 614 chan._unlink() -
615 -
616 - def get_remote_server_key(self): -
617 """ - 618 Return the host key of the server (in client mode). - 619 - 620 @note: Previously this call returned a tuple of (key type, key string). - 621 You can get the same effect by calling - 622 L{PKey.get_name <pkey.PKey.get_name>} for the key type, and - 623 C{str(key)} for the key string. - 624 - 625 @raise SSHException: if no session is currently active. - 626 - 627 @return: public key of the remote server - 628 @rtype: L{PKey <pkey.PKey>} - 629 """ - 630 if (not self.active) or (not self.initial_kex_done): - 631 raise SSHException('No existing session') - 632 return self.host_key -
633 -
634 - def is_active(self): -
635 """ - 636 Return true if this session is active (open). - 637 - 638 @return: True if the session is still active (open); False if the - 639 session is closed - 640 @rtype: bool - 641 """ - 642 return self.active -
643 -
644 - def open_session(self): -
645 """ - 646 Request a new channel to the server, of type C{"session"}. This - 647 is just an alias for C{open_channel('session')}. - 648 - 649 @return: a new L{Channel} - 650 @rtype: L{Channel} +paramiko.win_pageant.PageantConnection.close" class="py-name" href="#" onclick="return doclink('link-139', 'close', 'link-115');">close() + 615 self.join() + 616 for chan in self._channels.values(): + 617 chan._unlink() +
618 +
619 - def get_remote_server_key(self): +
620 """ + 621 Return the host key of the server (in client mode). + 622 + 623 @note: Previously this call returned a tuple of (key type, key string). + 624 You can get the same effect by calling + 625 L{PKey.get_name <pkey.PKey.get_name>} for the key type, and + 626 C{str(key)} for the key string. + 627 + 628 @raise SSHException: if no session is currently active. + 629 + 630 @return: public key of the remote server + 631 @rtype: L{PKey <pkey.PKey>} + 632 """ + 633 if (not self.active) or (not self.initial_kex_done): + 634 raise SSHException('No existing session') + 635 return self.host_key +
636 +
637 - def is_active(self): +
638 """ + 639 Return true if this session is active (open). + 640 + 641 @return: True if the session is still active (open); False if the + 642 session is closed + 643 @rtype: bool + 644 """ + 645 return self.active +
646 +
647 - def open_session(self): +
648 """ + 649 Request a new channel to the server, of type C{"session"}. This + 650 is just an alias for C{open_channel('session')}. 651 - 652 @raise SSHException: if the request is rejected or the session ends - 653 prematurely - 654 """ - 655 return self.open_channel('session') -
656 -
657 - def open_x11_channel(self, src_addr=None): -
658 """ - 659 Request a new channel to the client, of type C{"x11"}. This - 660 is just an alias for C{open_channel('x11', src_addr=src_addr)}. - 661 - 662 @param src_addr: the source address of the x11 server (port is the - 663 x11 port, ie. 6010) - 664 @type src_addr: (str, int) - 665 @return: a new L{Channel} - 666 @rtype: L{Channel} - 667 - 668 @raise SSHException: if the request is rejected or the session ends - 669 prematurely - 670 """ - 671 return self.open_channel('x11', src_addr=src_addr) -
672 -
673 - def open_forwarded_tcpip_channel(self, (src_addr, src_port), (dest_addr, dest_port)): -
674 """ - 675 Request a new channel back to the client, of type C{"forwarded-tcpip"}. - 676 This is used after a client has requested port forwarding, for sending - 677 incoming connections back to the client. - 678 - 679 @param src_addr: originator's address - 680 @param src_port: originator's port - 681 @param dest_addr: local (server) connected address - 682 @param dest_port: local (server) connected port - 683 """ - 684 return self.open_channel('forwarded-tcpip', (dest_addr, dest_port), (src_addr, src_port)) -
685 -
686 - def open_channel(self, kind, dest_addr=None, src_addr=None): -
687 """ - 688 Request a new channel to the server. L{Channel}s are socket-like - 689 objects used for the actual transfer of data across the session. - 690 You may only request a channel after negotiating encryption (using - 691 L{connect} or L{start_client}) and authenticating. - 692 - 693 @param kind: the kind of channel requested (usually C{"session"}, - 694 C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"}) - 695 @type kind: str - 696 @param dest_addr: the destination address of this port forwarding, - 697 if C{kind} is C{"forwarded-tcpip"} or C{"direct-tcpip"} (ignored - 698 for other channel types) - 699 @type dest_addr: (str, int) - 700 @param src_addr: the source address of this port forwarding, if - 701 C{kind} is C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"} - 702 @type src_addr: (str, int) - 703 @return: a new L{Channel} on success - 704 @rtype: L{Channel} - 705 - 706 @raise SSHException: if the request is rejected or the session ends - 707 prematurely - 708 """ - 709 chan = None - 710 if not self.active: - 711 # don't bother trying to allocate a channel - 712 return None - 713 self.lock.acquire() - 714 try: - 715 chanid = self._next_channel() - 716 m = Message() - 717 m.add_byte(chr( 652 @return: a new L{Channel} + 653 @rtype: L{Channel} + 654 + 655 @raise SSHException: if the request is rejected or the session ends + 656 prematurely + 657 """ + 658 return self.open_channel('session') +
659 +
660 - def open_x11_channel(self, src_addr=None): +
661 """ + 662 Request a new channel to the client, of type C{"x11"}. This + 663 is just an alias for C{open_channel('x11', src_addr=src_addr)}. + 664 + 665 @param src_addr: the source address of the x11 server (port is the + 666 x11 port, ie. 6010) + 667 @type src_addr: (str, int) + 668 @return: a new L{Channel} + 669 @rtype: L{Channel} + 670 + 671 @raise SSHException: if the request is rejected or the session ends + 672 prematurely + 673 """ + 674 return self.open_channel('x11', src_addr=src_addr) +
675 +
676 - def open_forwarded_tcpip_channel(self, (src_addr, src_port), (dest_addr, dest_port)): +
677 """ + 678 Request a new channel back to the client, of type C{"forwarded-tcpip"}. + 679 This is used after a client has requested port forwarding, for sending + 680 incoming connections back to the client. + 681 + 682 @param src_addr: originator's address + 683 @param src_port: originator's port + 684 @param dest_addr: local (server) connected address + 685 @param dest_port: local (server) connected port + 686 """ + 687 return self.open_channel('forwarded-tcpip', (dest_addr, dest_port), (src_addr, src_port)) +
688 +
689 - def open_channel(self, kind, dest_addr=None, src_addr=None): +
690 """ + 691 Request a new channel to the server. L{Channel}s are socket-like + 692 objects used for the actual transfer of data across the session. + 693 You may only request a channel after negotiating encryption (using + 694 L{connect} or L{start_client}) and authenticating. + 695 + 696 @param kind: the kind of channel requested (usually C{"session"}, + 697 C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"}) + 698 @type kind: str + 699 @param dest_addr: the destination address of this port forwarding, + 700 if C{kind} is C{"forwarded-tcpip"} or C{"direct-tcpip"} (ignored + 701 for other channel types) + 702 @type dest_addr: (str, int) + 703 @param src_addr: the source address of this port forwarding, if + 704 C{kind} is C{"forwarded-tcpip"}, C{"direct-tcpip"}, or C{"x11"} + 705 @type src_addr: (str, int) + 706 @return: a new L{Channel} on success + 707 @rtype: L{Channel} + 708 + 709 @raise SSHException: if the request is rejected or the session ends + 710 prematurely + 711 """ + 712 if not self.active: + 713 raise SSHException('SSH session not active') + 714 self.lock.acquire() + 715 try: + 716 chanid = self._next_channel() + 717 m = Message() + 718 m.add_byte(chr(MSG_CHANNEL_OPEN)) - 718 m.add_string(kind) - 719 m.add_int(chanid) - 720 m.add_int(self.window_size) - 721 m.add_int(self.max_packet_size) - 722 if (kind == 'forwarded-tcpip') or (kind == 'direct-tcpip'): - 723 m.add_string(dest_addr[0]) - 724 m.add_int(dest_addr[1]) - 725 m.add_string(src_addr[0]) - 726 m.add_int(src_addr[1]) - 727 elif kind == 'x11': - 728 m.add_string(src_addr[0]) - 729 m.add_int(src_addr[1]) - 730 chan = Channel(chanid) - 731 self._channels.put(chanid, chan) - 732 self.channel_events[chanid] = event = threading.Event() - 733 self.channels_seen[chanid] = True - 734 chan._set_transport(self) - 735 chan._set_window(self.window_size, self.max_packet_size) - 736 finally: - 737 self.lock.release() - 738 self._send_user_message(m) - 739 while True: - 740 event.wait(0.1); - 741 if not self.active: - 742 e = self.get_exception() - 743 if e is None: - 744 e = SSHException('Unable to open channel.') - 745 raise e - 746 if event.isSet(): - 747 break - 748 chan = self._channels.get(chanid) - 749 if chan is not None: - 750 return chan - 751 e = self.get_exception() - 752 if e is None: - 753 e = SSHException('Unable to open channel.') - 754 raise e -
755 -
756 - def request_port_forward(self, address, port, handler=None): -
757 """ - 758 Ask the server to forward TCP connections from a listening port on - 759 the server, across this SSH session. - 760 - 761 If a handler is given, that handler is called from a different thread - 762 whenever a forwarded connection arrives. The handler parameters are:: - 763 - 764 handler(channel, (origin_addr, origin_port), (server_addr, server_port)) - 765 - 766 where C{server_addr} and C{server_port} are the address and port that - 767 the server was listening on. - 768 - 769 If no handler is set, the default behavior is to send new incoming - 770 forwarded connections into the accept queue, to be picked up via - 771 L{accept}. - 772 - 773 @param address: the address to bind when forwarding - 774 @type address: str - 775 @param port: the port to forward, or 0 to ask the server to allocate - 776 any port - 777 @type port: int - 778 @param handler: optional handler for incoming forwarded connections - 779 @type handler: function(Channel, (str, int), (str, int)) - 780 @return: the port # allocated by the server - 781 @rtype: int - 782 - 783 @raise SSHException: if the server refused the TCP forward request - 784 """ - 785 if not self.active: - 786 raise SSHException('SSH session not active') - 787 address = str(address) - 788 port = int(port) - 789 response = self.global_request('tcpip-forward', (address, port), wait=True) - 790 if response is None: - 791 raise SSHException('TCP forwarding request denied') - 792 if port == 0: - 793 port = response.get_int() - 794 if handler is None: - 795 def default_handler(channel, (src_addr, src_port), (dest_addr, dest_port)): - 796 self._queue_incoming_channel(channel) -
797 handler = default_handler - 798 self._tcp_handler = handler - 799 return port -
800 -
801 - def cancel_port_forward(self, address, port): -
802 """ - 803 Ask the server to cancel a previous port-forwarding request. No more - 804 connections to the given address & port will be forwarded across this - 805 ssh connection. - 806 - 807 @param address: the address to stop forwarding - 808 @type address: str - 809 @param port: the port to stop forwarding - 810 @type port: int - 811 """ - 812 if not self.active: - 813 return - 814 self._tcp_handler = None - 815 self.global_request('cancel-tcpip-forward', (address, port), wait=True) -
816 -
817 - def open_sftp_client(self): -
818 """ - 819 Create an SFTP client channel from an open transport. On success, - 820 an SFTP session will be opened with the remote host, and a new - 821 SFTPClient object will be returned. - 822 - 823 @return: a new L{SFTPClient} object, referring to an sftp session - 824 (channel) across this transport - 825 @rtype: L{SFTPClient} - 826 """ - 827 return SFTPClient.from_transport(self) -
828 -
829 - def send_ignore(self, bytes=None): -
830 """ - 831 Send a junk packet across the encrypted link. This is sometimes used - 832 to add "noise" to a connection to confuse would-be attackers. It can - 833 also be used as a keep-alive for long lived connections traversing - 834 firewalls. - 835 - 836 @param bytes: the number of random bytes to send in the payload of the - 837 ignored packet -- defaults to a random number from 10 to 41. - 838 @type bytes: int - 839 """ - 840 m = Message() - 841 m.add_byte(chr(MSG_CHANNEL_OPEN)) + 719 m.add_string(kind) + 720 m.add_int(chanid) + 721 m.add_int(self.window_size) + 722 m.add_int(self.max_packet_size) + 723 if (kind == 'forwarded-tcpip') or (kind == 'direct-tcpip'): + 724 m.add_string(dest_addr[0]) + 725 m.add_int(dest_addr[1]) + 726 m.add_string(src_addr[0]) + 727 m.add_int(src_addr[1]) + 728 elif kind == 'x11': + 729 m.add_string(src_addr[0]) + 730 m.add_int(src_addr[1]) + 731 chan = Channel(chanid) + 732 self._channels.put(chanid, chan) + 733 self.channel_events[chanid] = event = threading.Event() + 734 self.channels_seen[chanid] = True + 735 chan._set_transport(self) + 736 chan._set_window(self.window_size, self.max_packet_size) + 737 finally: + 738 self.lock.release() + 739 self._send_user_message(m) + 740 while True: + 741 event.wait(0.1); + 742 if not self.active: + 743 e = self.get_exception() + 744 if e is None: + 745 e = SSHException('Unable to open channel.') + 746 raise e + 747 if event.isSet(): + 748 break + 749 chan = self._channels.get(chanid) + 750 if chan is not None: + 751 return chan + 752 e = self.get_exception() + 753 if e is None: + 754 e = SSHException('Unable to open channel.') + 755 raise e +
756 +
757 - def request_port_forward(self, address, port, handler=None): +
758 """ + 759 Ask the server to forward TCP connections from a listening port on + 760 the server, across this SSH session. + 761 + 762 If a handler is given, that handler is called from a different thread + 763 whenever a forwarded connection arrives. The handler parameters are:: + 764 + 765 handler(channel, (origin_addr, origin_port), (server_addr, server_port)) + 766 + 767 where C{server_addr} and C{server_port} are the address and port that + 768 the server was listening on. + 769 + 770 If no handler is set, the default behavior is to send new incoming + 771 forwarded connections into the accept queue, to be picked up via + 772 L{accept}. + 773 + 774 @param address: the address to bind when forwarding + 775 @type address: str + 776 @param port: the port to forward, or 0 to ask the server to allocate + 777 any port + 778 @type port: int + 779 @param handler: optional handler for incoming forwarded connections + 780 @type handler: function(Channel, (str, int), (str, int)) + 781 @return: the port # allocated by the server + 782 @rtype: int + 783 + 784 @raise SSHException: if the server refused the TCP forward request + 785 """ + 786 if not self.active: + 787 raise SSHException('SSH session not active') + 788 address = str(address) + 789 port = int(port) + 790 response = self.global_request('tcpip-forward', (address, port), wait=True) + 791 if response is None: + 792 raise SSHException('TCP forwarding request denied') + 793 if port == 0: + 794 port = response.get_int() + 795 if handler is None: + 796 def default_handler(channel, (src_addr, src_port), (dest_addr, dest_port)): + 797 self._queue_incoming_channel(channel) +
798 handler = default_handler + 799 self._tcp_handler = handler + 800 return port +
801 +
802 - def cancel_port_forward(self, address, port): +
803 """ + 804 Ask the server to cancel a previous port-forwarding request. No more + 805 connections to the given address & port will be forwarded across this + 806 ssh connection. + 807 + 808 @param address: the address to stop forwarding + 809 @type address: str + 810 @param port: the port to stop forwarding + 811 @type port: int + 812 """ + 813 if not self.active: + 814 return + 815 self._tcp_handler = None + 816 self.global_request('cancel-tcpip-forward', (address, port), wait=True) +
817 +
818 - def open_sftp_client(self): +
819 """ + 820 Create an SFTP client channel from an open transport. On success, + 821 an SFTP session will be opened with the remote host, and a new + 822 SFTPClient object will be returned. + 823 + 824 @return: a new L{SFTPClient} object, referring to an sftp session + 825 (channel) across this transport + 826 @rtype: L{SFTPClient} + 827 """ + 828 return SFTPClient.from_transport(self) +
829 +
830 - def send_ignore(self, bytes=None): +
831 """ + 832 Send a junk packet across the encrypted link. This is sometimes used + 833 to add "noise" to a connection to confuse would-be attackers. It can + 834 also be used as a keep-alive for long lived connections traversing + 835 firewalls. + 836 + 837 @param bytes: the number of random bytes to send in the payload of the + 838 ignored packet -- defaults to a random number from 10 to 41. + 839 @type bytes: int + 840 """ + 841 m = Message() + 842 m.add_byte(chr(MSG_IGNORE)) - 842 randpool.stir() +paramiko.util.MSG_IGNORE" class="py-name" href="#" onclick="return doclink('link-176', 'MSG_IGNORE', 'link-176');">MSG_IGNORE)) 843 if bytes is None: - 844 bytes = (ord(randpool.get_bytes(1)) % 32) + 10 - 845 m.add_bytes(randpool.get_bytes(bytes)) + 844 bytes = (ord(rng.read(1)) % 32) + 10 + 845 m.add_bytes(rng.read(bytes)) 846 self._send_user_message(m)
847
848 - def renegotiate_keys(self): @@ -1168,7 +1149,7 @@ paramiko.rng.StrongLockingRandomPool.get_bytes" class="py-name" href="#" onclick 862 while True: 863 self.completion_event.wait(0.1) 864 if not self.active: - 865 e = self.get_exception() + 865 e = self.get_exception() 866 if e is not None: 867 raise e 868 raise SSHException('Negotiation failed.') @@ -1188,7 +1169,7 @@ paramiko.rng.StrongLockingRandomPool.get_bytes" class="py-name" href="#" onclick 882 @type interval: int 883 """ 884 self.packetizer.set_keepalive(interval, - 885 lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False)) + 885 lambda x=weakref.proxy(self): x.global_request('keepalive@lag.net', wait=False))
886
887 - def global_request(self, kind, data=None, wait=True):
888 """ @@ -1211,7 +1192,7 @@ paramiko.rng.StrongLockingRandomPool.get_bytes" class="py-name" href="#" onclick 905 if wait: 906 self.completion_event = threading.Event() 907 m = Message() - 908 m.add_byte(chr( 908 m.add_byte(chr(MSG_GLOBAL_REQUEST)) - 909 m.add_string(kind) + 909 m.add_string(kind) 910 m.add_boolean(wait) 911 if data is not None: 912 m.get_name() ] +paramiko.RSAKey.get_name" class="py-name" href="#" onclick="return doclink('link-194', 'get_name', 'link-127');">get_name() ] 988 989 self.start_client() 990 @@ -1347,11 +1328,11 @@ paramiko.RSAKey.get_name" class="py-name" href="#" onclick="return doclink('link paramiko.Channel.get_name paramiko.DSSKey.get_name paramiko.PKey.get_name -paramiko.RSAKey.get_name" class="py-name" href="#" onclick="return doclink('link-197', 'get_name', 'link-126');">get_name() != hostkey.get_name() != hostkey.get_name()) or (str(key) != str(hostkey)): +paramiko.RSAKey.get_name" class="py-name" href="#" onclick="return doclink('link-198', 'get_name', 'link-127');">get_name()) or (str(key) != str(hostkey)): 995 self._log(get_name(), repr(str(hostkey)))) +paramiko.RSAKey.get_name" class="py-name" href="#" onclick="return doclink('link-201', 'get_name', 'link-127');">get_name(), repr(str(hostkey)))) 997 self._log(get_name(), repr(str(key)))) +paramiko.RSAKey.get_name" class="py-name" href="#" onclick="return doclink('link-203', 'get_name', 'link-127');">get_name(), repr(str(key)))) 998 raise SSHException('Bad host key from server') 999 self._log(get_name()) +paramiko.RSAKey.get_name" class="py-name" href="#" onclick="return doclink('link-206', 'get_name', 'link-127');">get_name()) 1000 1001 if (pkey is not None) or (password is not None): 1002 if password is not None: @@ -1988,7 +1969,7 @@ paramiko.RSAKey.verify_ssh_sig" class="py-name" href="#" onclick="return doclink 1451 m = Message() 1452 m.add_mpint(self.K) 1453 m.add_bytes(self.H) -1454 m.add_byte(id) +1454 m.add_byte(id) 1455 m.add_bytes(self.session_id) 1456 out = sofar = SHA.new(str(m)).digest() 1457 while len(out) < nbytes: @@ -2153,7 +2134,7 @@ paramiko.sftp_handle.MSG_IGNORE paramiko.sftp_server.MSG_IGNORE paramiko.sftp_si.MSG_IGNORE paramiko.transport.MSG_IGNORE -paramiko.util.MSG_IGNORE" class="py-name" href="#" onclick="return doclink('link-315', 'MSG_IGNORE', 'link-174');">MSG_IGNORE: +paramiko.util.MSG_IGNORE" class="py-name" href="#" onclick="return doclink('link-315', 'MSG_IGNORE', 'link-176');">MSG_IGNORE: 1528 continue 1529 elif ptype == 1545 if ptype in self._handler_table: 1546 self._handler_table[ptype](self, m) 1547 elif ptype in self._channel_handler_table: -1548 chanid = m.get_int() +1548 chanid = m.get_int() 1549 chan = self._channels.get(chanid) 1550 if chan is not None: @@ -2316,7 +2297,7 @@ paramiko.sftp_si.WARNING paramiko.transport.WARNING paramiko.util.WARNING" class="py-name" href="#" onclick="return doclink('link-336', 'WARNING', 'link-336');">WARNING, 'Oops, unhandled type %d' % ptype) 1562 msg = Message() -1563 msg.add_byte(chr(1563 msg.add_byte(chr(MSG_UNIMPLEMENTED)) -1564 msg.add_int(m.seqno) +1564 msg.add_int(m.seqno) 1565 self._send_message(msg) 1566 except SSHException, e: 1567 self._log(DEBUG, 'EOF in transport thread') 1572 #self._log(DEBUG, util.tb_strings()) 1573 self.saved_exception = e -1574 except socket.error, e: +1574 except socket.error, e: 1575 if type(e.args) is tuple: 1576 emsg = '%s (%d)' % (e.args[1], e.args[0]) 1577 else: 1578 emsg = e.args -1579 self._log(1579 self._log(ERROR, 'Socket exception: ' + emsg) +paramiko.util.ERROR" class="py-name" href="#" onclick="return doclink('link-347', 'ERROR', 'link-328');">ERROR, 'Socket exception: ' + emsg) 1580 self.saved_exception = e 1581 except Exception, e: -1582 self._log(1582 self._log(ERROR, 'Unknown exception: ' + str(e)) -1583 self._log(ERROR, 'Unknown exception: ' + str(e)) +1583 self._log(ERROR, util.tb_strings()) +paramiko.util.ERROR" class="py-name" href="#" onclick="return doclink('link-349', 'ERROR', 'link-328');">ERROR, util.tb_strings()) 1584 self.saved_exception = e -1585 _active_threads.remove(self) -1586 for chan in self._channels.values(): +1585 _active_threads.remove(self) +1586 for chan in self._channels.values(): 1587 chan._unlink() 1588 if self.active: 1589 self.active = False -1590 self.packetizer.1590 self.packetizer.close() +paramiko.win_pageant.PageantConnection.close" class="py-name" href="#" onclick="return doclink('link-355', 'close', 'link-115');">close() 1591 if self.completion_event != None: -1592 self.completion_event.1592 self.completion_event.set() -1593 if self.auth_handler is not None: -1594 self.auth_handler.abort() -1595 for event in self.channel_events.values(): -1596 event.set() +1593 if self.auth_handler is not None: +1594 self.auth_handler.abort() +1595 for event in self.channel_events.values(): +1596 event.set() +paramiko.pipe.WindowsPipe.set" class="py-name" href="#" onclick="return doclink('link-360', 'set', 'link-356');">set() 1597 try: 1598 self.lock.acquire() 1599 self.server_accept_cv.notify() 1600 finally: 1601 self.lock.release() -1602 self.sock.1602 self.sock.close() +paramiko.win_pageant.PageantConnection.close" class="py-name" href="#" onclick="return doclink('link-361', 'close', 'link-115');">close()
1603 1604 1605 ### protocol stages @@ -2540,18 +2520,18 @@ paramiko.win_pageant.PageantConnection.close" class="py-name" href="#" onclick="
1609 # throws SSHException on anything unusual 1610 self.clear_to_send_lock.acquire() 1611 try: -1612 self.clear_to_send.1612 self.clear_to_send.clear() +paramiko.pipe.WindowsPipe.clear" class="py-name" href="#" onclick="return doclink('link-362', 'clear', 'link-362');">clear() 1613 finally: 1614 self.clear_to_send_lock.release() 1615 if self.local_kex_init == None: 1616 # remote side wants to renegotiate 1617 self._send_kex_init() 1618 self._parse_kex_init(m) -1619 self.kex_engine.start_kex() +1619 self.kex_engine.start_kex()
1620
1621 - def _check_banner(self):
1622 # this is slow, but we only have to do it once @@ -2563,12 +2543,12 @@ paramiko.kex_group1.KexGroup1.start_kex" class="py-name" href="#" onclick="retur 1628 else: 1629 timeout = 2 1630 try: -1631 buf = self.packetizer.readline(timeout) +1631 buf = self.packetizer.readline(timeout) 1632 except Exception, x: -1633 raise SSHException('Error reading SSH protocol banner' + str(x)) +1633 raise SSHException('Error reading SSH protocol banner' + str(x)) 1634 if buf[:4] == 'SSH-': 1635 break -1636 self._log(1636 self._log(DEBUG, 'Banner: ' + buf) +paramiko.util.DEBUG" class="py-name" href="#" onclick="return doclink('link-366', 'DEBUG', 'link-192');">DEBUG, 'Banner: ' + buf) 1637 if buf[:4] != 'SSH-': -1638 raise SSHException('Indecipherable protocol version "' + buf + '"') +1638 raise SSHException('Indecipherable protocol version "' + buf + '"') 1639 # save this server version string for later 1640 self.remote_version = buf 1641 # pull off any attached comment @@ -2603,12 +2583,12 @@ paramiko.util.DEBUG" class="py-name" href="#" onclick="return doclink('link-367' 1647 # parse out version string and make sure it matches 1648 segs = buf.split('-', 2) 1649 if len(segs) < 3: -1650 raise SSHException('Invalid SSH banner') +1650 raise SSHException('Invalid SSH banner') 1651 version = segs[1] -1652 client = segs[2] +1652 client = segs[2] 1653 if version != '1.99' and version != '2.0': -1654 raise SSHException('Incompatible version (%s instead of 2.0)' % (version,)) -1655 self._log(1654 raise SSHException('Incompatible version (%s instead of 2.0)' % (version,)) +1655 self._log(INFO, 'Connected (version %s, client %s)' % (version, client)) +paramiko.util.INFO" class="py-name" href="#" onclick="return doclink('link-371', 'INFO', 'link-371');">INFO, 'Connected (version %s, client %s)' % (version, client))
1656
1657 - def _send_kex_init(self):
1658 """ @@ -2638,47 +2618,26 @@ paramiko.util.INFO" class="py-name" href="#" onclick="return doclink('link-372', 1661 """ 1662 self.clear_to_send_lock.acquire() 1663 try: -1664 self.clear_to_send.1664 self.clear_to_send.clear() +paramiko.pipe.WindowsPipe.clear" class="py-name" href="#" onclick="return doclink('link-373', 'clear', 'link-362');">clear() 1665 finally: 1666 self.clear_to_send_lock.release() 1667 self.in_kex = True 1668 if self.server_mode: -1669 if (self._modulus_pack is None) and ('diffie-hellman-group-exchange-sha1' in self._preferred_kex): +1669 if (self._modulus_pack is None) and ('diffie-hellman-group-exchange-sha1' in self._preferred_kex): 1670 # can't do group-exchange if we don't have a pack of potential primes -1671 pkex = list(self.get_security_options().kex) -1672 pkex.remove('diffie-hellman-group-exchange-sha1') -1673 self.get_security_options().kex = pkex -1674 available_server_keys = filter(self.server_key_dict.keys().__contains__, -1675 self._preferred_keys) +1671 pkex = list(self.get_security_options().kex) +1672 pkex.remove('diffie-hellman-group-exchange-sha1') +1673 self.get_security_options().kex = pkex +1674 available_server_keys = filter(self.server_key_dict.keys().__contains__, +1675 self._preferred_keys) 1676 else: -1677 available_server_keys = self._preferred_keys +1677 available_server_keys = self._preferred_keys 1678 -1679 randpool.stir() -1680 m = Message() -1681 m.add_byte(chr(1679 m = Message() +1680 m.add_byte(chr(MSG_KEXINIT)) -1682 m.add_bytes(randpool.get_bytes(16)) -1683 m.add_list(self._preferred_kex) -1684 m.add_list(available_server_keys) -1685 m.add_list(self._preferred_ciphers) -1686 m.add_list(self._preferred_ciphers) -1687 m.add_list(self._preferred_macs) -1688 m.add_list(self._preferred_macs) -1689 m.add_list(self._preferred_compression) -1690 m.add_list(self._preferred_compression) -1691 m.add_string('') -1692 m.add_string('') -1693 m.add_boolean(False) -1694 m.add_int(0) -1695 # save a copy for later (needed to compute a hash) -1696 self.local_kex_init = str(m) -1697 self._send_message(m) -
1698 -
1699 - def _parse_kex_init(self, m): -
1700 cookie = m.get_bytes(16) -1701 kex_algo_list = m.get_list() -1702 server_key_algo_list = m.get_list() -1703 client_encrypt_algo_list = m.get_list() -1704 server_encrypt_algo_list = m.get_list() -1705 client_mac_algo_list = m.get_list() -1706 server_mac_algo_list = m.get_list() -1707 client_compress_algo_list = m.get_list() -1708 server_compress_algo_list = m.get_list() -1709 client_lang_list = m.get_list() -1710 server_lang_list = m.get_list() -1711 kex_follows = m.get_boolean() -1712 unused = m.get_int() -1713 -1714 self._log(MSG_KEXINIT)) +1681 m.add_bytes(rng.read(16)) +1682 m.add_list(self._preferred_kex) +1683 m.add_list(available_server_keys) +1684 m.add_list(self._preferred_ciphers) +1685 m.add_list(self._preferred_ciphers) +1686 m.add_list(self._preferred_macs) +1687 m.add_list(self._preferred_macs) +1688 m.add_list(self._preferred_compression) +1689 m.add_list(self._preferred_compression) +1690 m.add_string('') +1691 m.add_string('') +1692 m.add_boolean(False) +1693 m.add_int(0) +1694 # save a copy for later (needed to compute a hash) +1695 self.local_kex_init = str(m) +1696 self._send_message(m) +
1697 +
1698 - def _parse_kex_init(self, m): +
1699 cookie = m.get_bytes(16) +1700 kex_algo_list = m.get_list() +1701 server_key_algo_list = m.get_list() +1702 client_encrypt_algo_list = m.get_list() +1703 server_encrypt_algo_list = m.get_list() +1704 client_mac_algo_list = m.get_list() +1705 server_mac_algo_list = m.get_list() +1706 client_compress_algo_list = m.get_list() +1707 server_compress_algo_list = m.get_list() +1708 client_lang_list = m.get_list() +1709 server_lang_list = m.get_list() +1710 kex_follows = m.get_boolean() +1711 unused = m.get_int() +1712 +1713 self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) + \ -1715 ' client encrypt:' + str(client_encrypt_algo_list) + \ -1716 ' server encrypt:' + str(server_encrypt_algo_list) + \ -1717 ' client mac:' + str(client_mac_algo_list) + \ -1718 ' server mac:' + str(server_mac_algo_list) + \ -1719 ' client compress:' + str(client_compress_algo_list) + \ -1720 ' server compress:' + str(server_compress_algo_list) + \ -1721 ' client lang:' + str(client_lang_list) + \ -1722 ' server lang:' + str(server_lang_list) + \ -1723 ' kex follows?' + str(kex_follows)) -1724 -1725 # as a server, we pick the first item in the client's list that we support. -1726 # as a client, we pick the first item in our list that the server supports. -1727 if self.server_mode: -1728 agreed_kex = filter(self._preferred_kex.__contains__, kex_algo_list) -1729 else: -1730 agreed_kex = filter(kex_algo_list.__contains__, self._preferred_kex) -1731 if len(agreed_kex) == 0: -1732 raise SSHException('Incompatible ssh peer (no acceptable kex algorithm)') -1733 self.kex_engine = self._kex_info[agreed_kex[0]](self) -1734 -1735 if self.server_mode: -1736 available_server_keys = filter(self.server_key_dict.keys().__contains__, -1737 self._preferred_keys) -1738 agreed_keys = filter(available_server_keys.__contains__, server_key_algo_list) -1739 else: -1740 agreed_keys = filter(server_key_algo_list.__contains__, self._preferred_keys) -1741 if len(agreed_keys) == 0: -1742 raise SSHException('Incompatible ssh peer (no acceptable host key)') -1743 self.host_key_type = agreed_keys[0] -1744 if self.server_mode and (self.get_server_key() is None): -1745 raise SSHException('Incompatible ssh peer (can\'t match requested host key type)') -1746 -1747 if self.server_mode: -1748 agreed_local_ciphers = filter(self._preferred_ciphers.__contains__, -1749 server_encrypt_algo_list) -1750 agreed_remote_ciphers = filter(self._preferred_ciphers.__contains__, -1751 client_encrypt_algo_list) -1752 else: -1753 agreed_local_ciphers = filter(client_encrypt_algo_list.__contains__, -1754 self._preferred_ciphers) -1755 agreed_remote_ciphers = filter(server_encrypt_algo_list.__contains__, -1756 self._preferred_ciphers) -1757 if (len(agreed_local_ciphers) == 0) or (len(agreed_remote_ciphers) == 0): -1758 raise SSHException('Incompatible ssh server (no acceptable ciphers)') -1759 self.local_cipher = agreed_local_ciphers[0] -1760 self.remote_cipher = agreed_remote_ciphers[0] -1761 self._log(DEBUG, 'kex algos:' + str(kex_algo_list) + ' server key:' + str(server_key_algo_list) + \ +1714 ' client encrypt:' + str(client_encrypt_algo_list) + \ +1715 ' server encrypt:' + str(server_encrypt_algo_list) + \ +1716 ' client mac:' + str(client_mac_algo_list) + \ +1717 ' server mac:' + str(server_mac_algo_list) + \ +1718 ' client compress:' + str(client_compress_algo_list) + \ +1719 ' server compress:' + str(server_compress_algo_list) + \ +1720 ' client lang:' + str(client_lang_list) + \ +1721 ' server lang:' + str(server_lang_list) + \ +1722 ' kex follows?' + str(kex_follows)) +1723 +1724 # as a server, we pick the first item in the client's list that we support. +1725 # as a client, we pick the first item in our list that the server supports. +1726 if self.server_mode: +1727 agreed_kex = filter(self._preferred_kex.__contains__, kex_algo_list) +1728 else: +1729 agreed_kex = filter(kex_algo_list.__contains__, self._preferred_kex) +1730 if len(agreed_kex) == 0: +1731 raise SSHException('Incompatible ssh peer (no acceptable kex algorithm)') +1732 self.kex_engine = self._kex_info[agreed_kex[0]](self) +1733 +1734 if self.server_mode: +1735 available_server_keys = filter(self.server_key_dict.keys().__contains__, +1736 self._preferred_keys) +1737 agreed_keys = filter(available_server_keys.__contains__, server_key_algo_list) +1738 else: +1739 agreed_keys = filter(server_key_algo_list.__contains__, self._preferred_keys) +1740 if len(agreed_keys) == 0: +1741 raise SSHException('Incompatible ssh peer (no acceptable host key)') +1742 self.host_key_type = agreed_keys[0] +1743 if self.server_mode and (self.get_server_key() is None): +1744 raise SSHException('Incompatible ssh peer (can\'t match requested host key type)') +1745 +1746 if self.server_mode: +1747 agreed_local_ciphers = filter(self._preferred_ciphers.__contains__, +1748 server_encrypt_algo_list) +1749 agreed_remote_ciphers = filter(self._preferred_ciphers.__contains__, +1750 client_encrypt_algo_list) +1751 else: +1752 agreed_local_ciphers = filter(client_encrypt_algo_list.__contains__, +1753 self._preferred_ciphers) +1754 agreed_remote_ciphers = filter(server_encrypt_algo_list.__contains__, +1755 self._preferred_ciphers) +1756 if (len(agreed_local_ciphers) == 0) or (len(agreed_remote_ciphers) == 0): +1757 raise SSHException('Incompatible ssh server (no acceptable ciphers)') +1758 self.local_cipher = agreed_local_ciphers[0] +1759 self.remote_cipher = agreed_remote_ciphers[0] +1760 self._log(DEBUG, 'Ciphers agreed: local=%s, remote=%s' % (self.local_cipher, self.remote_cipher)) -1762 -1763 if self.server_mode: -1764 agreed_remote_macs = filter(self._preferred_macs.__contains__, client_mac_algo_list) -1765 agreed_local_macs = filter(self._preferred_macs.__contains__, server_mac_algo_list) -1766 else: -1767 agreed_local_macs = filter(client_mac_algo_list.__contains__, self._preferred_macs) -1768 agreed_remote_macs = filter(server_mac_algo_list.__contains__, self._preferred_macs) -1769 if (len(agreed_local_macs) == 0) or (len(agreed_remote_macs) == 0): -1770 raise SSHException('Incompatible ssh server (no acceptable macs)') -1771 self.local_mac = agreed_local_macs[0] -1772 self.remote_mac = agreed_remote_macs[0] -1773 -1774 if self.server_mode: -1775 agreed_remote_compression = filter(self._preferred_compression.__contains__, client_compress_algo_list) -1776 agreed_local_compression = filter(self._preferred_compression.__contains__, server_compress_algo_list) -1777 else: -1778 agreed_local_compression = filter(client_compress_algo_list.__contains__, self._preferred_compression) -1779 agreed_remote_compression = filter(server_compress_algo_list.__contains__, self._preferred_compression) -1780 if (len(agreed_local_compression) == 0) or (len(agreed_remote_compression) == 0): -1781 raise SSHException('Incompatible ssh server (no acceptable compression) %r %r %r' % (agreed_local_compression, agreed_remote_compression, self._preferred_compression)) -1782 self.local_compression = agreed_local_compression[0] -1783 self.remote_compression = agreed_remote_compression[0] -1784 -1785 self._log(DEBUG, 'Ciphers agreed: local=%s, remote=%s' % (self.local_cipher, self.remote_cipher)) +1761 +1762 if self.server_mode: +1763 agreed_remote_macs = filter(self._preferred_macs.__contains__, client_mac_algo_list) +1764 agreed_local_macs = filter(self._preferred_macs.__contains__, server_mac_algo_list) +1765 else: +1766 agreed_local_macs = filter(client_mac_algo_list.__contains__, self._preferred_macs) +1767 agreed_remote_macs = filter(server_mac_algo_list.__contains__, self._preferred_macs) +1768 if (len(agreed_local_macs) == 0) or (len(agreed_remote_macs) == 0): +1769 raise SSHException('Incompatible ssh server (no acceptable macs)') +1770 self.local_mac = agreed_local_macs[0] +1771 self.remote_mac = agreed_remote_macs[0] +1772 +1773 if self.server_mode: +1774 agreed_remote_compression = filter(self._preferred_compression.__contains__, client_compress_algo_list) +1775 agreed_local_compression = filter(self._preferred_compression.__contains__, server_compress_algo_list) +1776 else: +1777 agreed_local_compression = filter(client_compress_algo_list.__contains__, self._preferred_compression) +1778 agreed_remote_compression = filter(server_compress_algo_list.__contains__, self._preferred_compression) +1779 if (len(agreed_local_compression) == 0) or (len(agreed_remote_compression) == 0): +1780 raise SSHException('Incompatible ssh server (no acceptable compression) %r %r %r' % (agreed_local_compression, agreed_remote_compression, self._preferred_compression)) +1781 self.local_compression = agreed_local_compression[0] +1782 self.remote_compression = agreed_remote_compression[0] +1783 +1784 self._log(DEBUG, 'using kex %s; server key type %s; cipher: local %s, remote %s; mac: local %s, remote %s; compression: local %s, remote %s' % -1786 (agreed_kex[0], self.host_key_type, self.local_cipher, self.remote_cipher, self.local_mac, -1787 self.remote_mac, self.local_compression, self.remote_compression)) -1788 -1789 # save for computing hash later... -1790 # now wait! openssh has a bug (and others might too) where there are -1791 # actually some extra bytes (one NUL byte in openssh's case) added to -1792 # the end of the packet but not parsed. turns out we need to throw -1793 # away those bytes because they aren't part of the hash. -1794 self.remote_kex_init = chr(DEBUG, 'using kex %s; server key type %s; cipher: local %s, remote %s; mac: local %s, remote %s; compression: local %s, remote %s' % +1785 (agreed_kex[0], self.host_key_type, self.local_cipher, self.remote_cipher, self.local_mac, +1786 self.remote_mac, self.local_compression, self.remote_compression)) +1787 +1788 # save for computing hash later... +1789 # now wait! openssh has a bug (and others might too) where there are +1790 # actually some extra bytes (one NUL byte in openssh's case) added to +1791 # the end of the packet but not parsed. turns out we need to throw +1792 # away those bytes because they aren't part of the hash. +1793 self.remote_kex_init = chr(MSG_KEXINIT) + m.get_so_far() -
1795 -
1796 - def _activate_inbound(self): -
1797 "switch on newly negotiated encryption parameters for inbound traffic" -1798 block_size = self._cipher_info[self.remote_cipher]['block-size'] -1799 if self.server_mode: -1800 IV_in = self._compute_key('A', block_size) -1801 key_in = self._compute_key('C', self._cipher_info[self.remote_cipher]['key-size']) -1802 else: -1803 IV_in = self._compute_key('B', block_size) -1804 key_in = self._compute_key('D', self._cipher_info[self.remote_cipher]['key-size']) -1805 engine = self._get_cipher(self.remote_cipher, key_in, IV_in) -1806 mac_size = self._mac_info[self.remote_mac]['size'] -1807 mac_engine = self._mac_info[self.remote_mac]['class'] -1808 # initial mac keys are done in the hash's natural size (not the potentially truncated -1809 # transmission size) -1810 if self.server_mode: -1811 mac_key = self._compute_key('E', mac_engine.digest_size) -1812 else: -1813 mac_key = self._compute_key('F', mac_engine.digest_size) -1814 self.packetizer.set_inbound_cipher(engine, block_size, mac_engine, mac_size, mac_key) -1815 compress_in = self._compression_info[self.remote_compression][1] -1816 if (compress_in is not None) and ((self.remote_compression != 'zlib@openssh.com') or self.authenticated): -1817 self._log(MSG_KEXINIT) + m.get_so_far() +
1794 +
1795 - def _activate_inbound(self): +
1796 "switch on newly negotiated encryption parameters for inbound traffic" +1797 block_size = self._cipher_info[self.remote_cipher]['block-size'] +1798 if self.server_mode: +1799 IV_in = self._compute_key('A', block_size) +1800 key_in = self._compute_key('C', self._cipher_info[self.remote_cipher]['key-size']) +1801 else: +1802 IV_in = self._compute_key('B', block_size) +1803 key_in = self._compute_key('D', self._cipher_info[self.remote_cipher]['key-size']) +1804 engine = self._get_cipher(self.remote_cipher, key_in, IV_in) +1805 mac_size = self._mac_info[self.remote_mac]['size'] +1806 mac_engine = self._mac_info[self.remote_mac]['class'] +1807 # initial mac keys are done in the hash's natural size (not the potentially truncated +1808 # transmission size) +1809 if self.server_mode: +1810 mac_key = self._compute_key('E', mac_engine.digest_size) +1811 else: +1812 mac_key = self._compute_key('F', mac_engine.digest_size) +1813 self.packetizer.set_inbound_cipher(engine, block_size, mac_engine, mac_size, mac_key) +1814 compress_in = self._compression_info[self.remote_compression][1] +1815 if (compress_in is not None) and ((self.remote_compression != 'zlib@openssh.com') or self.authenticated): +1816 self._log(DEBUG, 'Switching on inbound compression ...') -1818 self.packetizer.set_inbound_compressor(compress_in()) -
1819 -
1820 - def _activate_outbound(self): -
1821 "switch on newly negotiated encryption parameters for outbound traffic" -1822 m = Message() -1823 m.add_byte(chr(DEBUG, 'Switching on inbound compression ...') +1817 self.packetizer.set_inbound_compressor(compress_in()) +
1818 +
1819 - def _activate_outbound(self): +
1820 "switch on newly negotiated encryption parameters for outbound traffic" +1821 m = Message() +1822 m.add_byte(chr(MSG_NEWKEYS)) -1824 self._send_message(m) -1825 block_size = self._cipher_info[self.local_cipher]['block-size'] -1826 if self.server_mode: -1827 IV_out = self._compute_key('B', block_size) -1828 key_out = self._compute_key('D', self._cipher_info[self.local_cipher]['key-size']) -1829 else: -1830 IV_out = self._compute_key('A', block_size) -1831 key_out = self._compute_key('C', self._cipher_info[self.local_cipher]['key-size']) -1832 engine = self._get_cipher(self.local_cipher, key_out, IV_out) -1833 mac_size = self._mac_info[self.local_mac]['size'] -1834 mac_engine = self._mac_info[self.local_mac]['class'] -1835 # initial mac keys are done in the hash's natural size (not the potentially truncated -1836 # transmission size) -1837 if self.server_mode: -1838 mac_key = self._compute_key('F', mac_engine.digest_size) -1839 else: -1840 mac_key = self._compute_key('E', mac_engine.digest_size) -1841 self.packetizer.set_outbound_cipher(engine, block_size, mac_engine, mac_size, mac_key) -1842 compress_out = self._compression_info[self.local_compression][0] -1843 if (compress_out is not None) and ((self.local_compression != 'zlib@openssh.com') or self.authenticated): -1844 self._log(MSG_NEWKEYS)) +1823 self._send_message(m) +1824 block_size = self._cipher_info[self.local_cipher]['block-size'] +1825 if self.server_mode: +1826 IV_out = self._compute_key('B', block_size) +1827 key_out = self._compute_key('D', self._cipher_info[self.local_cipher]['key-size']) +1828 else: +1829 IV_out = self._compute_key('A', block_size) +1830 key_out = self._compute_key('C', self._cipher_info[self.local_cipher]['key-size']) +1831 engine = self._get_cipher(self.local_cipher, key_out, IV_out) +1832 mac_size = self._mac_info[self.local_mac]['size'] +1833 mac_engine = self._mac_info[self.local_mac]['class'] +1834 # initial mac keys are done in the hash's natural size (not the potentially truncated +1835 # transmission size) +1836 if self.server_mode: +1837 mac_key = self._compute_key('F', mac_engine.digest_size) +1838 else: +1839 mac_key = self._compute_key('E', mac_engine.digest_size) +1840 self.packetizer.set_outbound_cipher(engine, block_size, mac_engine, mac_size, mac_key) +1841 compress_out = self._compression_info[self.local_compression][0] +1842 if (compress_out is not None) and ((self.local_compression != 'zlib@openssh.com') or self.authenticated): +1843 self._log(DEBUG, 'Switching on outbound compression ...') -1845 self.packetizer.set_outbound_compressor(compress_out()) -1846 if not self.packetizer.need_rekey(): -1847 self.in_kex = False -1848 # we always expect to receive NEWKEYS now -1849 self._expect_packet(DEBUG, 'Switching on outbound compression ...') +1844 self.packetizer.set_outbound_compressor(compress_out()) +1845 if not self.packetizer.need_rekey(): +1846 self.in_kex = False +1847 # we always expect to receive NEWKEYS now +1848 self._expect_packet(MSG_NEWKEYS) -
1850 -
1851 - def _auth_trigger(self): -
1852 self.authenticated = True -1853 # delayed initiation of compression -1854 if self.local_compression == 'zlib@openssh.com': -1855 compress_out = self._compression_info[self.local_compression][0] -1856 self._log(MSG_NEWKEYS) +
1849 +
1850 - def _auth_trigger(self): +
1851 self.authenticated = True +1852 # delayed initiation of compression +1853 if self.local_compression == 'zlib@openssh.com': +1854 compress_out = self._compression_info[self.local_compression][0] +1855 self._log(DEBUG, 'Switching on outbound compression ...') -1857 self.packetizer.set_outbound_compressor(compress_out()) -1858 if self.remote_compression == 'zlib@openssh.com': -1859 compress_in = self._compression_info[self.remote_compression][1] -1860 self._log(DEBUG, 'Switching on outbound compression ...') +1856 self.packetizer.set_outbound_compressor(compress_out()) +1857 if self.remote_compression == 'zlib@openssh.com': +1858 compress_in = self._compression_info[self.remote_compression][1] +1859 self._log(DEBUG, 'Switching on inbound compression ...') -1861 self.packetizer.set_inbound_compressor(compress_in()) -
1862 -
1863 - def _parse_newkeys(self, m): -
1864 self._log(DEBUG, 'Switching on inbound compression ...') +1860 self.packetizer.set_inbound_compressor(compress_in()) +
1861 +
1862 - def _parse_newkeys(self, m): +
1863 self._log(DEBUG, 'Switch to new keys ...') -1865 self._activate_inbound() -1866 # can also free a bunch of stuff here -1867 self.local_kex_init = self.remote_kex_init = None -1868 self.K = None -1869 self.kex_engine = None -1870 if self.server_mode and (self.auth_handler is None): -1871 # create auth handler for server mode -1872 self.auth_handler = AuthHandler(self) -1873 if not self.initial_kex_done: -1874 # this was the first key exchange -1875 self.initial_kex_done = True -1876 # send an event? -1877 if self.completion_event != None: -1878 self.completion_event.DEBUG, 'Switch to new keys ...') +1864 self._activate_inbound() +1865 # can also free a bunch of stuff here +1866 self.local_kex_init = self.remote_kex_init = None +1867 self.K = None +1868 self.kex_engine = None +1869 if self.server_mode and (self.auth_handler is None): +1870 # create auth handler for server mode +1871 self.auth_handler = AuthHandler(self) +1872 if not self.initial_kex_done: +1873 # this was the first key exchange +1874 self.initial_kex_done = True +1875 # send an event? +1876 if self.completion_event != None: +1877 self.completion_event.set() -1879 # it's now okay to send data again (if this was a re-key) -1880 if not self.packetizer.need_rekey(): -1881 self.in_kex = False -1882 self.clear_to_send_lock.acquire() -1883 try: -1884 self.clear_to_send.set() +1878 # it's now okay to send data again (if this was a re-key) +1879 if not self.packetizer.need_rekey(): +1880 self.in_kex = False +1881 self.clear_to_send_lock.acquire() +1882 try: +1883 self.clear_to_send.set() -1885 finally: -1886 self.clear_to_send_lock.release() -1887 return -
1888 -
1889 - def _parse_disconnect(self, m): -
1890 code = m.get_int() -1891 desc = m.get_string() -1892 self._log(set() +1884 finally: +1885 self.clear_to_send_lock.release() +1886 return +
1887 +
1888 - def _parse_disconnect(self, m): +
1889 code = m.get_int() +1890 desc = m.get_string() +1891 self._log(INFO, 'Disconnect (code %d): %s' % (code, desc)) -
1893 -
1894 - def _parse_global_request(self, m): -
1895 kind = m.get_string() -1896 self._log(INFO, 'Disconnect (code %d): %s' % (code, desc)) +
1892 +
1893 - def _parse_global_request(self, m): +
1894 kind = m.get_string() +1895 self._log(DEBUG, 'Received global request "%s"' % kind) -1897 want_reply = m.get_boolean() -1898 if not self.server_mode: -1899 self._log(DEBUG, 'Received global request "%s"' % kind) +1896 want_reply = m.get_boolean() +1897 if not self.server_mode: +1898 self._log(DEBUG, 'Rejecting "%s" global request from server.' % kind) -1900 ok = False -1901 elif kind == 'tcpip-forward': -1902 address = m.get_string() -1903 port = m.get_int() -1904 ok = self.server_object.check_port_forward_request(address, port) -1905 if ok != False: -1906 ok = (ok,) -1907 elif kind == 'cancel-tcpip-forward': -1908 address = m.get_string() -1909 port = m.get_int() -1910 self.server_object.cancel_port_forward_request(address, port) -1911 ok = True -1912 else: -1913 ok = self.server_object.check_global_request(kind, m) -1914 extra = () -1915 if type(ok) is tuple: -1916 extra = ok -1917 ok = True -1918 if want_reply: -1919 msg = Message() -1920 if ok: -1921 msg.add_byte(chr(DEBUG, 'Rejecting "%s" global request from server.' % kind) +1899 ok = False +1900 elif kind == 'tcpip-forward': +1901 address = m.get_string() +1902 port = m.get_int() +1903 ok = self.server_object.check_port_forward_request(address, port) +1904 if ok != False: +1905 ok = (ok,) +1906 elif kind == 'cancel-tcpip-forward': +1907 address = m.get_string() +1908 port = m.get_int() +1909 self.server_object.cancel_port_forward_request(address, port) +1910 ok = True +1911 else: +1912 ok = self.server_object.check_global_request(kind, m) +1913 extra = () +1914 if type(ok) is tuple: +1915 extra = ok +1916 ok = True +1917 if want_reply: +1918 msg = Message() +1919 if ok: +1920 msg.add_byte(chr(MSG_REQUEST_SUCCESS)) -1922 msg.add(*extra) -1923 else: -1924 msg.add_byte(chr(MSG_REQUEST_SUCCESS)) +1921 msg.add(*extra) +1922 else: +1923 msg.add_byte(chr(MSG_REQUEST_FAILURE)) -1925 self._send_message(msg) -
1926 -
1927 - def _parse_request_success(self, m): -
1928 self._log(MSG_REQUEST_FAILURE)) +1924 self._send_message(msg) +
1925 +
1926 - def _parse_request_success(self, m): +
1927 self._log(DEBUG, 'Global request successful.') -1929 self.global_response = m -1930 if self.completion_event is not None: -1931 self.completion_event.DEBUG, 'Global request successful.') +1928 self.global_response = m +1929 if self.completion_event is not None: +1930 self.completion_event.set() -
1932 -
1933 - def _parse_request_failure(self, m): -
1934 self._log(set() +
1931 +
1932 - def _parse_request_failure(self, m): +
1933 self._log(DEBUG, 'Global request denied.') -1935 self.global_response = None -1936 if self.completion_event is not None: -1937 self.completion_event.DEBUG, 'Global request denied.') +1934 self.global_response = None +1935 if self.completion_event is not None: +1936 self.completion_event.set() -
1938 -
1939 - def _parse_channel_open_success(self, m): -
1940 chanid = m.get_int() -1941 server_chanid = m.get_int() -1942 server_window_size = m.get_int() -1943 server_max_packet_size = m.get_int() -1944 chan = self._channels.get(chanid) -1945 if chan is None: -1946 self._log(set() +
1937 +
1938 - def _parse_channel_open_success(self, m): +
1939 chanid = m.get_int() +1940 server_chanid = m.get_int() +1941 server_window_size = m.get_int() +1942 server_max_packet_size = m.get_int() +1943 chan = self._channels.get(chanid) +1944 if chan is None: +1945 self._log(WARNING, 'Success for unrequested channel! [??]') -1947 return -1948 self.lock.acquire() -1949 try: -1950 chan._set_remote_channel(server_chanid, server_window_size, server_max_packet_size) -1951 self._log(WARNING, 'Success for unrequested channel! [??]') +1946 return +1947 self.lock.acquire() +1948 try: +1949 chan._set_remote_channel(server_chanid, server_window_size, server_max_packet_size) +1950 self._log(INFO, 'Secsh channel %d opened.' % chanid) -1952 if chanid in self.channel_events: -1953 self.channel_events[chanid].INFO, 'Secsh channel %d opened.' % chanid) +1951 if chanid in self.channel_events: +1952 self.channel_events[chanid].set() -1954 del self.channel_events[chanid] -1955 finally: -1956 self.lock.release() -1957 return -
1958 -
1959 - def _parse_channel_open_failure(self, m): -
1960 chanid = m.get_int() -1961 reason = m.get_int() -1962 reason_str = m.get_string() -1963 lang = m.get_string() -1964 reason_text = set() +1953 del self.channel_events[chanid] +1954 finally: +1955 self.lock.release() +1956 return +
1957 +
1958 - def _parse_channel_open_failure(self, m): +
1959 chanid = m.get_int() +1960 reason = m.get_int() +1961 reason_str = m.get_string() +1962 lang = m.get_string() +1963 reason_text = CONNECTION_FAILED_CODE.get(reason, '(unknown code)') -1965 self._log(CONNECTION_FAILED_CODE.get(reason, '(unknown code)') +1964 self._log(INFO, 'Secsh channel %d open FAILED: %s: %s' % (chanid, reason_str, reason_text)) -1966 self.lock.acquire() -1967 try: -1968 self.saved_exception = ChannelException(reason, reason_text) -1969 if chanid in self.channel_events: -1970 self._channels.delete(chanid) -1971 if chanid in self.channel_events: -1972 self.channel_events[chanid].INFO, 'Secsh channel %d open FAILED: %s: %s' % (chanid, reason_str, reason_text)) +1965 self.lock.acquire() +1966 try: +1967 self.saved_exception = ChannelException(reason, reason_text) +1968 if chanid in self.channel_events: +1969 self._channels.delete(chanid) +1970 if chanid in self.channel_events: +1971 self.channel_events[chanid].set() -1973 del self.channel_events[chanid] -1974 finally: -1975 self.lock.release() -1976 return -
1977 -
1978 - def _parse_channel_open(self, m): -
1979 kind = m.get_string() -1980 chanid = m.get_int() -1981 initial_window_size = m.get_int() -1982 max_packet_size = m.get_int() -1983 reject = False -1984 if (kind == 'x11') and (self._x11_handler is not None): -1985 origin_addr = m.get_string() -1986 origin_port = m.get_int() -1987 self._log(set() +1972 del self.channel_events[chanid] +1973 finally: +1974 self.lock.release() +1975 return +
1976 +
1977 - def _parse_channel_open(self, m): +
1978 kind = m.get_string() +1979 chanid = m.get_int() +1980 initial_window_size = m.get_int() +1981 max_packet_size = m.get_int() +1982 reject = False +1983 if (kind == 'x11') and (self._x11_handler is not None): +1984 origin_addr = m.get_string() +1985 origin_port = m.get_int() +1986 self._log(DEBUG, 'Incoming x11 connection from %s:%d' % (origin_addr, origin_port)) -1988 self.lock.acquire() -1989 try: -1990 my_chanid = self._next_channel() -1991 finally: -1992 self.lock.release() -1993 elif (kind == 'forwarded-tcpip') and (self._tcp_handler is not None): -1994 server_addr = m.get_string() -1995 server_port = m.get_int() -1996 origin_addr = m.get_string() -1997 origin_port = m.get_int() -1998 self._log(DEBUG, 'Incoming x11 connection from %s:%d' % (origin_addr, origin_port)) +1987 self.lock.acquire() +1988 try: +1989 my_chanid = self._next_channel() +1990 finally: +1991 self.lock.release() +1992 elif (kind == 'forwarded-tcpip') and (self._tcp_handler is not None): +1993 server_addr = m.get_string() +1994 server_port = m.get_int() +1995 origin_addr = m.get_string() +1996 origin_port = m.get_int() +1997 self._log(DEBUG, 'Incoming tcp forwarded connection from %s:%d' % (origin_addr, origin_port)) -1999 self.lock.acquire() -2000 try: -2001 my_chanid = self._next_channel() -2002 finally: -2003 self.lock.release() -2004 elif not self.server_mode: -2005 self._log(DEBUG, 'Incoming tcp forwarded connection from %s:%d' % (origin_addr, origin_port)) +1998 self.lock.acquire() +1999 try: +2000 my_chanid = self._next_channel() +2001 finally: +2002 self.lock.release() +2003 elif not self.server_mode: +2004 self._log(DEBUG, 'Rejecting "%s" channel request from server.' % kind) -2006 reject = True -2007 reason = DEBUG, 'Rejecting "%s" channel request from server.' % kind) +2005 reject = True +2006 reason = OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED -2008 else: -2009 self.lock.acquire() -2010 try: -2011 my_chanid = self._next_channel() -2012 finally: -2013 self.lock.release() -2014 if kind == 'direct-tcpip': -2015 # handle direct-tcpip requests comming from the client -2016 dest_addr = m.get_string() -2017 dest_port = m.get_int() -2018 origin_addr = m.get_string() -2019 origin_port = m.get_int() -2020 reason = self.server_object.check_channel_direct_tcpip_request( -2021 my_chanid, (origin_addr, origin_port), -2022 (dest_addr, dest_port)) -2023 else: -2024 reason = self.server_object.check_channel_request(kind, my_chanid) -2025 if reason != OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED +2007 else: +2008 self.lock.acquire() +2009 try: +2010 my_chanid = self._next_channel() +2011 finally: +2012 self.lock.release() +2013 if kind == 'direct-tcpip': +2014 # handle direct-tcpip requests comming from the client +2015 dest_addr = m.get_string() +2016 dest_port = m.get_int() +2017 origin_addr = m.get_string() +2018 origin_port = m.get_int() +2019 reason = self.server_object.check_channel_direct_tcpip_request( +2020 my_chanid, (origin_addr, origin_port), +2021 (dest_addr, dest_port)) +2022 else: +2023 reason = self.server_object.check_channel_request(kind, my_chanid) +2024 if reason != OPEN_SUCCEEDED: -2026 self._log(OPEN_SUCCEEDED: +2025 self._log(DEBUG, 'Rejecting "%s" channel request from client.' % kind) -2027 reject = True -2028 if reject: -2029 msg = Message() -2030 msg.add_byte(chr(DEBUG, 'Rejecting "%s" channel request from client.' % kind) +2026 reject = True +2027 if reject: +2028 msg = Message() +2029 msg.add_byte(chr(MSG_CHANNEL_OPEN_FAILURE)) -2031 msg.add_int(chanid) -2032 msg.add_int(reason) -2033 msg.add_string('') -2034 msg.add_string('en') -2035 self._send_message(msg) -2036 return -2037 -2038 chan = Channel(my_chanid) -2039 self.lock.acquire() -2040 try: -2041 self._channels.put(my_chanid, chan) -2042 self.channels_seen[my_chanid] = True -2043 chan._set_transport(self) -2044 chan._set_window(self.window_size, self.max_packet_size) -2045 chan._set_remote_channel(chanid, initial_window_size, max_packet_size) -2046 finally: -2047 self.lock.release() -2048 m = Message() -2049 m.add_byte(chr(MSG_CHANNEL_OPEN_FAILURE)) +2030 msg.add_int(chanid) +2031 msg.add_int(reason) +2032 msg.add_string('') +2033 msg.add_string('en') +2034 self._send_message(msg) +2035 return +2036 +2037 chan = Channel(my_chanid) +2038 self.lock.acquire() +2039 try: +2040 self._channels.put(my_chanid, chan) +2041 self.channels_seen[my_chanid] = True +2042 chan._set_transport(self) +2043 chan._set_window(self.window_size, self.max_packet_size) +2044 chan._set_remote_channel(chanid, initial_window_size, max_packet_size) +2045 finally: +2046 self.lock.release() +2047 m = Message() +2048 m.add_byte(chr(MSG_CHANNEL_OPEN_SUCCESS)) -2050 m.add_int(chanid) -2051 m.add_int(my_chanid) -2052 m.add_int(self.window_size) -2053 m.add_int(self.max_packet_size) -2054 self._send_message(m) -2055 self._log(MSG_CHANNEL_OPEN_SUCCESS)) +2049 m.add_int(chanid) +2050 m.add_int(my_chanid) +2051 m.add_int(self.window_size) +2052 m.add_int(self.max_packet_size) +2053 self._send_message(m) +2054 self._log(INFO, 'Secsh channel %d (%s) opened.', my_chanid, kind) -2056 if kind == 'x11': -2057 self._x11_handler(chan, (origin_addr, origin_port)) -2058 elif kind == 'forwarded-tcpip': -2059 chan.origin_addr = (origin_addr, origin_port) -2060 self._tcp_handler(chan, (origin_addr, origin_port), (server_addr, server_port)) -2061 else: -2062 self._queue_incoming_channel(chan) -
2063 -
2064 - def _parse_debug(self, m): -
2065 always_display = m.get_boolean() -2066 msg = m.get_string() -2067 lang = m.get_string() -2068 self._log(INFO, 'Secsh channel %d (%s) opened.', my_chanid, kind) +2055 if kind == 'x11': +2056 self._x11_handler(chan, (origin_addr, origin_port)) +2057 elif kind == 'forwarded-tcpip': +2058 chan.origin_addr = (origin_addr, origin_port) +2059 self._tcp_handler(chan, (origin_addr, origin_port), (server_addr, server_port)) +2060 else: +2061 self._queue_incoming_channel(chan) +
2062 +
2063 - def _parse_debug(self, m): +
2064 always_display = m.get_boolean() +2065 msg = m.get_string() +2066 lang = m.get_string() +2067 self._log(DEBUG, 'Debug msg: ' + util.safe_string(msg)) -
2069 -
2070 - def _get_subsystem_handler(self, name): -
2071 try: -2072 self.lock.acquire() -2073 if name not in self.subsystem_table: -2074 return (None, [], {}) -2075 return self.subsystem_table[name] -2076 finally: -2077 self.lock.release() -
2078 -2079 _handler_table = { -2080 DEBUG, 'Debug msg: ' + util.safe_string(msg)) +
2068 +
2069 - def _get_subsystem_handler(self, name): +
2070 try: +2071 self.lock.acquire() +2072 if name not in self.subsystem_table: +2073 return (None, [], {}) +2074 return self.subsystem_table[name] +2075 finally: +2076 self.lock.release() +
2077 +2078 _handler_table = { +2079 MSG_NEWKEYS: _parse_newkeys, -2081 MSG_NEWKEYS: _parse_newkeys, +2080 MSG_GLOBAL_REQUEST: _parse_global_request, -2082 MSG_GLOBAL_REQUEST: _parse_global_request, +2081 MSG_REQUEST_SUCCESS: _parse_request_success, -2083 MSG_REQUEST_SUCCESS: _parse_request_success, +2082 MSG_REQUEST_FAILURE: _parse_request_failure, -2084 MSG_REQUEST_FAILURE: _parse_request_failure, +2083 MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success, -2085 MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success, +2084 MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure, -2086 MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure, +2085 MSG_CHANNEL_OPEN: _parse_channel_open, -2087 MSG_CHANNEL_OPEN: _parse_channel_open, +2086 MSG_KEXINIT: _negotiate_keys, -2088 } -2089 -2090 _channel_handler_table = { -2091 MSG_KEXINIT: _negotiate_keys, +2087 } +2088 +2089 _channel_handler_table = { +2090 MSG_CHANNEL_SUCCESS: Channel._request_success, -2092 MSG_CHANNEL_SUCCESS: Channel._request_success, +2091 MSG_CHANNEL_FAILURE: Channel._request_failed, -2093 MSG_CHANNEL_FAILURE: Channel._request_failed, +2092 MSG_CHANNEL_DATA: Channel._feed, -2094 MSG_CHANNEL_DATA: Channel._feed, +2093 MSG_CHANNEL_EXTENDED_DATA: Channel._feed_extended, -2095 MSG_CHANNEL_EXTENDED_DATA: Channel._feed_extended, +2094 MSG_CHANNEL_WINDOW_ADJUST: Channel._window_adjust, -2096 MSG_CHANNEL_WINDOW_ADJUST: Channel._window_adjust, +2095 MSG_CHANNEL_REQUEST: Channel._handle_request, -2097 MSG_CHANNEL_REQUEST: Channel._handle_request, +2096 MSG_CHANNEL_EOF: Channel._handle_eof, -2098 MSG_CHANNEL_EOF: Channel._handle_eof, +2097 MSG_CHANNEL_CLOSE: Channel._handle_close, -2099 } -2100