class WindowsAuthorizer(_Base, BaseWindowsAuthorizer): """A wrapper on top of BaseWindowsAuthorizer providing options to specify what users should be allowed to login, per-user options, etc. Example usages: >>> from pyftpdlib.contrib.authorizers import WindowsAuthorizer >>> # accept all except Administrator >>> auth = UnixAuthorizer(rejected_users=["Administrator"]) >>> >>> # accept some users only >>> auth = UnixAuthorizer(allowed_users=["matt", "jay"]) >>> >>> # set specific options for a user >>> auth.override_user("matt", password="******", perm="elr") """ # --- public API def __init__(self, global_perm="elradfmw", allowed_users=[], rejected_users=[], anonymous_user=None, anonymous_password=None, msg_login="******", msg_quit="Goodbye."): """Parameters: - (string) global_perm: a series of letters referencing the users permissions; defaults to "elradfmw" which means full read and write access for everybody (except anonymous). - (list) allowed_users: a list of users which are accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (list) rejected_users: a list of users which are not accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (string) anonymous_user: specify it if you intend to provide anonymous access. The value expected is a string representing the system user to use for managing anonymous sessions. As for IIS, it is recommended to use Guest account. The common practice is to first enable the Guest user, which is disabled by default and then assign an empty password. Defaults to None (anonymous access disabled). - (string) anonymous_password: the password of the user who has been chosen to manage the anonymous sessions. Defaults to None (empty password). - (string) msg_login: the string sent when client logs in. - (string) msg_quit: the string sent when client quits. """ self.global_perm = global_perm self.allowed_users = allowed_users self.rejected_users = rejected_users self.anonymous_user = anonymous_user self.anonymous_password = anonymous_password self.msg_login = msg_login self.msg_quit = msg_quit self._dummy_authorizer = DummyAuthorizer() self._dummy_authorizer._check_permissions('', global_perm) _Base.__init__(self) # actually try to impersonate the user if self.anonymous_user is not None: self.impersonate_user(self.anonymous_user, self.anonymous_password) self.terminate_impersonation() 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. """ _Base.override_user(self, username, password, homedir, perm, msg_login, msg_quit) # --- overridden / private API def validate_authentication(self, username, password): """Authenticates against Windows user database; return True on success. """ if username == "anonymous": return self.anonymous_user is not None if self.allowed_users and username not in self.allowed_users: return False if self.rejected_users and username in self.rejected_users: return False overridden_password = self._get_key(username, 'pwd') if overridden_password: return overridden_password == password else: return BaseWindowsAuthorizer.validate_authentication( self, username, password) def impersonate_user(self, username, password): """Impersonate the security context of another user.""" if username == "anonymous": username = self.anonymous_user or "" password = self.anonymous_password or "" return BaseWindowsAuthorizer.impersonate_user( self, username, password) @replace_anonymous def has_user(self, username): if self._is_rejected_user(username): return False return username in self._get_system_users() @replace_anonymous def get_home_dir(self, username): overridden_home = self._get_key(username, 'home') if overridden_home: home = overridden_home else: home = BaseWindowsAuthorizer.get_home_dir(self, username) if not PY3 and not isinstance(home, unicode): home = home.decode('utf8') return home
class WindowsAuthorizer(_Base, BaseWindowsAuthorizer): """A wrapper on top of BaseWindowsAuthorizer providing options to specify what users should be allowed to login, per-user options, etc. Example usages: >>> from pyftpdlib.contrib.authorizers import WindowsAuthorizer >>> # accept all except Administrator >>> auth = UnixAuthorizer(rejected_users=["Administrator"]) >>> >>> # accept some users only >>> auth = UnixAuthorizer(allowed_users=["matt", "jay"]) >>> >>> # set specific options for a user >>> auth.override_user("matt", password="******", perm="elr") """ # --- public API def __init__(self, global_perm="elradfmw", allowed_users=[], rejected_users=[], anonymous_user=None, anonymous_password=None, msg_login="******", msg_quit="Goodbye."): """Parameters: - (string) global_perm: a series of letters referencing the users permissions; defaults to "elradfmw" which means full read and write access for everybody (except anonymous). - (list) allowed_users: a list of users which are accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (list) rejected_users: a list of users which are not accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (string) anonymous_user: specify it if you intend to provide anonymous access. The value expected is a string representing the system user to use for managing anonymous sessions. As for IIS, it is recommended to use Guest account. The common practice is to first enable the Guest user, which is disabled by default and then assign an empty password. Defaults to None (anonymous access disabled). - (string) anonymous_password: the password of the user who has been chosen to manage the anonymous sessions. Defaults to None (empty password). - (string) msg_login: the string sent when client logs in. - (string) msg_quit: the string sent when client quits. """ self.global_perm = global_perm self.allowed_users = allowed_users self.rejected_users = rejected_users self.anonymous_user = anonymous_user self.anonymous_password = anonymous_password self.msg_login = msg_login self.msg_quit = msg_quit self._dummy_authorizer = DummyAuthorizer() self._dummy_authorizer._check_permissions('', global_perm) _Base.__init__(self) # actually try to impersonate the user if self.anonymous_user is not None: self.impersonate_user(self.anonymous_user, self.anonymous_password) self.terminate_impersonation() 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. """ _Base.override_user(self, username, password, homedir, perm, msg_login, msg_quit) # --- overridden / private API def validate_authentication(self, username, password): """Authenticates against Windows user database; return True on success. """ if username == "anonymous": return self.anonymous_user is not None if self.allowed_users and username not in self.allowed_users: return False if self.rejected_users and username in self.rejected_users: return False overridden_password = self._get_key(username, 'pwd') if overridden_password: return overridden_password == password else: return BaseWindowsAuthorizer.validate_authentication(self, username, password) def impersonate_user(self, username, password): """Impersonate the security context of another user.""" if username == "anonymous": username = self.anonymous_user or "" password = self.anonymous_password or "" return BaseWindowsAuthorizer.impersonate_user(self, username, password) @replace_anonymous def has_user(self, username): if self._is_rejected_user(username): return False return username in self._get_system_users() @replace_anonymous def get_home_dir(self, username): overridden_home = self._get_key(username, 'home') if overridden_home: home = overridden_home else: home = BaseWindowsAuthorizer.get_home_dir(self, username) if not PY3 and not isinstance(home, unicode): home = home.decode('utf8') return home
class UnixAuthorizer(_Base, BaseUnixAuthorizer): """A wrapper on top of BaseUnixAuthorizer providing options to specify what users should be allowed to login, per-user options, etc. Example usages: >>> from pyftpdlib.contrib.authorizers import UnixAuthorizer >>> # accept all except root >>> auth = UnixAuthorizer(rejected_users=["root"]) >>> >>> # accept some users only >>> auth = UnixAuthorizer(allowed_users=["matt", "jay"]) >>> >>> # accept everybody and don't care if they have not a valid shell >>> auth = UnixAuthorizer(require_valid_shell=False) >>> >>> # set specific options for a user >>> auth.override_user("matt", password="******", perm="elr") """ # --- public API def __init__(self, global_perm="elradfmw", allowed_users=[], rejected_users=[], require_valid_shell=True, anonymous_user=None, msg_login="******", msg_quit="Goodbye."): """Parameters: - (string) global_perm: a series of letters referencing the users permissions; defaults to "elradfmw" which means full read and write access for everybody (except anonymous). - (list) allowed_users: a list of users which are accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (list) rejected_users: a list of users which are not accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (bool) require_valid_shell: Deny access for those users which do not have a valid shell binary listed in /etc/shells. If /etc/shells cannot be found this is a no-op. Anonymous user is not subject to this option, and is free to not have a valid shell defined. Defaults to True (a valid shell is required for login). - (string) anonymous_user: specify it if you intend to provide anonymous access. The value expected is a string representing the system user to use for managing anonymous sessions; defaults to None (anonymous access disabled). - (string) msg_login: the string sent when client logs in. - (string) msg_quit: the string sent when client quits. """ BaseUnixAuthorizer.__init__(self, anonymous_user) self.global_perm = global_perm self.allowed_users = allowed_users self.rejected_users = rejected_users self.anonymous_user = anonymous_user self.require_valid_shell = require_valid_shell self.msg_login = msg_login self.msg_quit = msg_quit self._dummy_authorizer = DummyAuthorizer() self._dummy_authorizer._check_permissions('', global_perm) _Base.__init__(self) if require_valid_shell: for username in self.allowed_users: if not self._has_valid_shell(username): raise ValueError("user %s has not a valid shell" % username) 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 self.require_valid_shell and username != 'anonymous': if not self._has_valid_shell(username): raise ValueError("user %s has not a valid shell" % username) _Base.override_user(self, username, password, homedir, perm, msg_login, msg_quit) # --- overridden / private API def validate_authentication(self, username, password): if username == "anonymous": return self.anonymous_user is not None if self._is_rejected_user(username): return False if self.require_valid_shell and username != 'anonymous': if not self._has_valid_shell(username): return False overridden_password = self._get_key(username, 'pwd') if overridden_password: return overridden_password == password return BaseUnixAuthorizer.validate_authentication( self, username, password) @replace_anonymous def has_user(self, username): if self._is_rejected_user(username): return False return username in self._get_system_users() @replace_anonymous def get_home_dir(self, username): overridden_home = self._get_key(username, 'home') if overridden_home: return overridden_home return BaseUnixAuthorizer.get_home_dir(self, username) @staticmethod def _has_valid_shell(username): """Return True if the user has a valid shell binary listed in /etc/shells. If /etc/shells can't be found return True. """ file = None try: try: file = open('/etc/shells', 'r') except IOError: err = sys.exc_info()[1] if err.errno == errno.ENOENT: return True raise else: try: shell = pwd.getpwnam(username).pw_shell except KeyError: # invalid user return False for line in file: if line.startswith('#'): continue line = line.strip() if line == shell: return True return False finally: if file is not None: file.close()
class UnixAuthorizer(_Base, BaseUnixAuthorizer): """A wrapper on top of BaseUnixAuthorizer providing options to specify what users should be allowed to login, per-user options, etc. Example usages: >>> from pyftpdlib.contrib.authorizers import UnixAuthorizer >>> # accept all except root >>> auth = UnixAuthorizer(rejected_users=["root"]) >>> >>> # accept some users only >>> auth = UnixAuthorizer(allowed_users=["matt", "jay"]) >>> >>> # accept everybody and don't care if they have not a valid shell >>> auth = UnixAuthorizer(require_valid_shell=False) >>> >>> # set specific options for a user >>> auth.override_user("matt", password="******", perm="elr") """ # --- public API def __init__(self, global_perm="elradfmw", allowed_users=[], rejected_users=[], require_valid_shell=True, anonymous_user=None, msg_login="******", msg_quit="Goodbye."): """Parameters: - (string) global_perm: a series of letters referencing the users permissions; defaults to "elradfmw" which means full read and write access for everybody (except anonymous). - (list) allowed_users: a list of users which are accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (list) rejected_users: a list of users which are not accepted for authenticating against the FTP server; defaults to [] (no restrictions). - (bool) require_valid_shell: Deny access for those users which do not have a valid shell binary listed in /etc/shells. If /etc/shells cannot be found this is a no-op. Anonymous user is not subject to this option, and is free to not have a valid shell defined. Defaults to True (a valid shell is required for login). - (string) anonymous_user: specify it if you intend to provide anonymous access. The value expected is a string representing the system user to use for managing anonymous sessions; defaults to None (anonymous access disabled). - (string) msg_login: the string sent when client logs in. - (string) msg_quit: the string sent when client quits. """ BaseUnixAuthorizer.__init__(self, anonymous_user) self.global_perm = global_perm self.allowed_users = allowed_users self.rejected_users = rejected_users self.anonymous_user = anonymous_user self.require_valid_shell = require_valid_shell self.msg_login = msg_login self.msg_quit = msg_quit self._dummy_authorizer = DummyAuthorizer() self._dummy_authorizer._check_permissions('', global_perm) _Base.__init__(self) if require_valid_shell: for username in self.allowed_users: if not self._has_valid_shell(username): raise ValueError("user %s has not a valid shell" % username) 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 self.require_valid_shell and username != 'anonymous': if not self._has_valid_shell(username): raise ValueError("user %s has not a valid shell" % username) _Base.override_user(self, username, password, homedir, perm, msg_login, msg_quit) # --- overridden / private API def validate_authentication(self, username, password): if username == "anonymous": return self.anonymous_user is not None if self._is_rejected_user(username): return False if self.require_valid_shell and username != 'anonymous': if not self._has_valid_shell(username): return False overridden_password = self._get_key(username, 'pwd') if overridden_password: return overridden_password == password return BaseUnixAuthorizer.validate_authentication(self, username, password) @replace_anonymous def has_user(self, username): if self._is_rejected_user(username): return False return username in self._get_system_users() @replace_anonymous def get_home_dir(self, username): overridden_home = self._get_key(username, 'home') if overridden_home: return overridden_home return BaseUnixAuthorizer.get_home_dir(self, username) @staticmethod def _has_valid_shell(username): """Return True if the user has a valid shell binary listed in /etc/shells. If /etc/shells can't be found return True. """ file = None try: try: file = open('/etc/shells', 'r') except IOError: err = sys.exc_info()[1] if err.errno == errno.ENOENT: return True raise else: try: shell = pwd.getpwnam(username).pw_shell except KeyError: # invalid user return False for line in file: if line.startswith('#'): continue line = line.strip() if line == shell: return True return False finally: if file is not None: file.close()