Index: third_party/pyftpdlib/demo/winnt_ftpd.py |
=================================================================== |
--- third_party/pyftpdlib/demo/winnt_ftpd.py (revision 0) |
+++ third_party/pyftpdlib/demo/winnt_ftpd.py (revision 0) |
@@ -0,0 +1,115 @@ |
+#!/usr/bin/env python |
+# winnt_ftpd.py |
+ |
+"""A ftpd using local Windows NT account database to authenticate users |
+(users must already exist). |
+ |
+It also provides a mechanism to (temporarily) impersonate the system |
+users every time they are going to perform filesystem operations. |
+""" |
+ |
+import os |
+import win32security, win32net, pywintypes, win32con |
+ |
+from pyftpdlib import ftpserver |
+ |
+ |
+def get_profile_dir(username): |
+ """Return the user's profile directory.""" |
+ import _winreg, win32api |
+ sid = win32security.ConvertSidToStringSid( |
+ win32security.LookupAccountName(None, username)[0]) |
+ try: |
+ key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, |
+ r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"+"\\"+sid) |
+ except WindowsError: |
+ raise ftpserver.AuthorizerError("No profile directory defined for %s " |
+ "user" %username) |
+ value = _winreg.QueryValueEx(key, "ProfileImagePath")[0] |
+ return win32api.ExpandEnvironmentStrings(value) |
+ |
+ |
+class WinNtAuthorizer(ftpserver.DummyAuthorizer): |
+ |
+ def add_user(self, username, homedir=None, **kwargs): |
+ """Add a "real" system user to the virtual users table. |
+ |
+ If no homedir argument is specified the user's profile |
+ directory will possibly be determined and used. |
+ |
+ The keyword arguments in kwargs are the same expected by the |
+ original add_user method: "perm", "msg_login" and "msg_quit". |
+ """ |
+ # get the list of all available users on the system and check |
+ # if provided username exists |
+ users = [entry['name'] for entry in win32net.NetUserEnum(None, 0)[0]] |
+ if not username in users: |
+ raise ftpserver.AuthorizerError('No such user "%s".' %username) |
+ if not homedir: |
+ homedir = get_profile_dir(username) |
+ ftpserver.DummyAuthorizer.add_user(self, username, '', homedir, |
+ **kwargs) |
+ |
+ def add_anonymous(self, homedir=None, realuser="Guest", |
+ password="", **kwargs): |
+ """Add an anonymous user to the virtual users table. |
+ |
+ If no homedir argument is specified the realuser's profile |
+ directory will possibly be determined and used. |
+ |
+ realuser and password arguments are the credentials to use for |
+ managing anonymous sessions. |
+ The same behaviour is followed in IIS where the Guest account |
+ is used to do so (note: it must be enabled first). |
+ """ |
+ users = [entry['name'] for entry in win32net.NetUserEnum(None, 0)[0]] |
+ if not realuser in users: |
+ raise ftpserver.AuthorizerError('No such user "%s".' %realuser) |
+ if not homedir: |
+ homedir = get_profile_dir(realuser) |
+ # make sure provided credentials are valid, otherwise an exception |
+ # will be thrown; to do so we actually impersonate the user |
+ self.impersonate_user(realuser, password) |
+ self.terminate_impersonation() |
+ ftpserver.DummyAuthorizer.add_anonymous(self, homedir, **kwargs) |
+ self.anon_user = realuser |
+ self.anon_pwd = password |
+ |
+ def validate_authentication(self, username, password): |
+ if (username == "anonymous") and self.has_user('anonymous'): |
+ username = self.anon_user |
+ password = self.anon_pwd |
+ try: |
+ win32security.LogonUser(username, None, password, |
+ win32con.LOGON32_LOGON_INTERACTIVE, |
+ win32con.LOGON32_PROVIDER_DEFAULT) |
+ return True |
+ except pywintypes.error: |
+ return False |
+ |
+ def impersonate_user(self, username, password): |
+ if (username == "anonymous") and self.has_user('anonymous'): |
+ username = self.anon_user |
+ password = self.anon_pwd |
+ handler = win32security.LogonUser(username, None, password, |
+ win32con.LOGON32_LOGON_INTERACTIVE, |
+ win32con.LOGON32_PROVIDER_DEFAULT) |
+ win32security.ImpersonateLoggedOnUser(handler) |
+ handler.Close() |
+ |
+ def terminate_impersonation(self): |
+ win32security.RevertToSelf() |
+ |
+ |
+if __name__ == "__main__": |
+ authorizer = WinNtAuthorizer() |
+ # add a user (note: user must already exists) |
+ authorizer.add_user('user', perm='elradfmw') |
+ # add an anonymous user using Guest account to handle the anonymous |
+ # sessions (note: Guest must be enabled first) |
+ authorizer.add_anonymous(os.getcwd()) |
+ ftp_handler = ftpserver.FTPHandler |
+ ftp_handler.authorizer = authorizer |
+ address = ('', 21) |
+ ftpd = ftpserver.FTPServer(address, ftp_handler) |
+ ftpd.serve_forever() |