180 |
180 |
181 def _md5_hash(password, scheme, encoding, user=None): |
181 def _md5_hash(password, scheme, encoding, user=None): |
182 """Generates DIGEST-MD5 aka PLAIN-MD5 and LDAP-MD5 hashes.""" |
182 """Generates DIGEST-MD5 aka PLAIN-MD5 and LDAP-MD5 hashes.""" |
183 md5 = hashlib.md5() |
183 md5 = hashlib.md5() |
184 if scheme == 'DIGEST-MD5': |
184 if scheme == 'DIGEST-MD5': |
185 # Prior to Dovecot v1.1.12/v1.2.beta2 there was a problem with a |
185 md5.update(user.localpart.encode() + b':' + |
186 # empty auth_realms setting in dovecot.conf and user@domain.tld |
186 user.domainname.encode() + b':') |
187 # usernames. So we have to generate different hashes for different |
|
188 # versions. See also: |
|
189 # http://dovecot.org/list/dovecot-news/2009-March/000103.html |
|
190 # http://hg.dovecot.org/dovecot-1.1/rev/2b0043ba89ae |
|
191 if cfg_dget('misc.dovecot_version') >= 0x1010cf00: |
|
192 md5.update(user.localpart.encode() + b':' + |
|
193 user.domainname.encode() + b':') |
|
194 else: |
|
195 raise VMMError('You will need Dovecot >= v1.2.0 for proper ' |
|
196 'functioning digest-md5 authentication.', VMM_ERROR) |
|
197 md5.update(password) |
187 md5.update(password) |
198 if (scheme in ('PLAIN-MD5', 'DIGEST-MD5') and encoding in DEFAULT_HEX) or \ |
188 if (scheme in ('PLAIN-MD5', 'DIGEST-MD5') and encoding in DEFAULT_HEX) or \ |
199 (scheme == 'LDAP-MD5' and encoding == 'HEX'): |
189 (scheme == 'LDAP-MD5' and encoding == 'HEX'): |
200 digest = md5.hexdigest() |
190 digest = md5.hexdigest() |
201 else: |
191 else: |
327 def list_schemes(): |
317 def list_schemes(): |
328 """Returns the tuple (schemes, encodings). |
318 """Returns the tuple (schemes, encodings). |
329 |
319 |
330 `schemes` is an iterator for all supported password schemes (depends on |
320 `schemes` is an iterator for all supported password schemes (depends on |
331 the used Dovecot version and features of the libc). |
321 the used Dovecot version and features of the libc). |
332 `encodings` is a tuple with all usable encoding suffixes. The tuple may |
322 `encodings` is a tuple with all usable encoding suffixes. |
333 be empty. |
|
334 """ |
323 """ |
335 dcv = cfg_dget('misc.dovecot_version') |
324 dcv = cfg_dget('misc.dovecot_version') |
336 schemes = (k for (k, v) in _scheme_info.items() if v[1] <= dcv) |
325 schemes = (k for (k, v) in _scheme_info.items() if v[1] <= dcv) |
337 encodings = ('.B64', '.BASE64', '.HEX') if dcv >= 0x10100a01 else () |
326 encodings = ('.B64', '.BASE64', '.HEX') |
338 return schemes, encodings |
327 return schemes, encodings |
339 |
328 |
340 |
329 |
341 def verify_scheme(scheme): |
330 def verify_scheme(scheme): |
342 """Checks if the password scheme *scheme* is known and supported by the |
331 """Checks if the password scheme *scheme* is known and supported by the |
363 raise VMMError(_("The password scheme '%(scheme)s' requires Dovecot " |
352 raise VMMError(_("The password scheme '%(scheme)s' requires Dovecot " |
364 ">= v%(version)s.") % {'scheme': scheme, |
353 ">= v%(version)s.") % {'scheme': scheme, |
365 'version': version_str(_scheme_info[scheme][1])}, |
354 'version': version_str(_scheme_info[scheme][1])}, |
366 VMM_ERROR) |
355 VMM_ERROR) |
367 if len(scheme_encoding) > 1: |
356 if len(scheme_encoding) > 1: |
368 if cfg_dget('misc.dovecot_version') < 0x10100a01: |
|
369 raise VMMError(_('Encoding suffixes for password schemes require ' |
|
370 'Dovecot >= v1.1.alpha1.'), VMM_ERROR) |
|
371 if scheme_encoding[1] not in ('B64', 'BASE64', 'HEX'): |
357 if scheme_encoding[1] not in ('B64', 'BASE64', 'HEX'): |
372 raise VMMError(_("Unsupported password encoding: '%s'") % |
358 raise VMMError(_("Unsupported password encoding: '%s'") % |
373 scheme_encoding[1], VMM_ERROR) |
359 scheme_encoding[1], VMM_ERROR) |
374 encoding = scheme_encoding[1] |
360 encoding = scheme_encoding[1] |
375 else: |
361 else: |