前一段时间因为版权的原因,停用了SERV-U服务。但是ftp的服务不能停止,所以不得不自己动手写一个。但是由于时间原因,无法完全认真去看协议,所以希望利用现有的模块。这类模块在perl和python中都有,不过我差不多有半年没碰perl了,自然选择了python。除了几个无关紧要的bug,这个模块基本能满足日常使用。只是用户信息的存储不是很保险,如果存到数据库中总能好一些。密码则参照范例中的md5码例子进行加密。这个程序暂时还凑或使用,之后还需加入按用户的流控和空间分配。这个程序的cpu使用率有一点高,将近15%的样子-_-!
1
#
-*- coding: gbk -*-
2
3
import
md5, os
4
from
pyftpdlib
import
ftpserver
5
from
pysqlite2
import
dbapi2 as sqlite
6
7
class
Perm(object):
8
#
建立用于存储用户权限的类
9
def
__init__
(self, r
=
''
, w
=
''
):
10
self.r, self.w
=
str(r), str(w)
11
12
def
__repr__
(self):
13
if
self.w:
14
return
"
%c;%c
"
%
(self.r, self.w)
15
else
:
16
return
"
%c;
"
%
(self.r, )
17
18
def
adapt_perm(perm):
19
#
这个函数将权限类转换为sqlite支持的数据类型
20
if
perm.w:
21
return
"
%c;%c
"
%
(perm.r, perm.w)
22
else
:
23
return
"
%c;
"
%
(perm.r, )
24
25
sqlite.register_adapter(Perm, adapt_perm)
#
注册以上这个函数
26
27
class
DummyMD5Authorizer(ftpserver.DummyAuthorizer):
28
29
users_table
=
{ }
#
ftp运行时维护的用户信息表
30
31
def
__init__
(self):
32
#
初始化ftp用户管理类,并从sqlite数据库中读入用户信息
33
ftpserver.DummyAuthorizer.
__init__
(self)
34
self.sqlite_fetch_all()
35
36
def
sqlite_conn(self):
37
#
返回sqlite数据库连接对象,如未检测到数据库,则新建一个
38
dbpath
=
'
%s\\users.db
'
%
os.getcwd()
39
if
os.path.isfile(dbpath):
40
return
sqlite.connect(dbpath, isolation_level
=
None)
41
else
:
42
conn
=
sqlite.connect(dbpath, isolation_level
=
None, detect_types
=
sqlite.PARSE_DECLTYPES)
43
cursor
=
conn.cursor()
44
#
建立名为users的表,用来存储用户信息
45
cursor.execute(
"""
CREATE TABLE users(
46
username text primary key,
47
password text,
48
home text,
49
perm perm,
50
msg_login text,
51
msg_quit text
52
)
"""
)
53
cursor.close()
54
return
conn
55
56
def
sqlite_fetch_all(self):
57
#
提取用户信息
58
conn
=
self.sqlite_conn()
59
cursor
=
conn.cursor()
60
cursor.execute(
'
select * from users
'
)
61
for
eachresult
in
cursor.fetchall():
62
username, password, home, perm, msg_login, msg_quit
=
eachresult
63
perm
=
perm.split(
"
;
"
)
64
ftpserver.DummyAuthorizer.add_user(self, username, password, home, perm, msg_login, msg_quit)
65
cursor.close()
66
conn.close()
67
68
def
add_user(self, username, password, homedir, perm
=
(
'
r
'
),
69
msg_login
=
"
Login successful.
"
, msg_quit
=
"
Goodbye.
"
):
70
#
增加用户,分别添加到数据库和ftp运行过程中维护的用户信息表
71
try
:
72
password
=
md5.new(password).hexdigest()
73
ftpserver.DummyAuthorizer.add_user(self, username, password, homedir, perm, msg_login, msg_quit)
74
except
Exception, e:
75
print
e
76
return
77
self.sqlite_insert_user(username, password, homedir, perm, msg_login, msg_quit)
78
79
def
sqlite_insert_user(self, username, password, homedir, perm
=
(
'
r
'
),
80
msg_login
=
"
Login successful.
"
, msg_quit
=
"
Goodbye.
"
):
81
#
将用户信息插入sqlite数据库
82
conn
=
self.sqlite_conn()
83
cursor
=
conn.cursor()
84
cursor.execute(
'
insert into users values(?, ?, ?, ?, ?, ?)
'
85
, (username, password, homedir, Perm(
*
perm), msg_login, msg_quit))
86
cursor.close()
87
conn.close()
88
89
def
validate_authentication(self, username, password):
90
#
使用md5骂验证用户密码
91
hash
=
md5.new(password).hexdigest()
92
return
self.user_table[username][
'
pwd
'
]
==
hash
93
94
def
user_info():
95
#
在该函数中填入用户信息,使用后删除即可。当然一个更好的办法是建立一个
96
#
可填入用户信息的GUI界面,这个我已着手写了。
97
pass
98
99
100
#
测试代码
101
if
__name__
==
'
__main__
'
:
102
authorizer
=
DummyMD5Authorizer()
103
authorizer.add_anonymous(
'
E:\\FTPSite\\share
'
)
104
#
for eachuser,eachpwd, eachdir, eachperm in user_info():
105
#
authorizer.add_user(eachuser,eachpwd, eachdir, eachperm)
106
ftp_handler
=
ftpserver.FTPHandler
107
ftp_handler.authorizer
=
authorizer
108
ftp_handler.banner
=
'
pyftpdlib %s based ftpd ready
'
%
ftpserver.
__ver__
109
addr
=
(
''
,
21
)
110
ftpd
=
ftpserver.FTPServer(addr, ftp_handler)
111
ftpd.max_cons
=
256
112
ftpd.max_cons_per_ip
=
5
113
ftpd.serve_forever()
114
做了一些小修改
1import md5, os
2from pyftpdlib import ftpserver
3from pysqlite2 import dbapi2 as sqlite
4
5class DummyMD5Authorizer(ftpserver.DummyAuthorizer):
6
7 users_table = { }
8
9 def __init__(self):
10 ftpserver.DummyAuthorizer.__init__(self)
11 self.sqlite_fetch_all()
12
13 def sqlite_conn(self):
14 dbpath = '%s\\users.db' % os.getcwd()
15 if os.path.isfile(dbpath):
16 return sqlite.connect(dbpath, isolation_level = None)
17 else:
18 conn = sqlite.connect(dbpath, isolation_level = None, detect_types=sqlite.PARSE_DECLTYPES)
19 cursor = conn.cursor()
20 cursor.execute("""CREATE TABLE users(
21 username text primary key,
22 password text,
23 home text,
24 perm text,
25 msg_login text,
26 msg_quit text
27 )""")
28 cursor.close()
29 return conn
30
31 def sqlite_fetch_all(self):
32 conn = self.sqlite_conn()
33 cursor = conn.cursor()
34 cursor.execute('select * from users')
35 for eachresult in cursor.fetchall():
36 username, password, home, perm, msg_login, msg_quit = eachresult
37 perm = perm.split(";")
38 ftpserver.DummyAuthorizer.add_user(self, username, password, home, perm, msg_login, msg_quit)
39 cursor.close()
40 conn.close()
41
42 def add_user(self, username, password, homedir, perm = 'r;',
43 msg_login = "Login successful.", msg_quit = "Goodbye."):
44 try:
45 password = md5.new(password).hexdigest()
46 ftpserver.DummyAuthorizer.add_user(self, username, password, homedir, perm.split(';'), msg_login, msg_quit)
47 except Exception, e:
48 print e
49 return
50 self.sqlite_insert_user(username, password, homedir, perm, msg_login, msg_quit)
51
52 def sqlite_insert_user(self, username, password, homedir, perm = 'r;' ,
53 msg_login="Login successful.", msg_quit="Goodbye."):
54 conn = self.sqlite_conn()
55 cursor = conn.cursor()
56 cursor.execute('insert into users values(?, ?, ?, ?, ?, ?)'
57 , (username, password, homedir, perm, msg_login, msg_quit))
58 cursor.close()
59 conn.close()
60
61 def validate_authentication(self, username, password):
62 hash = md5.new(password).hexdigest()
63 return self.user_table[username]['pwd'] == hash
64
65if __name__ == '__main__':
66 authorizer = DummyMD5Authorizer()
67 ftp_handler = ftpserver.FTPHandler
68 ftp_handler.authorizer = authorizer
69 ftp_handler.banner = 'pyftpdlib %s based ftpd ready' % ftpserver.__ver__
70 addr = ('', 21)
71 ftpd = ftpserver.FTPServer(addr, ftp_handler)
72 ftpd.max_cons = 256
73 ftpd.max_cons_per_ip = 5
74 ftpd.serve_forever()
75