Coverage for /pythoncovmergedfiles/medio/medio/src/paramiko/paramiko/server.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

98 statements  

1# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com> 

2# 

3# This file is part of paramiko. 

4# 

5# Paramiko is free software; you can redistribute it and/or modify it under the 

6# terms of the GNU Lesser General Public License as published by the Free 

7# Software Foundation; either version 2.1 of the License, or (at your option) 

8# any later version. 

9# 

10# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY 

11# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 

12# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 

13# details. 

14# 

15# You should have received a copy of the GNU Lesser General Public License 

16# along with Paramiko; if not, write to the Free Software Foundation, Inc., 

17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 

18 

19""" 

20`.ServerInterface` is an interface to override for server support. 

21""" 

22 

23import threading 

24from paramiko import util 

25from paramiko.common import ( 

26 DEBUG, 

27 ERROR, 

28 OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED, 

29 AUTH_FAILED, 

30 AUTH_SUCCESSFUL, 

31) 

32 

33 

34class ServerInterface: 

35 """ 

36 This class defines an interface for controlling the behavior of Paramiko 

37 in server mode. 

38 

39 Methods on this class are called from Paramiko's primary thread, so you 

40 shouldn't do too much work in them. (Certainly nothing that blocks or 

41 sleeps.) 

42 """ 

43 

44 def check_channel_request(self, kind, chanid): 

45 """ 

46 Determine if a channel request of a given type will be granted, and 

47 return ``OPEN_SUCCEEDED`` or an error code. This method is 

48 called in server mode when the client requests a channel, after 

49 authentication is complete. 

50 

51 If you allow channel requests (and an ssh server that didn't would be 

52 useless), you should also override some of the channel request methods 

53 below, which are used to determine which services will be allowed on 

54 a given channel: 

55 

56 - `check_channel_pty_request` 

57 - `check_channel_shell_request` 

58 - `check_channel_subsystem_request` 

59 - `check_channel_window_change_request` 

60 - `check_channel_x11_request` 

61 - `check_channel_forward_agent_request` 

62 

63 The ``chanid`` parameter is a small number that uniquely identifies the 

64 channel within a `.Transport`. A `.Channel` object is not created 

65 unless this method returns ``OPEN_SUCCEEDED`` -- once a 

66 `.Channel` object is created, you can call `.Channel.get_id` to 

67 retrieve the channel ID. 

68 

69 The return value should either be ``OPEN_SUCCEEDED`` (or 

70 ``0``) to allow the channel request, or one of the following error 

71 codes to reject it: 

72 

73 - ``OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED`` 

74 - ``OPEN_FAILED_CONNECT_FAILED`` 

75 - ``OPEN_FAILED_UNKNOWN_CHANNEL_TYPE`` 

76 - ``OPEN_FAILED_RESOURCE_SHORTAGE`` 

77 

78 The default implementation always returns 

79 ``OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED``. 

80 

81 :param str kind: 

82 the kind of channel the client would like to open (usually 

83 ``"session"``). 

84 :param int chanid: ID of the channel 

85 :return: an `int` success or failure code (listed above) 

86 """ 

87 return OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED 

88 

89 def get_allowed_auths(self, username): 

90 """ 

91 Return a list of authentication methods supported by the server. 

92 This list is sent to clients attempting to authenticate, to inform them 

93 of authentication methods that might be successful. 

94 

95 The "list" is actually a string of comma-separated names of types of 

96 authentication. Possible values are ``"password"``, ``"publickey"``, 

97 and ``"none"``. 

98 

99 The default implementation always returns ``"password"``. 

100 

101 :param str username: the username requesting authentication. 

102 :return: a comma-separated `str` of authentication types 

103 """ 

104 return "password" 

105 

106 def check_auth_none(self, username): 

107 """ 

108 Determine if a client may open channels with no (further) 

109 authentication. 

110 

111 Return ``AUTH_FAILED`` if the client must authenticate, or 

112 ``AUTH_SUCCESSFUL`` if it's okay for the client to not 

113 authenticate. 

114 

115 The default implementation always returns ``AUTH_FAILED``. 

116 

117 :param str username: the username of the client. 

118 :return: 

119 ``AUTH_FAILED`` if the authentication fails; ``AUTH_SUCCESSFUL`` if 

120 it succeeds. 

121 :rtype: int 

122 """ 

123 return AUTH_FAILED 

124 

125 def check_auth_password(self, username, password): 

126 """ 

127 Determine if a given username and password supplied by the client is 

128 acceptable for use in authentication. 

129 

130 Return ``AUTH_FAILED`` if the password is not accepted, 

131 ``AUTH_SUCCESSFUL`` if the password is accepted and completes 

132 the authentication, or ``AUTH_PARTIALLY_SUCCESSFUL`` if your 

133 authentication is stateful, and this key is accepted for 

134 authentication, but more authentication is required. (In this latter 

135 case, `get_allowed_auths` will be called to report to the client what 

136 options it has for continuing the authentication.) 

137 

138 The default implementation always returns ``AUTH_FAILED``. 

139 

140 :param str username: the username of the authenticating client. 

141 :param str password: the password given by the client. 

142 :return: 

143 ``AUTH_FAILED`` if the authentication fails; ``AUTH_SUCCESSFUL`` if 

144 it succeeds; ``AUTH_PARTIALLY_SUCCESSFUL`` if the password auth is 

145 successful, but authentication must continue. 

146 :rtype: int 

147 """ 

148 return AUTH_FAILED 

149 

150 def check_auth_publickey(self, username, key): 

151 """ 

152 Determine if a given key supplied by the client is acceptable for use 

153 in authentication. You should override this method in server mode to 

154 check the username and key and decide if you would accept a signature 

155 made using this key. 

156 

157 Return ``AUTH_FAILED`` if the key is not accepted, 

158 ``AUTH_SUCCESSFUL`` if the key is accepted and completes the 

159 authentication, or ``AUTH_PARTIALLY_SUCCESSFUL`` if your 

160 authentication is stateful, and this password is accepted for 

161 authentication, but more authentication is required. (In this latter 

162 case, `get_allowed_auths` will be called to report to the client what 

163 options it has for continuing the authentication.) 

164 

165 Note that you don't have to actually verify any key signtature here. 

166 If you're willing to accept the key, Paramiko will do the work of 

167 verifying the client's signature. 

168 

169 The default implementation always returns ``AUTH_FAILED``. 

170 

171 :param str username: the username of the authenticating client 

172 :param .PKey key: the key object provided by the client 

173 :return: 

174 ``AUTH_FAILED`` if the client can't authenticate with this key; 

175 ``AUTH_SUCCESSFUL`` if it can; ``AUTH_PARTIALLY_SUCCESSFUL`` if it 

176 can authenticate with this key but must continue with 

177 authentication 

178 :rtype: int 

179 """ 

180 return AUTH_FAILED 

181 

182 def check_auth_interactive(self, username, submethods): 

183 """ 

184 Begin an interactive authentication challenge, if supported. You 

185 should override this method in server mode if you want to support the 

186 ``"keyboard-interactive"`` auth type, which requires you to send a 

187 series of questions for the client to answer. 

188 

189 Return ``AUTH_FAILED`` if this auth method isn't supported. Otherwise, 

190 you should return an `.InteractiveQuery` object containing the prompts 

191 and instructions for the user. The response will be sent via a call 

192 to `check_auth_interactive_response`. 

193 

194 The default implementation always returns ``AUTH_FAILED``. 

195 

196 :param str username: the username of the authenticating client 

197 :param str submethods: 

198 a comma-separated list of methods preferred by the client (usually 

199 empty) 

200 :return: 

201 ``AUTH_FAILED`` if this auth method isn't supported; otherwise an 

202 object containing queries for the user 

203 :rtype: int or `.InteractiveQuery` 

204 """ 

205 return AUTH_FAILED 

206 

207 def check_auth_interactive_response(self, responses): 

208 """ 

209 Continue or finish an interactive authentication challenge, if 

210 supported. You should override this method in server mode if you want 

211 to support the ``"keyboard-interactive"`` auth type. 

212 

213 Return ``AUTH_FAILED`` if the responses are not accepted, 

214 ``AUTH_SUCCESSFUL`` if the responses are accepted and complete 

215 the authentication, or ``AUTH_PARTIALLY_SUCCESSFUL`` if your 

216 authentication is stateful, and this set of responses is accepted for 

217 authentication, but more authentication is required. (In this latter 

218 case, `get_allowed_auths` will be called to report to the client what 

219 options it has for continuing the authentication.) 

220 

221 If you wish to continue interactive authentication with more questions, 

222 you may return an `.InteractiveQuery` object, which should cause the 

223 client to respond with more answers, calling this method again. This 

224 cycle can continue indefinitely. 

225 

226 The default implementation always returns ``AUTH_FAILED``. 

227 

228 :param responses: list of `str` responses from the client 

229 :return: 

230 ``AUTH_FAILED`` if the authentication fails; ``AUTH_SUCCESSFUL`` if 

231 it succeeds; ``AUTH_PARTIALLY_SUCCESSFUL`` if the interactive auth 

232 is successful, but authentication must continue; otherwise an 

233 object containing queries for the user 

234 :rtype: int or `.InteractiveQuery` 

235 """ 

236 return AUTH_FAILED 

237 

238 def check_auth_gssapi_with_mic( 

239 self, username, gss_authenticated=AUTH_FAILED, cc_file=None 

240 ): 

241 """ 

242 Authenticate the given user to the server if he is a valid krb5 

243 principal. 

244 

245 :param str username: The username of the authenticating client 

246 :param int gss_authenticated: The result of the krb5 authentication 

247 :param str cc_filename: The krb5 client credentials cache filename 

248 :return: ``AUTH_FAILED`` if the user is not authenticated otherwise 

249 ``AUTH_SUCCESSFUL`` 

250 :rtype: int 

251 :note: Kerberos credential delegation is not supported. 

252 :see: `.ssh_gss` 

253 :note: : We are just checking in L{AuthHandler} that the given user is 

254 a valid krb5 principal! 

255 We don't check if the krb5 principal is allowed to log in on 

256 the server, because there is no way to do that in python. So 

257 if you develop your own SSH server with paramiko for a certain 

258 platform like Linux, you should call C{krb5_kuserok()} in 

259 your local kerberos library to make sure that the 

260 krb5_principal has an account on the server and is allowed to 

261 log in as a user. 

262 :see: http://www.unix.com/man-page/all/3/krb5_kuserok/ 

263 """ 

264 if gss_authenticated == AUTH_SUCCESSFUL: 

265 return AUTH_SUCCESSFUL 

266 return AUTH_FAILED 

267 

268 def check_auth_gssapi_keyex( 

269 self, username, gss_authenticated=AUTH_FAILED, cc_file=None 

270 ): 

271 """ 

272 Authenticate the given user to the server if he is a valid krb5 

273 principal and GSS-API Key Exchange was performed. 

274 If GSS-API Key Exchange was not performed, this authentication method 

275 won't be available. 

276 

277 :param str username: The username of the authenticating client 

278 :param int gss_authenticated: The result of the krb5 authentication 

279 :param str cc_filename: The krb5 client credentials cache filename 

280 :return: ``AUTH_FAILED`` if the user is not authenticated otherwise 

281 ``AUTH_SUCCESSFUL`` 

282 :rtype: int 

283 :note: Kerberos credential delegation is not supported. 

284 :see: `.ssh_gss` `.kex_gss` 

285 :note: : We are just checking in L{AuthHandler} that the given user is 

286 a valid krb5 principal! 

287 We don't check if the krb5 principal is allowed to log in on 

288 the server, because there is no way to do that in python. So 

289 if you develop your own SSH server with paramiko for a certain 

290 platform like Linux, you should call C{krb5_kuserok()} in 

291 your local kerberos library to make sure that the 

292 krb5_principal has an account on the server and is allowed 

293 to log in as a user. 

294 :see: http://www.unix.com/man-page/all/3/krb5_kuserok/ 

295 """ 

296 if gss_authenticated == AUTH_SUCCESSFUL: 

297 return AUTH_SUCCESSFUL 

298 return AUTH_FAILED 

299 

300 def enable_auth_gssapi(self): 

301 """ 

302 Overwrite this function in your SSH server to enable GSSAPI 

303 authentication. 

304 The default implementation always returns false. 

305 

306 :returns bool: Whether GSSAPI authentication is enabled. 

307 :see: `.ssh_gss` 

308 """ 

309 UseGSSAPI = False 

310 return UseGSSAPI 

311 

312 def check_port_forward_request(self, address, port): 

313 """ 

314 Handle a request for port forwarding. The client is asking that 

315 connections to the given address and port be forwarded back across 

316 this ssh connection. An address of ``"0.0.0.0"`` indicates a global 

317 address (any address associated with this server) and a port of ``0`` 

318 indicates that no specific port is requested (usually the OS will pick 

319 a port). 

320 

321 The default implementation always returns ``False``, rejecting the 

322 port forwarding request. If the request is accepted, you should return 

323 the port opened for listening. 

324 

325 :param str address: the requested address 

326 :param int port: the requested port 

327 :return: 

328 the port number (`int`) that was opened for listening, or ``False`` 

329 to reject 

330 """ 

331 return False 

332 

333 def cancel_port_forward_request(self, address, port): 

334 """ 

335 The client would like to cancel a previous port-forwarding request. 

336 If the given address and port is being forwarded across this ssh 

337 connection, the port should be closed. 

338 

339 :param str address: the forwarded address 

340 :param int port: the forwarded port 

341 """ 

342 pass 

343 

344 def check_global_request(self, kind, msg): 

345 """ 

346 Handle a global request of the given ``kind``. This method is called 

347 in server mode and client mode, whenever the remote host makes a global 

348 request. If there are any arguments to the request, they will be in 

349 ``msg``. 

350 

351 There aren't any useful global requests defined, aside from port 

352 forwarding, so usually this type of request is an extension to the 

353 protocol. 

354 

355 If the request was successful and you would like to return contextual 

356 data to the remote host, return a tuple. Items in the tuple will be 

357 sent back with the successful result. (Note that the items in the 

358 tuple can only be strings, ints, or bools.) 

359 

360 The default implementation always returns ``False``, indicating that it 

361 does not support any global requests. 

362 

363 .. note:: Port forwarding requests are handled separately, in 

364 `check_port_forward_request`. 

365 

366 :param str kind: the kind of global request being made. 

367 :param .Message msg: any extra arguments to the request. 

368 :return: 

369 ``True`` or a `tuple` of data if the request was granted; ``False`` 

370 otherwise. 

371 """ 

372 return False 

373 

374 # ...Channel requests... 

375 

376 def check_channel_pty_request( 

377 self, channel, term, width, height, pixelwidth, pixelheight, modes 

378 ): 

379 """ 

380 Determine if a pseudo-terminal of the given dimensions (usually 

381 requested for shell access) can be provided on the given channel. 

382 

383 The default implementation always returns ``False``. 

384 

385 :param .Channel channel: the `.Channel` the pty request arrived on. 

386 :param str term: type of terminal requested (for example, ``"vt100"``). 

387 :param int width: width of screen in characters. 

388 :param int height: height of screen in characters. 

389 :param int pixelwidth: 

390 width of screen in pixels, if known (may be ``0`` if unknown). 

391 :param int pixelheight: 

392 height of screen in pixels, if known (may be ``0`` if unknown). 

393 :return: 

394 ``True`` if the pseudo-terminal has been allocated; ``False`` 

395 otherwise. 

396 """ 

397 return False 

398 

399 def check_channel_shell_request(self, channel): 

400 """ 

401 Determine if a shell will be provided to the client on the given 

402 channel. If this method returns ``True``, the channel should be 

403 connected to the stdin/stdout of a shell (or something that acts like 

404 a shell). 

405 

406 The default implementation always returns ``False``. 

407 

408 :param .Channel channel: the `.Channel` the request arrived on. 

409 :return: 

410 ``True`` if this channel is now hooked up to a shell; ``False`` if 

411 a shell can't or won't be provided. 

412 """ 

413 return False 

414 

415 def check_channel_exec_request(self, channel, command): 

416 """ 

417 Determine if a shell command will be executed for the client. If this 

418 method returns ``True``, the channel should be connected to the stdin, 

419 stdout, and stderr of the shell command. 

420 

421 The default implementation always returns ``False``. 

422 

423 :param .Channel channel: the `.Channel` the request arrived on. 

424 :param str command: the command to execute. 

425 :return: 

426 ``True`` if this channel is now hooked up to the stdin, stdout, and 

427 stderr of the executing command; ``False`` if the command will not 

428 be executed. 

429 

430 .. versionadded:: 1.1 

431 """ 

432 return False 

433 

434 def check_channel_subsystem_request(self, channel, name): 

435 """ 

436 Determine if a requested subsystem will be provided to the client on 

437 the given channel. If this method returns ``True``, all future I/O 

438 through this channel will be assumed to be connected to the requested 

439 subsystem. An example of a subsystem is ``sftp``. 

440 

441 The default implementation checks for a subsystem handler assigned via 

442 `.Transport.set_subsystem_handler`. 

443 If one has been set, the handler is invoked and this method returns 

444 ``True``. Otherwise it returns ``False``. 

445 

446 .. note:: Because the default implementation uses the `.Transport` to 

447 identify valid subsystems, you probably won't need to override this 

448 method. 

449 

450 :param .Channel channel: the `.Channel` the pty request arrived on. 

451 :param str name: name of the requested subsystem. 

452 :return: 

453 ``True`` if this channel is now hooked up to the requested 

454 subsystem; ``False`` if that subsystem can't or won't be provided. 

455 """ 

456 transport = channel.get_transport() 

457 handler_class, args, kwargs = transport._get_subsystem_handler(name) 

458 if handler_class is None: 

459 return False 

460 handler = handler_class(channel, name, self, *args, **kwargs) 

461 handler.start() 

462 return True 

463 

464 def check_channel_window_change_request( 

465 self, channel, width, height, pixelwidth, pixelheight 

466 ): 

467 """ 

468 Determine if the pseudo-terminal on the given channel can be resized. 

469 This only makes sense if a pty was previously allocated on it. 

470 

471 The default implementation always returns ``False``. 

472 

473 :param .Channel channel: the `.Channel` the pty request arrived on. 

474 :param int width: width of screen in characters. 

475 :param int height: height of screen in characters. 

476 :param int pixelwidth: 

477 width of screen in pixels, if known (may be ``0`` if unknown). 

478 :param int pixelheight: 

479 height of screen in pixels, if known (may be ``0`` if unknown). 

480 :return: ``True`` if the terminal was resized; ``False`` if not. 

481 """ 

482 return False 

483 

484 def check_channel_x11_request( 

485 self, 

486 channel, 

487 single_connection, 

488 auth_protocol, 

489 auth_cookie, 

490 screen_number, 

491 ): 

492 """ 

493 Determine if the client will be provided with an X11 session. If this 

494 method returns ``True``, X11 applications should be routed through new 

495 SSH channels, using `.Transport.open_x11_channel`. 

496 

497 The default implementation always returns ``False``. 

498 

499 :param .Channel channel: the `.Channel` the X11 request arrived on 

500 :param bool single_connection: 

501 ``True`` if only a single X11 channel should be opened, else 

502 ``False``. 

503 :param str auth_protocol: the protocol used for X11 authentication 

504 :param str auth_cookie: the cookie used to authenticate to X11 

505 :param int screen_number: the number of the X11 screen to connect to 

506 :return: ``True`` if the X11 session was opened; ``False`` if not 

507 """ 

508 return False 

509 

510 def check_channel_forward_agent_request(self, channel): 

511 """ 

512 Determine if the client will be provided with an forward agent session. 

513 If this method returns ``True``, the server will allow SSH Agent 

514 forwarding. 

515 

516 The default implementation always returns ``False``. 

517 

518 :param .Channel channel: the `.Channel` the request arrived on 

519 :return: ``True`` if the AgentForward was loaded; ``False`` if not 

520 

521 If ``True`` is returned, the server should create an 

522 :class:`AgentServerProxy` to access the agent. 

523 """ 

524 return False 

525 

526 def check_channel_direct_tcpip_request(self, chanid, origin, destination): 

527 """ 

528 Determine if a local port forwarding channel will be granted, and 

529 return ``OPEN_SUCCEEDED`` or an error code. This method is 

530 called in server mode when the client requests a channel, after 

531 authentication is complete. 

532 

533 The ``chanid`` parameter is a small number that uniquely identifies the 

534 channel within a `.Transport`. A `.Channel` object is not created 

535 unless this method returns ``OPEN_SUCCEEDED`` -- once a 

536 `.Channel` object is created, you can call `.Channel.get_id` to 

537 retrieve the channel ID. 

538 

539 The origin and destination parameters are (ip_address, port) tuples 

540 that correspond to both ends of the TCP connection in the forwarding 

541 tunnel. 

542 

543 The return value should either be ``OPEN_SUCCEEDED`` (or 

544 ``0``) to allow the channel request, or one of the following error 

545 codes to reject it: 

546 

547 - ``OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED`` 

548 - ``OPEN_FAILED_CONNECT_FAILED`` 

549 - ``OPEN_FAILED_UNKNOWN_CHANNEL_TYPE`` 

550 - ``OPEN_FAILED_RESOURCE_SHORTAGE`` 

551 

552 The default implementation always returns 

553 ``OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED``. 

554 

555 :param int chanid: ID of the channel 

556 :param tuple origin: 

557 2-tuple containing the IP address and port of the originator 

558 (client side) 

559 :param tuple destination: 

560 2-tuple containing the IP address and port of the destination 

561 (server side) 

562 :return: an `int` success or failure code (listed above) 

563 """ 

564 return OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED 

565 

566 def check_channel_env_request(self, channel, name, value): 

567 """ 

568 Check whether a given environment variable can be specified for the 

569 given channel. This method should return ``True`` if the server 

570 is willing to set the specified environment variable. Note that 

571 some environment variables (e.g., PATH) can be exceedingly 

572 dangerous, so blindly allowing the client to set the environment 

573 is almost certainly not a good idea. 

574 

575 The default implementation always returns ``False``. 

576 

577 :param channel: the `.Channel` the env request arrived on 

578 :param str name: name 

579 :param str value: Channel value 

580 :returns: A boolean 

581 """ 

582 return False 

583 

584 def get_banner(self): 

585 """ 

586 A pre-login banner to display to the user. The message may span 

587 multiple lines separated by crlf pairs. The language should be in 

588 rfc3066 style, for example: en-US 

589 

590 The default implementation always returns ``(None, None)``. 

591 

592 :returns: A tuple containing the banner and language code. 

593 

594 .. versionadded:: 2.3 

595 """ 

596 return (None, None) 

597 

598 

599class InteractiveQuery: 

600 """ 

601 A query (set of prompts) for a user during interactive authentication. 

602 """ 

603 

604 def __init__(self, name="", instructions="", *prompts): 

605 """ 

606 Create a new interactive query to send to the client. The name and 

607 instructions are optional, but are generally displayed to the end 

608 user. A list of prompts may be included, or they may be added via 

609 the `add_prompt` method. 

610 

611 :param str name: name of this query 

612 :param str instructions: 

613 user instructions (usually short) about this query 

614 :param str prompts: one or more authentication prompts 

615 """ 

616 self.name = name 

617 self.instructions = instructions 

618 self.prompts = [] 

619 for x in prompts: 

620 if isinstance(x, str): 

621 self.add_prompt(x) 

622 else: 

623 self.add_prompt(x[0], x[1]) 

624 

625 def add_prompt(self, prompt, echo=True): 

626 """ 

627 Add a prompt to this query. The prompt should be a (reasonably short) 

628 string. Multiple prompts can be added to the same query. 

629 

630 :param str prompt: the user prompt 

631 :param bool echo: 

632 ``True`` (default) if the user's response should be echoed; 

633 ``False`` if not (for a password or similar) 

634 """ 

635 self.prompts.append((prompt, echo)) 

636 

637 

638class SubsystemHandler(threading.Thread): 

639 """ 

640 Handler for a subsystem in server mode. If you create a subclass of this 

641 class and pass it to `.Transport.set_subsystem_handler`, an object of this 

642 class will be created for each request for this subsystem. Each new object 

643 will be executed within its own new thread by calling `start_subsystem`. 

644 When that method completes, the channel is closed. 

645 

646 For example, if you made a subclass ``MP3Handler`` and registered it as the 

647 handler for subsystem ``"mp3"``, then whenever a client has successfully 

648 authenticated and requests subsystem ``"mp3"``, an object of class 

649 ``MP3Handler`` will be created, and `start_subsystem` will be called on 

650 it from a new thread. 

651 """ 

652 

653 def __init__(self, channel, name, server): 

654 """ 

655 Create a new handler for a channel. This is used by `.ServerInterface` 

656 to start up a new handler when a channel requests this subsystem. You 

657 don't need to override this method, but if you do, be sure to pass the 

658 ``channel`` and ``name`` parameters through to the original 

659 ``__init__`` method here. 

660 

661 :param .Channel channel: the channel associated with this 

662 subsystem request. 

663 :param str name: name of the requested subsystem. 

664 :param .ServerInterface server: 

665 the server object for the session that started this subsystem 

666 """ 

667 threading.Thread.__init__(self, target=self._run) 

668 self.__channel = channel 

669 self.__transport = channel.get_transport() 

670 self.__name = name 

671 self.__server = server 

672 

673 def get_server(self): 

674 """ 

675 Return the `.ServerInterface` object associated with this channel and 

676 subsystem. 

677 """ 

678 return self.__server 

679 

680 def _run(self): 

681 try: 

682 self.__transport._log( 

683 DEBUG, "Starting handler for subsystem {}".format(self.__name) 

684 ) 

685 self.start_subsystem(self.__name, self.__transport, self.__channel) 

686 except Exception as e: 

687 self.__transport._log( 

688 ERROR, 

689 'Exception in subsystem handler for "{}": {}'.format( 

690 self.__name, e 

691 ), 

692 ) 

693 self.__transport._log(ERROR, util.tb_strings()) 

694 try: 

695 self.finish_subsystem() 

696 except: 

697 pass 

698 

699 def start_subsystem(self, name, transport, channel): 

700 """ 

701 Process an ssh subsystem in server mode. This method is called on a 

702 new object (and in a new thread) for each subsystem request. It is 

703 assumed that all subsystem logic will take place here, and when the 

704 subsystem is finished, this method will return. After this method 

705 returns, the channel is closed. 

706 

707 The combination of ``transport`` and ``channel`` are unique; this 

708 handler corresponds to exactly one `.Channel` on one `.Transport`. 

709 

710 .. note:: 

711 It is the responsibility of this method to exit if the underlying 

712 `.Transport` is closed. This can be done by checking 

713 `.Transport.is_active` or noticing an EOF on the `.Channel`. If 

714 this method loops forever without checking for this case, your 

715 Python interpreter may refuse to exit because this thread will 

716 still be running. 

717 

718 :param str name: name of the requested subsystem. 

719 :param .Transport transport: the server-mode `.Transport`. 

720 :param .Channel channel: the channel associated with this subsystem 

721 request. 

722 """ 

723 pass 

724 

725 def finish_subsystem(self): 

726 """ 

727 Perform any cleanup at the end of a subsystem. The default 

728 implementation just closes the channel. 

729 

730 .. versionadded:: 1.1 

731 """ 

732 self.__channel.close()