54 _sys_rand = SystemRandom() |
54 _sys_rand = SystemRandom() |
55 _choice = _sys_rand.choice |
55 _choice = _sys_rand.choice |
56 _get_salt = lambda s_len: ''.join(_choice(SALTCHARS) for x in range(s_len)) |
56 _get_salt = lambda s_len: ''.join(_choice(SALTCHARS) for x in range(s_len)) |
57 |
57 |
58 |
58 |
59 def _dovecotpw(password, scheme, encoding): |
59 def _doveadmpw(password, scheme, encoding): |
60 """Communicates with dovecotpw (Dovecot 2.0: `doveadm pw`) and returns |
60 """Communicates with Dovecot's doveadm and returns |
61 the hashed password: {scheme[.encoding]}hash |
61 the hashed password: {scheme[.encoding]}hash |
62 """ |
62 """ |
63 if encoding: |
63 if encoding: |
64 scheme = '.'.join((scheme, encoding)) |
64 scheme = '.'.join((scheme, encoding)) |
65 cmd_args = [cfg_dget('bin.dovecotpw'), '-s', scheme, '-p', |
65 cmd_args = [cfg_dget('bin.doveadm'), 'pw', '-s', scheme, '-p', |
66 get_unicode(password)] |
66 get_unicode(password)] |
67 if cfg_dget('misc.dovecot_version') >= 0x20000a01: |
|
68 cmd_args.insert(1, 'pw') |
|
69 process = Popen(cmd_args, stdout=PIPE, stderr=PIPE) |
67 process = Popen(cmd_args, stdout=PIPE, stderr=PIPE) |
70 stdout, stderr = process.communicate() |
68 stdout, stderr = process.communicate() |
71 if process.returncode: |
69 if process.returncode: |
72 raise VMMError(stderr.strip().decode(ENCODING), VMM_ERROR) |
70 raise VMMError(stderr.strip().decode(ENCODING), VMM_ERROR) |
73 hashed = stdout.strip().decode(ENCODING) |
71 hashed = stdout.strip().decode(ENCODING) |
74 if not hashed.startswith('{%s}' % scheme): |
72 if not hashed.startswith('{%s}' % scheme): |
75 raise VMMError('Unexpected result from %s: %s' % |
73 raise VMMError('Unexpected result from %s: %s' % |
76 (cfg_dget('bin.dovecotpw'), hashed), VMM_ERROR) |
74 (cfg_dget('bin.doveadm'), hashed), VMM_ERROR) |
77 return hashed |
75 return hashed |
78 |
76 |
79 |
77 |
80 def _md4_new(): |
78 def _md4_new(): |
81 """Returns an new MD4-hash object if supported by the hashlib - |
79 """Returns an new MD4-hash object if supported by the hashlib - |
173 if encoding in DEFAULT_HEX: |
171 if encoding in DEFAULT_HEX: |
174 digest = md4.hexdigest() |
172 digest = md4.hexdigest() |
175 else: |
173 else: |
176 digest = b64encode(md4.digest()).decode() |
174 digest = b64encode(md4.digest()).decode() |
177 return _format_digest(digest, scheme, encoding) |
175 return _format_digest(digest, scheme, encoding) |
178 return _dovecotpw(password, scheme, encoding) |
176 return _doveadmpw(password, scheme, encoding) |
179 |
177 |
180 |
178 |
181 def _md5_hash(password, scheme, encoding, user=None): |
179 def _md5_hash(password, scheme, encoding, user=None): |
182 """Generates DIGEST-MD5 aka PLAIN-MD5 and LDAP-MD5 hashes.""" |
180 """Generates DIGEST-MD5 aka PLAIN-MD5 and LDAP-MD5 hashes.""" |
183 md5 = hashlib.md5() |
181 md5 = hashlib.md5() |
203 if encoding in DEFAULT_HEX: |
201 if encoding in DEFAULT_HEX: |
204 digest = md4.hexdigest() |
202 digest = md4.hexdigest() |
205 else: |
203 else: |
206 digest = b64encode(md4.digest()).decode() |
204 digest = b64encode(md4.digest()).decode() |
207 return _format_digest(digest, scheme, encoding) |
205 return _format_digest(digest, scheme, encoding) |
208 return _dovecotpw(password, scheme, encoding) |
206 return _doveadmpw(password, scheme, encoding) |
209 |
207 |
210 |
208 |
211 def _sha1_hash(password, scheme, encoding): |
209 def _sha1_hash(password, scheme, encoding): |
212 """Generates SHA1 aka SHA hashes.""" |
210 """Generates SHA1 aka SHA hashes.""" |
213 sha1 = hashlib.sha1(password) |
211 sha1 = hashlib.sha1(password) |
285 return _format_digest(digest, scheme, encoding) |
283 return _format_digest(digest, scheme, encoding) |
286 |
284 |
287 _scheme_info = { |
285 _scheme_info = { |
288 'CLEAR': (_clear_hash, 0x2010df00), |
286 'CLEAR': (_clear_hash, 0x2010df00), |
289 'CLEARTEXT': (_clear_hash, 0x10000f00), |
287 'CLEARTEXT': (_clear_hash, 0x10000f00), |
290 'CRAM-MD5': (_dovecotpw, 0x10000f00), |
288 'CRAM-MD5': (_doveadmpw, 0x10000f00), |
291 'CRYPT': (_crypt_hash, 0x10000f00), |
289 'CRYPT': (_crypt_hash, 0x10000f00), |
292 'DIGEST-MD5': (_md5_hash, 0x10000f00), |
290 'DIGEST-MD5': (_md5_hash, 0x10000f00), |
293 'HMAC-MD5': (_dovecotpw, 0x10000f00), |
291 'HMAC-MD5': (_doveadmpw, 0x10000f00), |
294 'LANMAN': (_dovecotpw, 0x10000f00), |
292 'LANMAN': (_doveadmpw, 0x10000f00), |
295 'LDAP-MD5': (_md5_hash, 0x10000f00), |
293 'LDAP-MD5': (_md5_hash, 0x10000f00), |
296 'MD5': (_crypt_hash, 0x10000f00), |
294 'MD5': (_crypt_hash, 0x10000f00), |
297 'MD5-CRYPT': (_crypt_hash, 0x10000f00), |
295 'MD5-CRYPT': (_crypt_hash, 0x10000f00), |
298 'NTLM': (_ntlm_hash, 0x10000f00), |
296 'NTLM': (_ntlm_hash, 0x10000f00), |
299 'OTP': (_dovecotpw, 0x10100a01), |
297 'OTP': (_doveadmpw, 0x10100a01), |
300 'PLAIN': (_clear_hash, 0x10000f00), |
298 'PLAIN': (_clear_hash, 0x10000f00), |
301 'PLAIN-MD4': (_md4_hash, 0x10000f00), |
299 'PLAIN-MD4': (_md4_hash, 0x10000f00), |
302 'PLAIN-MD5': (_md5_hash, 0x10000f00), |
300 'PLAIN-MD5': (_md5_hash, 0x10000f00), |
303 'RPA': (_dovecotpw, 0x10000f00), |
301 'RPA': (_doveadmpw, 0x10000f00), |
304 'SCRAM-SHA-1': (_dovecotpw, 0x20200a01), |
302 'SCRAM-SHA-1': (_doveadmpw, 0x20200a01), |
305 'SHA': (_sha1_hash, 0x10000f00), |
303 'SHA': (_sha1_hash, 0x10000f00), |
306 'SHA1': (_sha1_hash, 0x10000f00), |
304 'SHA1': (_sha1_hash, 0x10000f00), |
307 'SHA256': (_sha256_hash, 0x10100a01), |
305 'SHA256': (_sha256_hash, 0x10100a01), |
308 'SHA512': (_sha512_hash, 0x20000b03), |
306 'SHA512': (_sha512_hash, 0x20000b03), |
309 'SKEY': (_dovecotpw, 0x10100a01), |
307 'SKEY': (_doveadmpw, 0x10100a01), |
310 'SMD5': (_smd5_hash, 0x10000f00), |
308 'SMD5': (_smd5_hash, 0x10000f00), |
311 'SSHA': (_ssha1_hash, 0x10000f00), |
309 'SSHA': (_ssha1_hash, 0x10000f00), |
312 'SSHA256': (_ssha256_hash, 0x10200a04), |
310 'SSHA256': (_ssha256_hash, 0x10200a04), |
313 'SSHA512': (_ssha512_hash, 0x20000b03), |
311 'SSHA512': (_ssha512_hash, 0x20000b03), |
314 } |
312 } |