2 # -*- coding: UTF-8 -*-
3 # Depends: python-mysqldb
4 # install -o root -g ejabberd -m 0750 -c auth-mysql.py /etc/ejabberd/
5 # install -o ejabberd -g adm -m 0640 -c /dev/null /var/log/ejabberd/auth-mysql.log
6 # Test: printf '\000\031isuser:moussa.nombre:test' | ./auth-mysql.py | hd
15 # TODO: transformer toute la partie gestion de BdD en une classe
16 # TODO: connexion persistente et gérer les coupures de service MySQL
23 _query
= "SELECT * FROM auforg_virtual WHERE source=%s AND LENGTH(password)>1"
24 _log_filename
= '/var/log/ejabberd/auth-mysql.log'
25 _cache_positive_ttl
= (15*60)
26 _cache_negative_ttl
= (1*60)
28 # ce qui suit est à usage interne, ne pas toucher...
30 _authenticate_user_cache
= {}
32 def find_user(user
, host
):
34 Returns (found, in_cache)
35 where 'found' means the (user,host) was found in the database
36 and 'in_cache' means it was found from the local cache
40 global _find_user_cache
41 c
= _find_user_cache
.get((user
,host
))
43 if c
['found'] and now
< (c
['time'] + _cache_positive_ttl
):
45 if not c
['found'] and now
< (c
['time'] + _cache_negative_ttl
):
48 global _host
, _user
, _passwd
, _db
49 db
= MySQLdb
.connect(host
=_host
, user
=_user
, passwd
=_passwd
,
50 db
=_db
, connect_timeout
=_timeout
)
51 cur
= db
.cursor(MySQLdb
.cursors
.DictCursor
)
52 nrows
= cur
.execute(_query
, ('%s@%s' % (user
,host
), ))
55 _find_user_cache
[(user
,host
)] = {'found': found
, 'time': now
}
58 def authenticate_user(user
, host
, password
):
60 Returns (valid, in_cache)
61 where 'valid' means the (user,host,password) was valid in the database
62 and 'in_cache' means it was validated against the local cache
66 global _authenticate_user_cache
67 c
= _authenticate_user_cache
.get((user
,host
,password
))
69 if c
['valid'] and now
< (c
['time'] + _cache_positive_ttl
):
71 if not c
['valid'] and now
< (c
['time'] + _cache_negative_ttl
):
74 global _host
, _user
, _passwd
, _db
75 db
= MySQLdb
.connect(host
=_host
, user
=_user
, passwd
=_passwd
,
76 db
=_db
, connect_timeout
=_timeout
)
77 cur
= db
.cursor(MySQLdb
.cursors
.DictCursor
)
78 nrows
= cur
.execute(_query
, ('%s@%s' % (user
,host
), ))
79 users
= cur
.fetchall()
84 if crypt
.crypt(password
, u
['password']) == u
['password']:
87 _authenticate_user_cache
[(user
,host
,password
)] = {'valid': valid
, 'time': now
}
91 log_file
= open(_log_filename
, 'a')
94 nread
= sys
.stdin
.read(2)
98 now
= time
.strftime('%Y/%m/%d %H:%M:%S', time
.localtime())
100 log_file
.write('%s bytes_read=%d\n' % (now
, len(nread
)))
103 size
= struct
.unpack('>h', nread
)[0]
104 data
= sys
.stdin
.read(size
)
105 (operation
, data
) = data
.split(':', 1)
106 if operation
== 'auth':
107 (user
, host
, password
) = data
.split(':', 2)
108 log_file
.write('%s operation=%s user=%s host=%s\n'
109 % (now
, operation
, user
, host
))
111 (result
, in_cache
) = authenticate_user(user
, host
, password
)
112 elif operation
== 'isuser':
113 (user
, host
) = data
.split(':', 1)
114 log_file
.write('%s operation=%s user=%s host=%s\n'
115 % (now
, operation
, user
, host
))
117 (result
, in_cache
) = find_user(user
, host
)
118 elif operation
== 'setpass':
119 (user
, host
, password
) = data
.split(':', 2)
120 log_file
.write('%s operation=%s user=%s host=%s\n'
121 % (now
, operation
, user
, host
))
123 #result = set_user_password(user, host, password)
130 in_cache
= ' (from cache)'
133 log_file
.write('%s => result=%s%s\n' % (now
, result
, in_cache
))
135 sys
.stdout
.write(struct
.pack('>hh', 2, result
and 1 or 0))
138 traceback
.print_exc(file=log_file
)
141 if __name__
== '__main__':