Esempio n. 1
0
    def override_user(self,
                      username,
                      password=None,
                      homedir=None,
                      perm=None,
                      msg_login=None,
                      msg_quit=None):
        """Overrides the options specified in the class constructor
        for a specific user.
        """
        if (not password and not homedir and not perm and not msg_login
                and not msg_quit):
            raise AuthorizerError(
                "at least one keyword argument must be specified")
        if self.allowed_users and username not in self.allowed_users:
            raise AuthorizerError('%s is not an allowed user' % username)
        if self.rejected_users and username in self.rejected_users:
            raise AuthorizerError('%s is not an allowed user' % username)
        if username == "anonymous" and password:
            raise AuthorizerError("can't assign password to anonymous user")
        if not self.has_user(username):
            raise AuthorizerError('no such user %s' % username)
        if homedir is not None and not isinstance(homedir, unicode):
            homedir = homedir.decode('utf8')

        if username in self._dummy_authorizer.user_table:
            # re-set parameters
            del self._dummy_authorizer.user_table[username]
        self._dummy_authorizer.add_user(username, password or "", homedir
                                        or getcwdu(), perm or "", msg_login
                                        or "", msg_quit or "")
        if homedir is None:
            self._dummy_authorizer.user_table[username]['home'] = ""
Esempio n. 2
0
    def __init__(self, addr=None):
        os.mkdir('server')
        os.chdir('server')
        try:
            HOST = socket.gethostbyname('localhost')
        except socket.error:
            HOST = 'localhost'
        USER = '******'
        PASSWD = '12345'
        HOME = getcwdu()

        threading.Thread.__init__(self)
        self.__serving = False
        self.__stopped = False
        self.__lock = threading.Lock()
        self.__flag = threading.Event()
        if addr is None:
            addr = (HOST, 0)

        authorizer = DummyAuthorizer()
        authorizer.add_user(USER, PASSWD, HOME, perm='elradfmwM')  # full perms
        authorizer.add_anonymous(HOME)
        self.handler.authorizer = authorizer
        # lowering buffer sizes = more cycles to transfer data
        # = less false positive test failures
        self.handler.dtp_handler.ac_in_buffer_size = 32768
        self.handler.dtp_handler.ac_out_buffer_size = 32768
        self.server = self.server_class(addr, self.handler)
        self.host, self.port = self.server.socket.getsockname()[:2]
        os.chdir('..')
Esempio n. 3
0
    def override_user(self, username, password=None, homedir=None, perm=None,
                      msg_login=None, msg_quit=None):
        """Overrides the options specified in the class constructor
        for a specific user.
        """
        if (not password and not homedir and not perm and not msg_login
                and not msg_quit):
            raise AuthorizerError(
                "at least one keyword argument must be specified")
        if self.allowed_users and username not in self.allowed_users:
            raise AuthorizerError('%s is not an allowed user' % username)
        if self.rejected_users and username in self.rejected_users:
            raise AuthorizerError('%s is not an allowed user' % username)
        if username == "anonymous" and password:
            raise AuthorizerError("can't assign password to anonymous user")
        if not self.has_user(username):
            raise AuthorizerError('no such user %s' % username)
        if homedir is not None and not isinstance(homedir, unicode):
            homedir = homedir.decode('utf8')

        if username in self._dummy_authorizer.user_table:
            # re-set parameters
            del self._dummy_authorizer.user_table[username]
        self._dummy_authorizer.add_user(username,
                                        password or "",
                                        homedir or getcwdu(),
                                        perm or "",
                                        msg_login or "",
                                        msg_quit or "")
        if homedir is None:
            self._dummy_authorizer.user_table[username]['home'] = ""
Esempio n. 4
0
    def __init__(self, addr=None):
        os.mkdir ('server')
        os.chdir ('server')
        try:
            HOST = socket.gethostbyname ('localhost')
        except socket.error:
            HOST = 'localhost'
        USER = '******'
        PASSWD = '12345'
        HOME = getcwdu ()

        threading.Thread.__init__(self)
        self.__serving = False
        self.__stopped = False
        self.__lock = threading.Lock()
        self.__flag = threading.Event()
        if addr is None:
            addr = (HOST, 0)

        authorizer = DummyAuthorizer()
        authorizer.add_user(USER, PASSWD, HOME, perm='elradfmwM')  # full perms
        authorizer.add_anonymous(HOME)
        self.handler.authorizer = authorizer
        # lowering buffer sizes = more cycles to transfer data
        # = less false positive test failures
        self.handler.dtp_handler.ac_in_buffer_size = 32768
        self.handler.dtp_handler.ac_out_buffer_size = 32768
        self.server = self.server_class(addr, self.handler)
        self.host, self.port = self.server.socket.getsockname()[:2]
        os.chdir ('..')
Esempio n. 5
0
 def test_case(self):
     root = getcwdu()
     fs = filesystems.UnixFilesystem(root, None)
     self.assertEqual(fs.root, root)
     self.assertEqual(fs.cwd, root)
     cdup = os.path.dirname(root)
     self.assertEqual(fs.ftp2fs(u('..')), cdup)
     self.assertEqual(fs.fs2ftp(root), root)
Esempio n. 6
0
 def test_case(self):
     root = getcwdu()
     fs = UnixFilesystem(root, None)
     self.assertEqual(fs.root, root)
     self.assertEqual(fs.cwd, root)
     cdup = os.path.dirname(root)
     self.assertEqual(fs.ftp2fs(u('..')), cdup)
     self.assertEqual(fs.fs2ftp(root), root)
Esempio n. 7
0
def main():
    """Start a stand alone anonymous FTP server."""
    usage = "python -m pyftpdlib.ftpserver [options]"
    parser = optparse.OptionParser(usage=usage, description=main.__doc__,
                                   formatter=CustomizedOptionFormatter())
    parser.add_option('-i', '--interface', default=None, metavar="ADDRESS",
                      help="specify the interface to run on (default all "
                           "interfaces)")
    parser.add_option('-p', '--port', type="int", default=2121, metavar="PORT",
                      help="specify port number to run on (default 21)")
    parser.add_option('-w', '--write', action="store_true", default=False,
                      help="grants write access for the anonymous user "
                           "(default read-only)")
    parser.add_option('-d', '--directory', default=getcwdu(), metavar="FOLDER",
                      help="specify the directory to share (default current "
                           "directory)")
    parser.add_option('-n', '--nat-address', default=None, metavar="ADDRESS",
                      help="the NAT address to use for passive connections")
    parser.add_option('-r', '--range', default=None, metavar="FROM-TO",
                      help="the range of TCP ports to use for passive "
                           "connections (e.g. -r 8000-9000)")
    parser.add_option('-v', '--version', action='store_true',
                      help="print pyftpdlib version and exit")

    options, args = parser.parse_args()
    if options.version:
        sys.exit("pyftpdlib %s" % __ver__)
    passive_ports = None
    if options.range:
        try:
            start, stop = options.range.split('-')
            start = int(start)
            stop = int(stop)
        except ValueError:
            parser.error('invalid argument passed to -r option')
        else:
            passive_ports = list(range(start, stop + 1))
    # On recent Windows versions, if address is not specified and IPv6
    # is installed the socket will listen on IPv6 by default; in this
    # case we force IPv4 instead.
    if os.name in ('nt', 'ce') and not options.interface:
        options.interface = '0.0.0.0'

    authorizer = DummyAuthorizer()
    perm = options.write and "elradfmwM" or "elr"
    authorizer.add_anonymous(options.directory, perm=perm)
    handler = FTPHandler
    handler.authorizer = authorizer
    handler.masquerade_address = options.nat_address
    handler.passive_ports = passive_ports
    ftpd = FTPServer((options.interface, options.port), FTPHandler)
    try:
        ftpd.serve_forever()
    finally:
        ftpd.close_all()
Esempio n. 8
0
 def test_override_user_homedir(self):
     auth = self.authorizer_class()
     user = self.get_current_user()
     dir = os.path.dirname(getcwdu())
     auth.override_user(user, homedir=dir)
     self.assertEqual(auth.get_home_dir(user), dir)
     # make sure other settings keep using default values
     #self.assertEqual(auth.get_home_dir(user), self.get_current_user_homedir())
     self.assertEqual(auth.get_perms(user), "elradfmw")
     self.assertEqual(auth.get_msg_login(user), "Login successful.")
     self.assertEqual(auth.get_msg_quit(user), "Goodbye.")
Esempio n. 9
0
 def test_override_user_homedir(self):
     auth = self.authorizer_class()
     user = self.get_current_user()
     dir = os.path.dirname(getcwdu())
     auth.override_user(user, homedir=dir)
     self.assertEqual(auth.get_home_dir(user), dir)
     # make sure other settings keep using default values
     #self.assertEqual(auth.get_home_dir(user), self.get_current_user_homedir())
     self.assertEqual(auth.get_perms(user), "elradfmw")
     self.assertEqual(auth.get_msg_login(user), "Login successful.")
     self.assertEqual(auth.get_msg_quit(user), "Goodbye.")
Esempio n. 10
0
    def test_ftp2fs(self):
        # Tests for ftp2fs method.
        def join(x, y):
            return os.path.join(x, y.replace('/', os.sep))

        ae = self.assertEqual
        fs = AbstractedFS(u('/'), None)

        def goforit(root):
            fs._root = root
            fs._cwd = u('/')
            ae(fs.ftp2fs(u('')), root)
            ae(fs.ftp2fs(u('/')), root)
            ae(fs.ftp2fs(u('.')), root)
            ae(fs.ftp2fs(u('..')), root)
            ae(fs.ftp2fs(u('a')), join(root, u('a')))
            ae(fs.ftp2fs(u('/a')), join(root, u('a')))
            ae(fs.ftp2fs(u('/a/')), join(root, u('a')))
            ae(fs.ftp2fs(u('a/..')), root)
            ae(fs.ftp2fs(u('a/b')), join(root, u(r'a/b')))
            ae(fs.ftp2fs(u('/a/b')), join(root, u(r'a/b')))
            ae(fs.ftp2fs(u('/a/b/..')), join(root, u('a')))
            ae(fs.ftp2fs(u('/a/b/../..')), root)
            fs._cwd = u('/sub')
            ae(fs.ftp2fs(u('')), join(root, u('sub')))
            ae(fs.ftp2fs(u('/')), root)
            ae(fs.ftp2fs(u('.')), join(root, u('sub')))
            ae(fs.ftp2fs(u('..')), root)
            ae(fs.ftp2fs(u('a')), join(root, u('sub/a')))
            ae(fs.ftp2fs(u('a/')), join(root, u('sub/a')))
            ae(fs.ftp2fs(u('a/..')), join(root, u('sub')))
            ae(fs.ftp2fs(u('a/b')), join(root, 'sub/a/b'))
            ae(fs.ftp2fs(u('a/b/..')), join(root, u('sub/a')))
            ae(fs.ftp2fs(u('a/b/../..')), join(root, u('sub')))
            ae(fs.ftp2fs(u('a/b/../../..')), root)
            # UNC paths must be collapsed
            ae(fs.ftp2fs(u('//a')), join(root, u('a')))

        if os.sep == '\\':
            goforit(u(r'C:\dir'))
            goforit(u('C:\\'))
            # on DOS-derived filesystems (e.g. Windows) this is the same
            # as specifying the current drive directory (e.g. 'C:\\')
            goforit(u('\\'))
        elif os.sep == '/':
            goforit(u('/home/user'))
            goforit(u('/'))
        else:
            # os.sep == ':'? Don't know... let's try it anyway
            goforit(getcwdu())
Esempio n. 11
0
    def test_ftp2fs(self):
        # Tests for ftp2fs method.
        def join(x, y):
            return os.path.join(x, y.replace('/', os.sep))

        ae = self.assertEqual
        fs = AbstractedFS(u('/'), None)

        def goforit(root):
            fs._root = root
            fs._cwd = u('/')
            ae(fs.ftp2fs(u('')), root)
            ae(fs.ftp2fs(u('/')), root)
            ae(fs.ftp2fs(u('.')), root)
            ae(fs.ftp2fs(u('..')), root)
            ae(fs.ftp2fs(u('a')), join(root, u('a')))
            ae(fs.ftp2fs(u('/a')), join(root, u('a')))
            ae(fs.ftp2fs(u('/a/')), join(root, u('a')))
            ae(fs.ftp2fs(u('a/..')), root)
            ae(fs.ftp2fs(u('a/b')), join(root, u(r'a/b')))
            ae(fs.ftp2fs(u('/a/b')), join(root, u(r'a/b')))
            ae(fs.ftp2fs(u('/a/b/..')), join(root, u('a')))
            ae(fs.ftp2fs(u('/a/b/../..')), root)
            fs._cwd = u('/sub')
            ae(fs.ftp2fs(u('')), join(root, u('sub')))
            ae(fs.ftp2fs(u('/')), root)
            ae(fs.ftp2fs(u('.')), join(root, u('sub')))
            ae(fs.ftp2fs(u('..')), root)
            ae(fs.ftp2fs(u('a')), join(root, u('sub/a')))
            ae(fs.ftp2fs(u('a/')), join(root, u('sub/a')))
            ae(fs.ftp2fs(u('a/..')), join(root, u('sub')))
            ae(fs.ftp2fs(u('a/b')), join(root, 'sub/a/b'))
            ae(fs.ftp2fs(u('a/b/..')), join(root, u('sub/a')))
            ae(fs.ftp2fs(u('a/b/../..')), join(root, u('sub')))
            ae(fs.ftp2fs(u('a/b/../../..')), root)
            # UNC paths must be collapsed
            ae(fs.ftp2fs(u('//a')), join(root, u('a')))

        if os.sep == '\\':
            goforit(u(r'C:\dir'))
            goforit(u('C:\\'))
            # on DOS-derived filesystems (e.g. Windows) this is the same
            # as specifying the current drive directory (e.g. 'C:\\')
            goforit(u('\\'))
        elif os.sep == '/':
            goforit(u('/home/user'))
            goforit(u('/'))
        else:
            # os.sep == ':'? Don't know... let's try it anyway
            goforit(getcwdu())
Esempio n. 12
0
    def test_fs2ftp(self):
        # Tests for fs2ftp method.
        def join(x, y):
            return os.path.join(x, y.replace('/', os.sep))

        ae = self.assertEqual
        fs = AbstractedFS(u('/'), None)

        def goforit(root):
            fs._root = root
            ae(fs.fs2ftp(root), u('/'))
            ae(fs.fs2ftp(join(root, u('/'))), u('/'))
            ae(fs.fs2ftp(join(root, u('.'))), u('/'))
            # can't escape from root
            ae(fs.fs2ftp(join(root, u('..'))), u('/'))
            ae(fs.fs2ftp(join(root, u('a'))), u('/a'))
            ae(fs.fs2ftp(join(root, u('a/'))), u('/a'))
            ae(fs.fs2ftp(join(root, u('a/..'))), u('/'))
            ae(fs.fs2ftp(join(root, u('a/b'))), u('/a/b'))
            ae(fs.fs2ftp(join(root, u('a/b'))), u('/a/b'))
            ae(fs.fs2ftp(join(root, u('a/b/..'))), u('/a'))
            ae(fs.fs2ftp(join(root, u('/a/b/../..'))), u('/'))
            fs._cwd = u('/sub')
            ae(fs.fs2ftp(join(root, 'a/')), u('/a'))

        if os.sep == '\\':
            goforit(u(r'C:\dir'))
            goforit(u('C:\\'))
            # on DOS-derived filesystems (e.g. Windows) this is the same
            # as specifying the current drive directory (e.g. 'C:\\')
            goforit(u('\\'))
            fs._root = u(r'C:\dir')
            ae(fs.fs2ftp(u('C:\\')), u('/'))
            ae(fs.fs2ftp(u('D:\\')), u('/'))
            ae(fs.fs2ftp(u('D:\\dir')), u('/'))
        elif os.sep == '/':
            goforit(u('/'))
            if os.path.realpath('/__home/user') != '/__home/user':
                self.fail('Test skipped (symlinks not allowed).')
            goforit(u('/__home/user'))
            fs._root = u('/__home/user')
            ae(fs.fs2ftp(u('/__home')), u('/'))
            ae(fs.fs2ftp(u('/')), u('/'))
            ae(fs.fs2ftp(u('/__home/userx')), u('/'))
        else:
            # os.sep == ':'? Don't know... let's try it anyway
            goforit(getcwdu())
Esempio n. 13
0
    def test_fs2ftp(self):
        # Tests for fs2ftp method.
        def join(x, y):
            return os.path.join(x, y.replace('/', os.sep))

        ae = self.assertEqual
        fs = AbstractedFS(u('/'), None)

        def goforit(root):
            fs._root = root
            ae(fs.fs2ftp(root), u('/'))
            ae(fs.fs2ftp(join(root, u('/'))), u('/'))
            ae(fs.fs2ftp(join(root, u('.'))), u('/'))
            # can't escape from root
            ae(fs.fs2ftp(join(root, u('..'))), u('/'))
            ae(fs.fs2ftp(join(root, u('a'))), u('/a'))
            ae(fs.fs2ftp(join(root, u('a/'))), u('/a'))
            ae(fs.fs2ftp(join(root, u('a/..'))), u('/'))
            ae(fs.fs2ftp(join(root, u('a/b'))), u('/a/b'))
            ae(fs.fs2ftp(join(root, u('a/b'))), u('/a/b'))
            ae(fs.fs2ftp(join(root, u('a/b/..'))), u('/a'))
            ae(fs.fs2ftp(join(root, u('/a/b/../..'))), u('/'))
            fs._cwd = u('/sub')
            ae(fs.fs2ftp(join(root, 'a/')), u('/a'))

        if os.sep == '\\':
            goforit(u(r'C:\dir'))
            goforit(u('C:\\'))
            # on DOS-derived filesystems (e.g. Windows) this is the same
            # as specifying the current drive directory (e.g. 'C:\\')
            goforit(u('\\'))
            fs._root = u(r'C:\dir')
            ae(fs.fs2ftp(u('C:\\')), u('/'))
            ae(fs.fs2ftp(u('D:\\')), u('/'))
            ae(fs.fs2ftp(u('D:\\dir')), u('/'))
        elif os.sep == '/':
            goforit(u('/'))
            if os.path.realpath('/__home/user') != '/__home/user':
                self.fail('Test skipped (symlinks not allowed).')
            goforit(u('/__home/user'))
            fs._root = u('/__home/user')
            ae(fs.fs2ftp(u('/__home')), u('/'))
            ae(fs.fs2ftp(u('/')), u('/'))
            ae(fs.fs2ftp(u('/__home/userx')), u('/'))
        else:
            # os.sep == ':'? Don't know... let's try it anyway
            goforit(getcwdu())
Esempio n. 14
0
if sys.version_info < (2, 7):
    import unittest2 as unittest  # pip install unittest2
else:
    import unittest

sendfile = _import_sendfile()

# Attempt to use IP rather than hostname (test suite will run a lot faster)
try:
    HOST = socket.gethostbyname('localhost')
except socket.error:
    HOST = 'localhost'
USER = '******'
PASSWD = '12345'
HOME = getcwdu()
# Disambiguate TESTFN for parallel testing.
if os.name == 'java':
    # Jython disallows @ in module names
    TESTFN_PREFIX = '$pyftpd-%s-' % os.getpid()
else:
    TESTFN_PREFIX = '@pyftpd-%s-' % os.getpid()
TIMEOUT = 2
BUFSIZE = 1024
INTERRUPTED_TRANSF_SIZE = 32768
NO_RETRIES = 5
OSX = sys.platform.startswith("darwin")
POSIX = os.name == 'posix'
WINDOWS = os.name == 'nt'
TRAVIS = bool(os.environ.get('TRAVIS'))
VERBOSITY = 1 if os.getenv('SILENT') else 2
Esempio n. 15
0
def main():
    """Start a stand alone anonymous FTP server."""
    import optparse
    import sys
    import os

    from pyftpdlib.authorizers import DummyAuthorizer
    from pyftpdlib.handlers import FTPHandler
    from pyftpdlib.servers import FTPServer
    from pyftpdlib._compat import getcwdu

    class CustomizedOptionFormatter(optparse.IndentedHelpFormatter):
        """Formats options shown in help in a prettier way."""
        def format_option(self, option):
            result = []
            opts = self.option_strings[option]
            result.append('  %s\n' % opts)
            if option.help:
                help_text = '     %s\n\n' % self.expand_default(option)
                result.append(help_text)
            return ''.join(result)

    usage = "python -m pyftpdlib.ftpserver [options]"
    parser = optparse.OptionParser(usage=usage,
                                   description=main.__doc__,
                                   formatter=CustomizedOptionFormatter())
    parser.add_option('-i',
                      '--interface',
                      default='',
                      metavar="ADDRESS",
                      help="specify the interface to run on (default all "
                      "interfaces)")
    parser.add_option('-p',
                      '--port',
                      type="int",
                      default=21,
                      metavar="PORT",
                      help="specify port number to run on (default 21)")
    parser.add_option('-w',
                      '--write',
                      action="store_true",
                      default=False,
                      help="grants write access for the anonymous user "
                      "(default read-only)")
    parser.add_option('-d',
                      '--directory',
                      default=getcwdu(),
                      metavar="FOLDER",
                      help="specify the directory to share (default current "
                      "directory)")
    parser.add_option('-n',
                      '--nat-address',
                      default=None,
                      metavar="ADDRESS",
                      help="the NAT address to use for passive connections")
    parser.add_option('-r',
                      '--range',
                      default=None,
                      metavar="FROM-TO",
                      help="the range of TCP ports to use for passive "
                      "connections (e.g. -r 8000-9000)")
    parser.add_option('-v',
                      '--version',
                      action='store_true',
                      help="print pyftpdlib version and exit")

    options, args = parser.parse_args()
    if options.version:
        sys.exit("pyftpdlib %s" % __ver__)
    passive_ports = None
    if options.range:
        try:
            start, stop = options.range.split('-')
            start = int(start)
            stop = int(stop)
        except ValueError:
            parser.error('invalid argument passed to -r option')
        else:
            passive_ports = list(range(start, stop + 1))
    # On recent Windows versions, if address is not specified and IPv6
    # is installed the socket will listen on IPv6 by default; in this
    # case we force IPv4 instead.
    if os.name in ('nt', 'ce') and not options.interface:
        options.interface = '0.0.0.0'

    authorizer = DummyAuthorizer()
    perm = options.write and "elradfmwM" or "elr"
    authorizer.add_anonymous(options.directory, perm=perm)
    handler = FTPHandler
    handler.authorizer = authorizer
    handler.masquerade_address = options.nat_address
    handler.passive_ports = passive_ports
    ftpd = FTPServer((options.interface, options.port), FTPHandler)
    ftpd.serve_forever()
Esempio n. 16
0
sendfile = None
if os.name == 'posix':
    try:
        import sendfile
    except ImportError:
        pass


# Attempt to use IP rather than hostname (test suite will run a lot faster)
try:
    HOST = socket.gethostbyname('localhost')
except socket.error:
    HOST = 'localhost'
USER = '******'
PASSWD = '12345'
HOME = getcwdu()
TESTFN = 'tmp-pyftpdlib'
TESTFN_UNICODE = TESTFN + '-unicode-' + '\xe2\x98\x83'
TESTFN_UNICODE_2 = TESTFN_UNICODE + '-2'
TIMEOUT = 2
BUFSIZE = 1024
INTERRUPTED_TRANSF_SIZE = 32768
NO_RETRIES = 5
OSX = sys.platform.startswith("darwin")
POSIX = os.name == 'posix'
WINDOWS = os.name == 'nt'
TRAVIS = bool(os.environ.get('TRAVIS'))
VERBOSITY = 1 if os.getenv('SILENT') else 2


class TestCase(unittest.TestCase):
Esempio n. 17
0
def main():
    """Start a stand alone anonymous FTP server."""
    usage = "python -m pyftpdlib.ftpserver [options]"
    parser = optparse.OptionParser(usage=usage,
                                   description=main.__doc__,
                                   formatter=CustomizedOptionFormatter())
    parser.add_option('-i',
                      '--interface',
                      default=None,
                      metavar="ADDRESS",
                      help="specify the interface to run on (default all "
                      "interfaces)")
    parser.add_option('-p',
                      '--port',
                      type="int",
                      default=2121,
                      metavar="PORT",
                      help="specify port number to run on (default 21)")
    parser.add_option('-w',
                      '--write',
                      action="store_true",
                      default=False,
                      help="grants write access for the anonymous user "
                      "(default read-only)")
    parser.add_option('-d',
                      '--directory',
                      default=getcwdu(),
                      metavar="FOLDER",
                      help="specify the directory to share (default current "
                      "directory)")
    parser.add_option('-n',
                      '--nat-address',
                      default=None,
                      metavar="ADDRESS",
                      help="the NAT address to use for passive connections")
    parser.add_option('-r',
                      '--range',
                      default=None,
                      metavar="FROM-TO",
                      help="the range of TCP ports to use for passive "
                      "connections (e.g. -r 8000-9000)")
    parser.add_option('-v',
                      '--version',
                      action='store_true',
                      help="print pyftpdlib version and exit")
    parser.add_option('-V',
                      '--verbose',
                      action='store_true',
                      help="activate a more verbose logging")

    options, args = parser.parse_args()
    if options.version:
        sys.exit("pyftpdlib %s" % __ver__)
    if options.verbose:
        import logging
        import pyftpdlib.log
        pyftpdlib.log.LEVEL = logging.DEBUG

    passive_ports = None
    if options.range:
        try:
            start, stop = options.range.split('-')
            start = int(start)
            stop = int(stop)
        except ValueError:
            parser.error('invalid argument passed to -r option')
        else:
            passive_ports = list(range(start, stop + 1))
    # On recent Windows versions, if address is not specified and IPv6
    # is installed the socket will listen on IPv6 by default; in this
    # case we force IPv4 instead.
    if os.name in ('nt', 'ce') and not options.interface:
        options.interface = '0.0.0.0'

    authorizer = DummyAuthorizer()
    perm = options.write and "elradfmwM" or "elr"
    authorizer.add_anonymous(options.directory, perm=perm)
    handler = FTPHandler
    handler.authorizer = authorizer
    handler.masquerade_address = options.nat_address
    handler.passive_ports = passive_ports
    ftpd = FTPServer((options.interface, options.port), FTPHandler)
    try:
        ftpd.serve_forever()
    finally:
        ftpd.close_all()