password-scheme.c revision e14ccef85097644c0c9de49d87cbcd67d1ad539b
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenstatic const char salt_chars[] =
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
b624773984e35dd894db8dff976c1a2114c70782Timo SirainenARRAY_TYPE(password_scheme_p) password_schemes;
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainenstatic const struct password_scheme *
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int i, count;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen schemes = array_get(&password_schemes, &count);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < count; i++) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen/* Lookup scheme and encoding by given name. The encoding is taken from
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen ".base64", ".b64" or ".hex" suffix if it exists, otherwise the default
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen encoding is used. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic const struct password_scheme *
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenpassword_scheme_lookup(const char *name, enum password_encoding *encoding_r)
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen for (scheme_len = 0; name[scheme_len] != '\0'; scheme_len++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* unknown encoding. treat as invalid scheme. */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenint password_verify(const char *plaintext, const char *user, const char *scheme,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *raw_password, size_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct password_scheme *s;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *generated;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen s = password_scheme_lookup(scheme, &encoding);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return s->password_verify(plaintext, user, raw_password, size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* generic verification handler: generate the password and compare it
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen to the one in database */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen s->password_generate(plaintext, user, &generated, &generated_size);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainenconst char *password_get_scheme(const char **password)
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen const char *p, *scheme;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* $1$<salt>$<password>[$<ignored>] */
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen /* stop at next '$' after password */
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen return "MD5-CRYPT";
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainenint password_decode(const char *password, const char *scheme,
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen const struct password_scheme *s;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen unsigned int len;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen s = password_scheme_lookup(scheme, &encoding);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen if (encoding != PW_ENCODING_NONE && s->raw_password_len != 0 &&
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* encoding not specified. we can guess quite well between
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen base64 and hex encodings. the only problem is distinguishing
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen 2 character strings, but there shouldn't be any that short
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen raw_password_lens. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen encoding = len == s->raw_password_len * 2 ? PW_ENCODING_HEX :
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *raw_password_r = (const unsigned char *)password;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen buf = buffer_create_static_hard(pool_datastack_create(),
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen /* fall through, just in case it was base64-encoded after
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen all. some input lengths produce matching hex and base64
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen encoded lengths. */
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen buf = buffer_create_static_hard(pool_datastack_create(),
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (base64_decode(password, len, NULL, buf) < 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (s->raw_password_len != *size_r && s->raw_password_len != 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* password has invalid length */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainenbool password_generate(const char *plaintext, const char *user,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const struct password_scheme *s;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen s = password_scheme_lookup(scheme, &encoding);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen s->password_generate(plaintext, user, raw_password_r, size_r);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainenbool password_generate_encoded(const char *plaintext, const char *user,
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen const struct password_scheme *s;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen const unsigned char *raw_password;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen s = password_scheme_lookup(scheme, &encoding);
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen s->password_generate(plaintext, user, &raw_password, &size);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(size) + 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *password_r = binary_to_hex(raw_password, size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenbool password_scheme_is_alias(const char *scheme1, const char *scheme2)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct password_scheme *const *schemes, *s1 = NULL, *s2 = NULL;
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen unsigned int i, count;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen schemes = array_get(&password_schemes, &count);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen for (i = 0; i < count; i++) {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (strcasecmp(schemes[i]->name, scheme1) == 0)
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen else if (strcasecmp(schemes[i]->name, scheme2) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* if they've the same generate function, they're equivalent */
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen s1->password_generate == s2->password_generate;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainencrypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *raw_password, size_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* the default mycrypt() handler would return match */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return strcmp(mycrypt(plaintext, password), password) == 0;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainencrypt_generate(const char *plaintext, const char *user ATTR_UNUSED,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen salt[0] = salt_chars[salt[0] % (sizeof(salt_chars)-1)];
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen salt[1] = salt_chars[salt[1] % (sizeof(salt_chars)-1)];
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen password = t_strdup(mycrypt(plaintext, salt));
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen *raw_password_r = (const unsigned char *)password;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenmd5_verify(const char *plaintext, const char *user,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen const unsigned char *raw_password, size_t size)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const unsigned char *md5_password;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen /* MD5-CRYPT */
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen str = password_generate_md5_crypt(plaintext, password);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return password_verify(plaintext, user, "PLAIN-MD5",
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenmd5_crypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const unsigned char *raw_password, size_t size)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen str = password_generate_md5_crypt(plaintext, password);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenmd5_crypt_generate(const char *plaintext, const char *user ATTR_UNUSED,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen unsigned int i;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)];
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen password = password_generate_md5_crypt(plaintext, salt);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen *raw_password_r = (const unsigned char *)password;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainensha1_generate(const char *plaintext, const char *user ATTR_UNUSED,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen unsigned char *digest;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen sha1_get_digest(plaintext, strlen(plaintext), digest);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainensha256_generate(const char *plaintext, const char *user ATTR_UNUSED,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen unsigned char *digest;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen sha256_get_digest(plaintext, strlen(plaintext), digest);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenssha_generate(const char *plaintext, const char *user ATTR_UNUSED,
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen digest = t_malloc(SHA1_RESULTLEN + SSHA_SALT_LEN);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen sha1_loop(&ctx, plaintext, strlen(plaintext));
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic bool ssha_verify(const char *plaintext, const char *user,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *raw_password, size_t size)
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen /* format: <SHA1 hash><salt> */
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen i_error("ssha_verify(%s): SSHA password too short", user);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen sha1_loop(&ctx, plaintext, strlen(plaintext));
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen sha1_loop(&ctx, raw_password + SHA1_RESULTLEN, size - SHA1_RESULTLEN);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return memcmp(sha1_digest, raw_password, SHA1_RESULTLEN) == 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenssha256_generate(const char *plaintext, const char *user ATTR_UNUSED,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen digest = t_malloc(SHA256_RESULTLEN + SSHA256_SALT_LEN);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen sha256_loop(&ctx, plaintext, strlen(plaintext));
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen *size_r = SHA256_RESULTLEN + SSHA256_SALT_LEN;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainenstatic bool ssha256_verify(const char *plaintext, const char *user,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen const unsigned char *raw_password, size_t size)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen unsigned char sha256_digest[SHA256_RESULTLEN];
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* format: <SHA256 hash><salt> */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("ssha256_verify(%s): SSHA256 password too short", user);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen sha256_loop(&ctx, plaintext, strlen(plaintext));
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen sha256_loop(&ctx, raw_password + SHA256_RESULTLEN,
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen return memcmp(sha256_digest, raw_password, SHA256_RESULTLEN) == 0;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainensmd5_generate(const char *plaintext, const char *user ATTR_UNUSED,
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen digest = t_malloc(MD5_RESULTLEN + SMD5_SALT_LEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_update(&ctx, plaintext, strlen(plaintext));
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic bool smd5_verify(const char *plaintext, const char *user,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const unsigned char *raw_password, size_t size)
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen /* format: <MD5 hash><salt> */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_error("smd5_verify(%s): SMD5 password too short", user);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen md5_update(&ctx, plaintext, strlen(plaintext));
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_update(&ctx, raw_password + MD5_RESULTLEN, size - MD5_RESULTLEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return memcmp(md5_digest, raw_password, MD5_RESULTLEN) == 0;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenplain_generate(const char *plaintext, const char *user ATTR_UNUSED,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *raw_password_r = (const unsigned char *)plaintext,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainencram_md5_generate(const char *plaintext, const char *user ATTR_UNUSED,
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned char *context_digest;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen context_digest = t_malloc(CRAM_MD5_CONTEXTLEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen hmac_md5_init(&ctx, (const unsigned char *)plaintext,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen hmac_md5_get_cram_context(&ctx, context_digest);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainendigest_md5_generate(const char *plaintext, const char *user,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen unsigned char *digest;
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen i_fatal("digest_md5_generate(): username not given");
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen /* user:realm:passwd */
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen str = t_strdup_printf("%s:%s:%s", t_strcut(user, '@'),
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenplain_md4_generate(const char *plaintext, const char *user ATTR_UNUSED,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned char *digest;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md4_get_digest(plaintext, strlen(plaintext), digest);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenplain_md5_generate(const char *plaintext, const char *user ATTR_UNUSED,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen unsigned char *digest;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_get_digest(plaintext, strlen(plaintext), digest);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenlm_generate(const char *plaintext, const char *user ATTR_UNUSED,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen unsigned char *digest;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenntlm_generate(const char *plaintext, const char *user ATTR_UNUSED,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen unsigned char *digest;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic bool otp_verify(const char *plaintext, const char *user ATTR_UNUSED,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen const unsigned char *raw_password, size_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen password_generate_otp(plaintext, password, -1)) == 0;
459b483806babd159daa8b461377281d89bb3bdcTimo Sirainenotp_generate(const char *plaintext, const char *user ATTR_UNUSED,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen password = password_generate_otp(plaintext, NULL, OTP_HASH_SHA1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *raw_password_r = (const unsigned char *)password;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenskey_generate(const char *plaintext, const char *user ATTR_UNUSED,
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen password = password_generate_otp(plaintext, NULL, OTP_HASH_MD4);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen *raw_password_r = (const unsigned char *)password;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainenrpa_generate(const char *plaintext, const char *user ATTR_UNUSED,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen unsigned char *digest;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenstatic const struct password_scheme builtin_schemes[] = {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "CRYPT", PW_ENCODING_NONE, 0, crypt_verify, crypt_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "MD5", PW_ENCODING_NONE, 0, md5_verify, md5_crypt_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "SHA", PW_ENCODING_BASE64, SHA1_RESULTLEN, NULL, sha1_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "SHA1", PW_ENCODING_BASE64, SHA1_RESULTLEN, NULL, sha1_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "SHA256", PW_ENCODING_BASE64, SHA256_RESULTLEN,
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "SMD5", PW_ENCODING_BASE64, 0, smd5_verify, smd5_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "SSHA", PW_ENCODING_BASE64, 0, ssha_verify, ssha_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "SSHA256", PW_ENCODING_BASE64, 0, ssha256_verify, ssha256_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "PLAIN", PW_ENCODING_NONE, 0, NULL, plain_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "CLEARTEXT", PW_ENCODING_NONE, 0, NULL, plain_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "CRAM-MD5", PW_ENCODING_HEX, 0, NULL, cram_md5_generate },
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen { "HMAC-MD5", PW_ENCODING_HEX, CRAM_MD5_CONTEXTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "DIGEST-MD5", PW_ENCODING_HEX, MD5_RESULTLEN,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen { "PLAIN-MD4", PW_ENCODING_HEX, MD4_RESULTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "PLAIN-MD5", PW_ENCODING_HEX, MD5_RESULTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "LDAP-MD5", PW_ENCODING_BASE64, MD5_RESULTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "LANMAN", PW_ENCODING_HEX, LM_HASH_SIZE, NULL, lm_generate },
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen { "NTLM", PW_ENCODING_HEX, NTLMSSP_HASH_SIZE, NULL, ntlm_generate },
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "OTP", PW_ENCODING_NONE, 0, otp_verify, otp_generate },
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "SKEY", PW_ENCODING_NONE, 0, otp_verify, skey_generate },
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "RPA", PW_ENCODING_HEX, MD5_RESULTLEN, NULL, rpa_generate }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid password_scheme_register(const struct password_scheme *scheme)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (password_scheme_lookup_name(scheme->name) != NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_panic("password_scheme_register(%s): Already registered",
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenvoid password_scheme_unregister(const struct password_scheme *scheme)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen unsigned int i, count;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen schemes = array_get(&password_schemes, &count);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen for (i = 0; i < count; i++) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen if (strcasecmp(schemes[i]->name, scheme->name) == 0) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen i_panic("password_scheme_unregister(%s): Not registered", scheme->name);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen unsigned int i;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen i_array_init(&password_schemes, N_ELEMENTS(builtin_schemes) + 4);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen for (i = 0; i < N_ELEMENTS(builtin_schemes); i++)