1============= 2API reference 3============= 4 5.. contents:: Table of Contents 6 7pyftpdlib implements the server side of the FTP protocol as defined in 8`RFC-959 <http://www.faqs.org/rfcs/rfc959.html>`_. This document is intended to 9serve as a simple API reference of most important classes and functions. 10After reading this you will probably want to read the 11`tutorial <tutorial.html>`_ including customization through the use of some 12example scripts. 13 14Modules and classes hierarchy 15============================= 16 17:: 18 19 pyftpdlib.authorizers 20 pyftpdlib.authorizers.AuthenticationFailed 21 pyftpdlib.authorizers.DummyAuthorizer 22 pyftpdlib.authorizers.UnixAuthorizer 23 pyftpdlib.authorizers.WindowsAuthorizer 24 pyftpdlib.handlers 25 pyftpdlib.handlers.FTPHandler 26 pyftpdlib.handlers.TLS_FTPHandler 27 pyftpdlib.handlers.DTPHandler 28 pyftpdlib.handlers.TLS_DTPHandler 29 pyftpdlib.handlers.ThrottledDTPHandler 30 pyftpdlib.filesystems 31 pyftpdlib.filesystems.FilesystemError 32 pyftpdlib.filesystems.AbstractedFS 33 pyftpdlib.filesystems.UnixFilesystem 34 pyftpdlib.servers 35 pyftpdlib.servers.FTPServer 36 pyftpdlib.servers.ThreadedFTPServer 37 pyftpdlib.servers.MultiprocessFTPServer 38 pyftpdlib.ioloop 39 pyftpdlib.ioloop.IOLoop 40 pyftpdlib.ioloop.Connector 41 pyftpdlib.ioloop.Acceptor 42 pyftpdlib.ioloop.AsyncChat 43 44Users 45===== 46 47.. class:: pyftpdlib.authorizers.DummyAuthorizer() 48 49 Basic "dummy" authorizer class, suitable for subclassing to create your own 50 custom authorizers. An "authorizer" is a class handling authentications and 51 permissions of the FTP server. It is used inside 52 :class:`pyftpdlib.handlers.FTPHandler` class for verifying user's password, 53 getting users home directory, checking user permissions when a filesystem 54 read/write event occurs and changing user before accessing the filesystem. 55 DummyAuthorizer is the base authorizer, providing a platform independent 56 interface for managing "virtual" FTP users. Typically the first thing you 57 have to do is create an instance of this class and start adding ftp users: 58 59 >>> from pyftpdlib.authorizers import DummyAuthorizer 60 >>> authorizer = DummyAuthorizer() 61 >>> authorizer.add_user('user', 'password', '/home/user', perm='elradfmwMT') 62 >>> authorizer.add_anonymous('/home/nobody') 63 64 .. method:: add_user(username, password, homedir, perm="elr", msg_login="Login successful.", msg_quit="Goodbye.") 65 66 Add a user to the virtual users table. AuthorizerError exception is raised 67 on error conditions such as insufficient permissions or duplicate usernames. 68 Optional *perm* argument is a set of letters referencing the user's 69 permissions. Every letter is used to indicate that the access rights the 70 current FTP user has over the following specific actions are granted. The 71 available permissions are the following listed below: 72 73 Read permissions: 74 75 - ``"e"`` = change directory (CWD, CDUP commands) 76 - ``"l"`` = list files (LIST, NLST, STAT, MLSD, MLST, SIZE commands) 77 - ``"r"`` = retrieve file from the server (RETR command) 78 79 Write permissions: 80 81 - ``"a"`` = append data to an existing file (APPE command) 82 - ``"d"`` = delete file or directory (DELE, RMD commands) 83 - ``"f"`` = rename file or directory (RNFR, RNTO commands) 84 - ``"m"`` = create directory (MKD command) 85 - ``"w"`` = store a file to the server (STOR, STOU commands) 86 - ``"M"`` = change file mode / permission (SITE CHMOD command) *New in 0.7.0* 87 - ``"T"`` = change file modification time (SITE MFMT command) *New in 1.5.3* 88 89 Optional *msg_login* and *msg_quit* arguments can be specified to provide 90 customized response strings when user log-in and quit. The *perm* argument 91 of the :meth:`add_user()` method refers to user's permissions. Every letter 92 is used to indicate that the access rights the current FTP user has over 93 the following specific actions are granted. 94 95 .. method:: add_anonymous(homedir, **kwargs) 96 97 Add an anonymous user to the virtual users table. AuthorizerError exception 98 is raised on error conditions such as insufficient permissions, missing 99 home directory, or duplicate anonymous users. The keyword arguments in 100 kwargs are the same expected by :meth:`add_user()` method: *perm*, 101 *msg_login* and *msg_quit*. The optional perm keyword argument is a string 102 defaulting to "elr" referencing "read-only" anonymous user's permission. 103 Using a "write" value results in a RuntimeWarning. 104 105 .. method:: override_perm(username, directory, perm, recursive=False) 106 107 Override user permissions for a given directory. 108 109 .. method:: validate_authentication(username, password, handler) 110 111 Raises :class:`pyftpdlib.authorizers.AuthenticationFailed` if the supplied 112 username and password doesn't match the stored credentials. 113 114 *Changed in 1.0.0: new handler parameter.* 115 116 *Changed in 1.0.0: an exception is now raised for signaling a failed authenticaiton as opposed to returning a bool.* 117 118 .. method:: impersonate_user(username, password) 119 120 Impersonate another user (noop). It is always called before accessing the 121 filesystem. By default it does nothing. The subclass overriding this method 122 is expected to provide a mechanism to change the current user. 123 124 .. method:: terminate_impersonation(username) 125 126 Terminate impersonation (noop). It is always called after having accessed 127 the filesystem. By default it does nothing. The subclass overriding this 128 method is expected to provide a mechanism to switch back to the original 129 user. 130 131 .. method:: remove_user(username) 132 133 Remove a user from the virtual user table. 134 135Control connection 136================== 137 138.. class:: pyftpdlib.handlers.FTPHandler(conn, server) 139 140 This class implements the FTP server Protocol Interpreter (see 141 `RFC-959 <http://www.faqs.org/rfcs/rfc959.html>`_), handling commands received 142 from the client on the control channel by calling the command's corresponding 143 method (e.g. for received command "MKD pathname", ftp_MKD() method is called 144 with pathname as the argument). All relevant session information are stored 145 in instance variables. conn is the underlying socket object instance of the 146 newly established connection, server is the 147 :class:`pyftpdlib.servers.FTPServer` class instance. Basic usage simply 148 requires creating an instance of FTPHandler class and specify which 149 authorizer instance it will going to use: 150 151 >>> from pyftpdlib.handlers import FTPHandler 152 >>> handler = FTPHandler 153 >>> handler.authorizer = authorizer 154 155 All relevant session information is stored in class attributes reproduced 156 below and can be modified before instantiating this class: 157 158 .. data:: timeout 159 160 The timeout which is the maximum time a remote client may spend between FTP 161 commands. If the timeout triggers, the remote client will be kicked off 162 (defaults to ``300`` seconds). 163 164 *New in version 5.0* 165 166 .. data:: banner 167 168 String sent when client connects (default 169 ``"pyftpdlib %s ready." %__ver__``). 170 171 .. data:: max_login_attempts 172 173 Maximum number of wrong authentications before disconnecting (default 174 ``3``). 175 176 .. data:: permit_foreign_addresses 177 178 Whether enable FXP feature (default ``False``). 179 180 .. data:: permit_privileged_ports 181 182 Set to ``True`` if you want to permit active connections (PORT) over 183 privileged ports (not recommended, default ``False``). 184 185 .. data:: masquerade_address 186 187 The "masqueraded" IP address to provide along PASV reply when pyftpdlib is 188 running behind a NAT or other types of gateways. When configured pyftpdlib 189 will hide its local address and instead use the public address of your NAT 190 (default None). 191 192 .. data:: masquerade_address_map 193 194 In case the server has multiple IP addresses which are all behind a NAT 195 router, you may wish to specify individual masquerade_addresses for each of 196 them. The map expects a dictionary containing private IP addresses as keys, 197 and their corresponding public (masquerade) addresses as values (defaults 198 to ``{}``). *New in version 0.6.0* 199 200 .. data:: passive_ports 201 202 What ports ftpd will use for its passive data transfers. Value expected is 203 a list of integers (e.g. ``range(60000, 65535)``). When configured 204 pyftpdlib will no longer use kernel-assigned random ports (default 205 ``None``). 206 207 .. data:: use_gmt_times 208 209 When ``True`` causes the server to report all ls and MDTM times in GMT and 210 not local time (default ``True``). *New in version 0.6.0* 211 212 .. data:: tcp_no_delay 213 214 Controls the use of the TCP_NODELAY socket option which disables the Nagle 215 algorithm resulting in significantly better performances (default ``True`` 216 on all platforms where it is supported). *New in version 0.6.0* 217 218 .. data:: use_sendfile 219 220 When ``True`` uses sendfile(2) system call to send a file resulting in 221 faster uploads (from server to client). Works on UNIX only and requires 222 `pysendfile <https://github.com/giampaolo/pysendfile>`__ module to be 223 installed separately. 224 225 *New in version 0.7.0* 226 227 .. data:: auth_failed_timeout 228 229 The amount of time the server waits before sending a response in case of 230 failed authentication. 231 232 *New in version 1.5.0* 233 234 Follows a list of callback methods that can be overridden in a subclass. For 235 blocking operations read the FAQ on how to run time consuming tasks. 236 237 .. method:: on_connect() 238 239 Called when client connects. 240 241 *New in version 1.0.0* 242 243 .. method:: on_disconnect() 244 245 Called when connection is closed. 246 247 *New in version 1.0.0* 248 249 .. method:: on_login(username) 250 251 Called on user login. 252 253 *New in version 0.6.0* 254 255 .. method:: on_login_failed(username, password) 256 257 Called on failed user login. 258 259 *New in version 0.7.0* 260 261 .. method:: on_logout(username) 262 263 Called when user logs out due to QUIT or USER issued twice. This is not 264 called if client just disconnects without issuing QUIT first. 265 266 *New in version 0.6.0* 267 268 .. method:: on_file_sent(file) 269 270 Called every time a file has been successfully sent. *file* is the 271 absolute name of that file. 272 273 .. method:: on_file_received(file) 274 275 Called every time a file has been successfully received. *file* is the 276 absolute name of that file. 277 278 .. method:: on_incomplete_file_sent(file) 279 280 Called every time a file has not been entirely sent (e.g. transfer aborted 281 by client). *file* is the absolute name of that file. 282 283 *New in version 0.6.0* 284 285 .. method:: on_incomplete_file_received(file) 286 287 Called every time a file has not been entirely received (e.g. transfer 288 aborted by client). *file* is the absolute name of that file. *New in 289 version 0.6.0* 290 291Data connection 292=============== 293 294.. class:: pyftpdlib.handlers.DTPHandler(sock_obj, cmd_channel) 295 296 This class handles the server-data-transfer-process (server-DTP, see `RFC-959 297 <http://www.faqs.org/rfcs/rfc959.html>`_) managing all transfer operations 298 regarding the data channel. *sock_obj* is the underlying socket object 299 instance of the newly established connection, cmd_channel is the 300 :class:`pyftpdlib.handlers.FTPHandler` class instance. 301 302 *Changed in version 1.0.0: added ioloop argument.* 303 304 .. data:: timeout 305 306 The timeout which roughly is the maximum time we permit data transfers to 307 stall for with no progress. If the timeout triggers, the remote client will 308 be kicked off (default ``300`` seconds). 309 310 .. data:: ac_in_buffer_size 311 .. data:: ac_out_buffer_size 312 313 The buffer sizes to use when receiving and sending data (both defaulting to 314 ``65536`` bytes). For LANs you may want this to be fairly large. Depending 315 on available memory and number of connected clients setting them to a lower 316 value can result in better performances. 317 318 319.. class:: pyftpdlib.handlers.ThrottledDTPHandler(sock_obj, cmd_channel) 320 321 A :class:`pyftpdlib.handlers.DTPHandler` subclass which wraps sending and 322 receiving in a data counter and temporarily "sleeps" the channel so that you 323 burst to no more than x Kb/sec average. Use it instead of 324 :class:`pyftpdlib.handlers.DTPHandler` to set transfer rates limits for both 325 downloads and/or uploads (see the 326 `demo script <https://github.com/giampaolo/pyftpdlib/blob/master/demo/throttled_ftpd.py>`__ 327 showing the example usage). 328 329 .. data:: read_limit 330 331 The maximum number of bytes to read (receive) in one second (defaults to 332 ``0`` == no limit) 333 334 .. data:: write_limit 335 336 The maximum number of bytes to write (send) in one second (defaults to 337 ``0`` == no limit). 338 339Server (acceptor) 340================= 341 342.. class:: pyftpdlib.servers.FTPServer(address_or_socket, handler, ioloop=None, backlog=100) 343 344 Creates a socket listening on *address* (an ``(host, port)`` tuple) or a 345 pre- existing socket object, dispatching the requests to *handler* (typically 346 :class:`pyftpdlib.handlers.FTPHandler` class). Also, starts the asynchronous 347 IO loop. *backlog* is the maximum number of queued connections passed to 348 `socket.listen() <http://docs.python.org/library/socket.html#socket.socket.listen>`_. 349 If a connection request arrives when the queue is full the client may raise 350 ECONNRESET. 351 352 *Changed in version 1.0.0: added ioloop argument.* 353 354 *Changed in version 1.2.0: address can also be a pre-existing socket object.* 355 356 *Changed in version 1.2.0: Added backlog argument.* 357 358 *Changed in version 1.5.4: Support for the context manager protocol was 359 added. Exiting the context manager is equivalent to calling 360 :meth:`close_all`.* 361 362 >>> from pyftpdlib.servers import FTPServer 363 >>> address = ('127.0.0.1', 21) 364 >>> server = FTPServer(address, handler) 365 >>> server.serve_forever() 366 367 It can also be used as a context manager. Exiting the context manager is 368 equivalent to calling :meth:`close_all`. 369 370 >>> with FTPServer(address, handler) as server: 371 ... server.serve_forever() 372 373 .. data:: max_cons 374 375 Number of maximum simultaneous connections accepted (default ``512``). 376 377 .. data:: max_cons_per_ip 378 379 Number of maximum connections accepted for the same IP address (default 380 ``0`` == no limit). 381 382 .. method:: serve_forever(timeout=None, blocking=True, handle_exit=True, worker_processes=1) 383 384 Starts the asynchronous IO loop. 385 386 - (float) timeout: the timeout passed to the underlying IO 387 loop expressed in seconds. 388 389 - (bool) blocking: if False loop once and then return the 390 timeout of the next scheduled call next to expire soonest 391 (if any). 392 393 - (bool) handle_exit: when True catches ``KeyboardInterrupt`` and 394 ``SystemExit`` exceptions (caused by SIGTERM / SIGINT signals) and 395 gracefully exits after cleaning up resources. Also, logs server start and 396 stop. 397 398 - (int) worker_processes: pre-fork a certain number of child 399 processes before starting. See: :ref:`pre-fork-model`. 400 Each child process will keep using a 1-thread, async 401 concurrency model, handling multiple concurrent connections. 402 If the number is None or <= 0 the number of usable cores 403 available on this machine is detected and used. 404 It is a good idea to use this option in case the app risks 405 blocking for too long on a single function call (e.g. 406 hard-disk is slow, long DB query on auth etc.). 407 By splitting the work load over multiple processes the delay 408 introduced by a blocking function call is amortized and divided 409 by the number of worker processes. 410 411 *Changed in version 1.0.0*: no longer a classmethod 412 413 *Changed in version 1.0.0*: 'use_poll' and 'count' parameters were removed 414 415 *Changed in version 1.0.0*: 'blocking' and 'handle_exit' parameters were 416 added 417 418 .. method:: close() 419 420 Stop accepting connections without disconnecting currently connected 421 clients. :meth:`server_forever` loop will automatically stop when there are 422 no more connected clients. 423 424 .. method:: close_all() 425 426 Disconnect all clients, tell :meth:`server_forever` loop to stop and wait 427 until it does. 428 429 *Changed in version 1.0.0: 'map' and 'ignore_all' parameters were removed.* 430 431Filesystem 432========== 433 434.. class:: pyftpdlib.filesystems.FilesystemError 435 436 Exception class which can be raised from within 437 :class:`pyftpdlib.filesystems.AbstractedFS` in order to send custom error 438 messages to client. *New in version 1.0.0* 439 440.. class:: pyftpdlib.filesystems.AbstractedFS(root, cmd_channel) 441 442 A class used to interact with the file system, providing a cross-platform 443 interface compatible with both Windows and UNIX style filesystems where all 444 paths use ``"/"`` separator. AbstractedFS distinguishes between "real" 445 filesystem paths and "virtual" ftp paths emulating a UNIX chroot jail where 446 the user can not escape its home directory (example: real "/home/user" path 447 will be seen as "/" by the client). It also provides some utility methods and 448 wraps around all os.* calls involving operations against the filesystem like 449 creating files or removing directories. The contructor accepts two arguments: 450 root which is the user "real" home directory (e.g. '/home/user') and 451 cmd_channel which is the :class:`pyftpdlib.handlers.FTPHandler` class 452 instance. 453 454 *Changed in version 0.6.0: root and cmd_channel arguments were added.* 455 456 .. data:: root 457 458 User's home directory ("real"). *Changed in version 0.7.0: support 459 setattr()* 460 461 .. data:: cwd 462 463 User's current working directory ("virtual"). 464 465 *Changed in version 0.7.0: support setattr()* 466 467 .. method:: ftpnorm(ftppath) 468 469 Normalize a "virtual" ftp pathname depending on the current working 470 directory (e.g. having ``"/foo"`` as current working directory ``"bar"`` 471 becomes ``"/foo/bar"``). 472 473 .. method:: ftp2fs(ftppath) 474 475 Translate a "virtual" ftp pathname into equivalent absolute "real" 476 filesystem pathname (e.g. having ``"/home/user"`` as root directory 477 ``"foo"`` becomes ``"/home/user/foo"``). 478 479 .. method:: fs2ftp(fspath) 480 481 Translate a "real" filesystem pathname into equivalent absolute "virtual" 482 ftp pathname depending on the user's root directory (e.g. having 483 ``"/home/user"`` as root directory ``"/home/user/foo"`` becomes ``"/foo"``. 484 485 .. method:: validpath(path) 486 487 Check whether the path belongs to user's home directory. Expected argument 488 is a "real" filesystem path. If path is a symbolic link it is resolved to 489 check its real destination. Pathnames escaping from user's root directory 490 are considered not valid (return ``False``). 491 492 .. method:: open(filename, mode) 493 494 Wrapper around 495 `open() <http://docs.python.org/library/functions.html#open>`_ builtin. 496 497 .. method:: mkdir(path) 498 .. method:: chdir(path) 499 .. method:: rmdir(path) 500 .. method:: remove(path) 501 .. method:: rename(src, dst) 502 .. method:: chmod(path, mode) 503 .. method:: stat(path) 504 .. method:: lstat(path) 505 .. method:: readlink(path) 506 507 Wrappers around corresponding 508 `os <http://docs.python.org/library/os.html>`_ module functions. 509 510 .. method:: isfile(path) 511 .. method:: islink(path) 512 .. method:: isdir(path) 513 .. method:: getsize(path) 514 .. method:: getmtime(path) 515 .. method:: realpath(path) 516 .. method:: lexists(path) 517 518 Wrappers around corresponding 519 `os.path <http://docs.python.org/library/os.path.html>`_ module functions. 520 521 .. method:: mkstemp(suffix='', prefix='', dir=None, mode='wb') 522 523 Wrapper around 524 `tempfile.mkstemp <http://docs.python.org/library/tempfile.html#tempfile.mkstemp>`_. 525 526 .. method:: listdir(path) 527 528 Wrapper around 529 `os.listdir <http://docs.python.org/library/os.html#os.listdir>`_. 530 It is expected to return a list of unicode strings or a generator yielding 531 unicode strings. 532 533 .. versionchanged:: 1.6.0 can also return a generator. 534 535 536Extended classes 537================ 538 539 We are about to introduces are extensions (subclasses) of the ones explained 540 so far. They usually require third-party modules to be installed separately 541 or are specific for a given Python version or operating system. 542 543Extended handlers 544----------------- 545 546.. class:: pyftpdlib.handlers.TLS_FTPHandler(conn, server) 547 548 A :class:`pyftpdlib.handlers.FTPHandler` subclass implementing FTPS (FTP over 549 SSL/TLS) as described in `RFC-4217 <http://www.faqs.org/rfcs/rfc4217.html>`_ 550 implementing AUTH, PBSZ and PROT commands. 551 `PyOpenSSL <http://pypi.python.org/pypi/pyOpenSSL>`_ module is required to be 552 installed. Example below shows how to setup an FTPS server. Configurable 553 attributes: 554 555 .. data:: certfile 556 557 The path to a file which contains a certificate to be used to identify the 558 local side of the connection. This must always be specified, unless context 559 is provided instead. 560 561 .. data:: keyfile 562 563 The path of the file containing the private RSA key; can be omittetted if 564 certfile already contains the private key (defaults: ``None``). 565 566 .. data:: ssl_protocol 567 568 The desired SSL protocol version to use. This defaults to 569 `SSL.SSLv23_METHOD` which will negotiate the highest protocol that both 570 the server and your installation of OpenSSL support. 571 572 .. data:: ssl_options 573 574 specific OpenSSL options. These default to: 575 `SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3 | SSL.OP_NO_COMPRESSION` disabling 576 SSLv2 and SSLv3 versions and SSL compression algorithm which are 577 considered insecure. 578 Can be set to None in order to improve compatibilty with older (insecure) 579 FTP clients. 580 581 .. versionadded:: 1.6.0 582 583 .. data:: ssl_context 584 585 A `SSL.Context <http://pyopenssl.sourceforge.net/pyOpenSSL.html/openssl-context.html>`__ 586 instance which was previously configured. 587 If specified :data:`ssl_protocol` and :data:`ssl_options` parameters will 588 be ignored. 589 590 .. data:: tls_control_required 591 592 When True requires SSL/TLS to be established on the control channel, before 593 logging in. This means the user will have to issue AUTH before USER/PASS 594 (default ``False``). 595 596 .. data:: tls_data_required 597 598 When True requires SSL/TLS to be established on the data channel. This 599 means the user will have to issue PROT before PASV or PORT (default 600 ``False``). 601 602Extended authorizers 603-------------------- 604 605.. class:: pyftpdlib.authorizers.UnixAuthorizer(global_perm="elradfmwMT", allowed_users=None, rejected_users=None, require_valid_shell=True, anonymous_user=None, ,msg_login="Login successful.", msg_quit="Goodbye.") 606 607 Authorizer which interacts with the UNIX password database. Users are no 608 longer supposed to be explicitly added as when using 609 :class:`pyftpdlib.authorizers.DummyAuthorizer`. All FTP users are the same 610 defined on the UNIX system so if you access on your system by using 611 ``"john"`` as username and ``"12345"`` as password those same credentials can 612 be used for accessing the FTP server as well. The user home directories will 613 be automatically determined when user logins. Every time a filesystem 614 operation occurs (e.g. a file is created or deleted) the id of the process is 615 temporarily changed to the effective user id and whether the operation will 616 succeed depends on user and file permissions. This is why full read and write 617 permissions are granted by default in the class constructors. 618 619 *global_perm* is a series of letters referencing the users permissions; 620 defaults to "elradfmwMT" which means full read and write access for everybody 621 (except anonymous). *allowed_users* and *rejected_users* options expect a 622 list of users which are accepted or rejected for authenticating against the 623 FTP server; defaults both to ``[]`` (no restrictions). *require_valid_shell* 624 denies access for those users which do not have a valid shell binary listed in 625 /etc/shells. If /etc/shells cannot be found this is a no-op. *anonymous user* 626 is not subject to this option, and is free to not have a valid shell defined. 627 Defaults to ``True`` (a valid shell is required for login). *anonymous_user* 628 can be specified if you intend to provide anonymous access. The value 629 expected is a string representing the system user to use for managing 630 anonymous sessions; 631 defaults to ``None`` (anonymous access disabled). Note that in order to use 632 this class super user privileges are required. 633 634 *New in version 0.6.0* 635 636 .. method:: override_user(username=None, password=None, homedir=None, perm=None, anonymous_user=None, msg_login=None, msg_quit=None) 637 638 Overrides one or more options specified in the class constructor for a 639 specific user. Example: 640 641 >>> from pyftpdlib.authorizers import UnixAuthorizer 642 >>> auth = UnixAuthorizer(rejected_users=["root"]) 643 >>> auth = UnixAuthorizer(allowed_users=["matt", "jay"]) 644 >>> auth = UnixAuthorizer(require_valid_shell=False) 645 >>> auth.override_user("matt", password="foo", perm="elr") 646 647.. class:: pyftpdlib.authorizers.WindowsAuthorizer(global_perm="elradfmwMT", allowed_users=None, rejected_users=None, anonymous_user=None, anonymous_password="", msg_login="Login successful.", msg_quit="Goodbye.") 648 649 Same as :class:`pyftpdlib.authorizers.UnixAuthorizer` except for 650 *anonymous_password* argument which must be specified when defining the 651 *anonymous_user*. Also requires_valid_shell option is not available. In 652 order to use this class pywin32 extension must be installed. 653 654 *New in version 0.6.0* 655 656Extended filesystems 657-------------------- 658 659.. class:: pyftpdlib.filesystems.UnixFilesystem(root, cmd_channel) 660 661 Represents the real UNIX filesystem. Differently from 662 :class:`pyftpdlib.filesystems.AbstractedFS` the client will login into 663 /home/<username> and will be able to escape its home directory and navigate 664 the real filesystem. Use it in conjuction with 665 :class:`pyftpdlib.authorizers.UnixAuthorizer` to implement a "real" UNIX FTP 666 server (see 667 `demo/unix_ftpd.py <https://github.com/giampaolo/pyftpdlib/blob/master/demo/unix_ftpd.py>`__). 668 669 *New in version 0.6.0* 670 671Extended servers 672---------------- 673 674.. class:: pyftpdlib.servers.ThreadedFTPServer(address_or_socket, handler, ioloop=None, backlog=5) 675 676 A modified version of base :class:`pyftpdlib.servers.FTPServer` class which 677 spawns a thread every time a new connection is established. Differently from 678 base FTPServer class, the handler will be free to block without hanging the 679 whole IO loop. See :ref:`changing-the-concurrency-model`. 680 681 *New in version 1.0.0* 682 683 *Changed in 1.2.0: added ioloop parameter; address can also be a pre-existing 684 *socket.* 685 686.. class:: pyftpdlib.servers.MultiprocessFTPServer(address_or_socket, handler, ioloop=None, backlog=5) 687 688 A modified version of base :class:`pyftpdlib.servers.FTPServer` class which 689 spawns a process every time a new connection is established. Differently from 690 base FTPServer class, the handler will be free to block without hanging the 691 whole IO loop. See :ref:`changing-the-concurrency-model`. 692 693 *New in version 1.0.0* 694 695 *Changed in 1.2.0: added ioloop parameter; address can also be a pre-existing socket.* 696 697 *Availability: POSIX + Python >= 2.6* 698