2 from __future__ import print_function
3 import os, cgi, MySQLdb, subprocess, time
8 DB_PW = '{{postfix.dovecot.mysql_password}}'
11 db = MySQLdb.connect(user=DB_USER, passwd=DB_PW, db=DB_NAME, charset='utf8')
13 def db_execute(query, args):
14 cursor = db.cursor(MySQLdb.cursors.DictCursor)
15 if len(args) == 1 and isinstance(args[0], dict): args = args[0] # einzelnes dict weiterreichen
16 cursor.execute(query, args)
19 def db_fetch_one_row(query, *args):
20 cursor = db_execute(query, args)
21 result = cursor.fetchone()
22 if cursor.fetchone() is not None:
23 raise Exception("Found more than one result, only one was expected")
27 def db_run(query, *args):
28 cursor = db_execute(query, args)
32 return db_fetch_one_row('SELECT * FROM users WHERE username=%s', name)
34 def change_user_pw(name, hash):
35 db_run('UPDATE users SET password=%s WHERE username=%s', hash, name)
37 def change_user_active(name, active):
38 db_run('UPDATE users SET active=%s WHERE username=%s', int(active), name)
40 # interaction with dbadm pw
41 def compare_pw(hash, plain):
43 subprocess.check_output(["doveadm", "pw", "-t", hash, "-p", plain])
45 except subprocess.CalledProcessError:
49 return subprocess.check_output(["doveadm", "pw", "-s", "SHA512-CRYPT", "-r", str(64*1024), "-p", plain]).decode('utf-8').strip()
52 def act(user, oldpw, newpw1, newpw2):
53 if user is None and oldpw is None and newpw1 is None and newpw2 is None:
55 if user is None or oldpw is None or newpw1 is None or newpw2 is None:
56 return "<b>Error</b>: You have to fill all the fields."
57 curdata = get_user(user)
59 return "<b>Error</b>: User not found."
61 return "<b>Error</b>: Password must be at least 8 characters long."
63 return "<b>Error</b>: New passwords do not match."
64 # slow down brute-force attacks
67 if not compare_pw(curdata['password'], oldpw):
68 return "<b>Error</b>: Old PW is wrong."
69 new_hash = gen_hash(newpw1)
70 change_user_pw(user, new_hash)
71 # potentially enable this user
72 if curdata['active'] < 0:
73 change_user_active(user, -curdata['active'])
74 return "Password successfully changed."
77 print("Content-Type: text/html")
80 # print document header
81 print("<!DOCTYPE html>")
83 print(" <meta charset='utf-8'>")
84 print(" <title>User PW change</title>")
85 print(" <style type='text/css'> th { text-align: right; } </style>")
86 print("</head><body>")
89 form = cgi.FieldStorage()
90 msg = act(form.getfirst('user'), form.getfirst('oldpw'), form.getfirst('newpw1'), form.getfirst('newpw2'))
92 print("<p>{}</p>".format(msg))
95 print(" <form action='changepw' method='post'><table>")
96 print(" <tr><th>Username: </th><td><input type='text' name='user' placeholder='user@domain'></td>")
97 print(" <tr><th>Old Password: </th><td><input type='password' name='oldpw'></td>")
98 print(" <tr><th>New Password: </th><td><input type='password' name='newpw1'></td>")
99 print(" <tr><th>New Password (confirmation): </th><td><input type='password' name='newpw2'></td>")
100 print(" <tr><th></th><td><input type='submit' value='Change Password'></td></tr>")
101 print(" </table></form>")
102 print("</body></html>")