password-scheme.c revision e14ccef85097644c0c9de49d87cbcd67d1ad539b
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "lib.h"
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen#include "array.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "base64.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "hex-binary.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "md4.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "md5.h"
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen#include "hmac-md5.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "ntlm.h"
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen#include "mycrypt.h"
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#include "randgen.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "sha1.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "sha2.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "otp.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "str.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "password-scheme.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenstatic const char salt_chars[] =
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo SirainenARRAY_TYPE(password_scheme_p) password_schemes;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainenstatic const struct password_scheme *
12d38e76ba7f70d6219c89ec7416fea0d5de7e02Timo Sirainenpassword_scheme_lookup_name(const char *name)
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct password_scheme *const *schemes;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int i, count;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen schemes = array_get(&password_schemes, &count);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < count; i++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strcasecmp(schemes[i]->name, name) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return schemes[i];
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen return NULL;
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen}
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
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)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const struct password_scheme *scheme;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen const char *encoding = NULL;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned int scheme_len;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *encoding_r = PW_ENCODING_NONE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen for (scheme_len = 0; name[scheme_len] != '\0'; scheme_len++) {
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (name[scheme_len] == '.') {
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen encoding = name + scheme_len + 1;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen name = t_strndup(name, scheme_len);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen break;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen }
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen scheme = password_scheme_lookup_name(name);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (scheme == NULL)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen return NULL;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (encoding == NULL)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen *encoding_r = scheme->default_encoding;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen else if (strcasecmp(encoding, "b64") == 0 ||
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen strcasecmp(encoding, "base64") == 0)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen *encoding_r = PW_ENCODING_BASE64;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen else if (strcasecmp(encoding, "hex") == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *encoding_r = PW_ENCODING_HEX;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* unknown encoding. treat as invalid scheme. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return NULL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return scheme;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
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{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct password_scheme *s;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen enum password_encoding encoding;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *generated;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen size_t generated_size;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen s = password_scheme_lookup(scheme, &encoding);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (s == NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (s->password_verify != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return s->password_verify(plaintext, user, raw_password, size);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
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 Sirainen return size != generated_size ? 0 :
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen memcmp(generated, raw_password, size) == 0;
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen}
83d2e37f065eabe38dc92db485c5ca39ee43ce05Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainenconst char *password_get_scheme(const char **password)
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen{
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen const char *p, *scheme;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (*password == NULL)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen return NULL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(*password, "$1$", 3) == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* $1$<salt>$<password>[$<ignored>] */
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen p = strchr(*password + 3, '$');
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen if (p != NULL) {
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen /* stop at next '$' after password */
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen p = strchr(p+1, '$');
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen if (p != NULL)
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen *password = t_strdup_until(*password, p);
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen return "MD5-CRYPT";
3a7113e3e2dac0e333e1a3f62af7d682896f59c6Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen if (**password != '{')
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen return NULL;
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen p = strchr(*password, '}');
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen if (p == NULL)
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen return NULL;
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen
d6bffcdf187c155dccc04fb4267b4f82ce59347dTimo Sirainen scheme = t_strdup_until(*password + 1, p);
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen *password = p + 1;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen return scheme;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen}
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainenint password_decode(const char *password, const char *scheme,
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen{
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen const struct password_scheme *s;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen enum password_encoding encoding;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen buffer_t *buf;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen unsigned int len;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen s = password_scheme_lookup(scheme, &encoding);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen if (s == NULL)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen return 0;
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen len = strlen(password);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen if (encoding != PW_ENCODING_NONE && s->raw_password_len != 0 &&
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen strchr(scheme, '.') == NULL) {
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 :
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen PW_ENCODING_BASE64;
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen }
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen switch (encoding) {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen case PW_ENCODING_NONE:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *raw_password_r = (const unsigned char *)password;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen *size_r = len;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen break;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen case PW_ENCODING_HEX:
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen buf = buffer_create_static_hard(pool_datastack_create(),
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen len / 2 + 1);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (hex_to_binary(password, buf) == 0) {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen *raw_password_r = buf->data;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen *size_r = buf->used;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen break;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen }
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. */
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen case PW_ENCODING_BASE64:
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen buf = buffer_create_static_hard(pool_datastack_create(),
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen MAX_BASE64_DECODED_SIZE(len));
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (base64_decode(password, len, NULL, buf) < 0)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *raw_password_r = buf->data;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen *size_r = buf->used;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (s->raw_password_len != *size_r && s->raw_password_len != 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* password has invalid length */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 1;
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainenbool password_generate(const char *plaintext, const char *user,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen const char *scheme,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const struct password_scheme *s;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen enum password_encoding encoding;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen s = password_scheme_lookup(scheme, &encoding);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (s == NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen s->password_generate(plaintext, user, raw_password_r, size_r);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return TRUE;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainenbool password_generate_encoded(const char *plaintext, const char *user,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen const char *scheme, const char **password_r)
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen{
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen const struct password_scheme *s;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen const unsigned char *raw_password;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen enum password_encoding encoding;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen string_t *str;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen size_t size;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen s = password_scheme_lookup(scheme, &encoding);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (s == NULL)
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen return FALSE;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen s->password_generate(plaintext, user, &raw_password, &size);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen switch (encoding) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen case PW_ENCODING_NONE:
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen *password_r = t_strndup(raw_password, size);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen break;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen case PW_ENCODING_BASE64:
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(size) + 1);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen base64_encode(raw_password, size, str);
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen *password_r = str_c(str);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case PW_ENCODING_HEX:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *password_r = binary_to_hex(raw_password, size);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen break;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen return TRUE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenbool password_scheme_is_alias(const char *scheme1, const char *scheme2)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct password_scheme *const *schemes, *s1 = NULL, *s2 = NULL;
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen unsigned int i, count;
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen scheme1 = t_strcut(scheme1, '.');
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen scheme2 = t_strcut(scheme2, '.');
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (strcasecmp(scheme1, scheme2) == 0)
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen return TRUE;
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen
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 s1 = schemes[i];
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen else if (strcasecmp(schemes[i]->name, scheme2) == 0)
3db05c8c00faca6ab9ac8391e1d6977365f4d1b3Timo Sirainen s2 = schemes[i];
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* if they've the same generate function, they're equivalent */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return s1 != NULL && s2 != NULL &&
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen s1->password_generate == s2->password_generate;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainenstatic bool
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainencrypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *raw_password, size_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen const char *password;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (size == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* the default mycrypt() handler would return match */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen password = t_strndup(raw_password, size);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return strcmp(mycrypt(plaintext, password), password) == 0;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen}
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstatic void
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainencrypt_generate(const char *plaintext, const char *user ATTR_UNUSED,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen char salt[3];
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const char *password;
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen random_fill(salt, sizeof(salt)-1);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen salt[0] = salt_chars[salt[0] % (sizeof(salt_chars)-1)];
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen salt[1] = salt_chars[salt[1] % (sizeof(salt_chars)-1)];
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen salt[2] = '\0';
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen password = t_strdup(mycrypt(plaintext, salt));
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen *raw_password_r = (const unsigned char *)password;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen *size_r = strlen(password);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainenstatic bool
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenmd5_verify(const char *plaintext, const char *user,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen const unsigned char *raw_password, size_t size)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const char *password, *str;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const unsigned char *md5_password;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen size_t md5_size;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen password = t_strndup(raw_password, size);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (strncmp(password, "$1$", 3) == 0) {
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen /* MD5-CRYPT */
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen str = password_generate_md5_crypt(plaintext, password);
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen return strcmp(str, password) == 0;
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen } else {
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen if (password_decode(password, "PLAIN-MD5",
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen &md5_password, &md5_size) < 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return password_verify(plaintext, user, "PLAIN-MD5",
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen md5_password, md5_size) > 0;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic bool
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenmd5_crypt_verify(const char *plaintext, const char *user ATTR_UNUSED,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const unsigned char *raw_password, size_t size)
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen{
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen const char *password, *str;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen password = t_strndup(raw_password, size);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen str = password_generate_md5_crypt(plaintext, password);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return strcmp(str, password) == 0;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainenstatic void
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenmd5_crypt_generate(const char *plaintext, const char *user ATTR_UNUSED,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const char *password;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen char salt[9];
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen unsigned int i;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen random_fill(salt, sizeof(salt)-1);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen for (i = 0; i < sizeof(salt)-1; i++)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)];
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen salt[sizeof(salt)-1] = '\0';
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen password = password_generate_md5_crypt(plaintext, salt);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen *raw_password_r = (const unsigned char *)password;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen *size_r = strlen(password);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic void
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainensha1_generate(const char *plaintext, const char *user ATTR_UNUSED,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen unsigned char *digest;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen digest = t_malloc(SHA1_RESULTLEN);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen sha1_get_digest(plaintext, strlen(plaintext), digest);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen *raw_password_r = digest;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen *size_r = SHA1_RESULTLEN;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic void
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{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen unsigned char *digest;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen digest = t_malloc(SHA256_RESULTLEN);
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen sha256_get_digest(plaintext, strlen(plaintext), digest);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *raw_password_r = digest;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *size_r = SHA256_RESULTLEN;
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen}
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
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{
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen#define SSHA_SALT_LEN 4
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen unsigned char *digest, *salt;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen struct sha1_ctxt ctx;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen digest = t_malloc(SHA1_RESULTLEN + SSHA_SALT_LEN);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen salt = digest + SHA1_RESULTLEN;
559f278a4c54d9fa7e0f2e96ebceda30562f9009Timo Sirainen random_fill(salt, SSHA_SALT_LEN);
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen
88e9835c4d8973c62cd4db1ec7324ff46dd3ff15Timo Sirainen sha1_init(&ctx);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen sha1_loop(&ctx, plaintext, strlen(plaintext));
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen sha1_loop(&ctx, salt, SSHA_SALT_LEN);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen sha1_result(&ctx, digest);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen *raw_password_r = digest;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen *size_r = SHA1_RESULTLEN + SSHA_SALT_LEN;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic bool ssha_verify(const char *plaintext, const char *user,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char *raw_password, size_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen unsigned char sha1_digest[SHA1_RESULTLEN];
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen struct sha1_ctxt ctx;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen /* format: <SHA1 hash><salt> */
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen if (size <= SHA1_RESULTLEN) {
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen i_error("ssha_verify(%s): SSHA password too short", user);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen return FALSE;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen }
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen sha1_init(&ctx);
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen sha1_loop(&ctx, plaintext, strlen(plaintext));
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen sha1_loop(&ctx, raw_password + SHA1_RESULTLEN, size - SHA1_RESULTLEN);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen sha1_result(&ctx, sha1_digest);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return memcmp(sha1_digest, raw_password, SHA1_RESULTLEN) == 0;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenssha256_generate(const char *plaintext, const char *user ATTR_UNUSED,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen{
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen#define SSHA256_SALT_LEN 4
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen unsigned char *digest, *salt;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen struct sha256_ctx ctx;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen digest = t_malloc(SHA256_RESULTLEN + SSHA256_SALT_LEN);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen salt = digest + SHA256_RESULTLEN;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen random_fill(salt, SSHA256_SALT_LEN);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen sha256_init(&ctx);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen sha256_loop(&ctx, plaintext, strlen(plaintext));
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen sha256_loop(&ctx, salt, SSHA256_SALT_LEN);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen sha256_result(&ctx, digest);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen *raw_password_r = digest;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen *size_r = SHA256_RESULTLEN + SSHA256_SALT_LEN;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen}
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainenstatic bool ssha256_verify(const char *plaintext, const char *user,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen const unsigned char *raw_password, size_t size)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen unsigned char sha256_digest[SHA256_RESULTLEN];
cd75c360f244c96b9ee10e01ee3a66fad13183c8Timo Sirainen struct sha256_ctx ctx;
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* format: <SHA256 hash><salt> */
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (size <= SHA256_RESULTLEN) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("ssha256_verify(%s): SSHA256 password too short", user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen }
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen sha256_init(&ctx);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen sha256_loop(&ctx, plaintext, strlen(plaintext));
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen sha256_loop(&ctx, raw_password + SHA256_RESULTLEN,
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen size - SHA256_RESULTLEN);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen sha256_result(&ctx, sha256_digest);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen return memcmp(sha256_digest, raw_password, SHA256_RESULTLEN) == 0;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen}
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainenstatic void
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{
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen#define SMD5_SALT_LEN 4
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen unsigned char *digest, *salt;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen struct md5_context ctx;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen digest = t_malloc(MD5_RESULTLEN + SMD5_SALT_LEN);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen salt = digest + MD5_RESULTLEN;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen random_fill(salt, SMD5_SALT_LEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_init(&ctx);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_update(&ctx, plaintext, strlen(plaintext));
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_update(&ctx, salt, SMD5_SALT_LEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_final(&ctx, digest);
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen
7cba14a4c3beb026a2862ee50d24c554fa713329Timo Sirainen *raw_password_r = digest;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *size_r = MD5_RESULTLEN + SMD5_SALT_LEN;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen}
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic bool smd5_verify(const char *plaintext, const char *user,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const unsigned char *raw_password, size_t size)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen{
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen unsigned char md5_digest[MD5_RESULTLEN];
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct md5_context ctx;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen /* format: <MD5 hash><salt> */
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen if (size <= MD5_RESULTLEN) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_error("smd5_verify(%s): SMD5 password too short", user);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen return FALSE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen md5_init(&ctx);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen md5_update(&ctx, plaintext, strlen(plaintext));
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_update(&ctx, raw_password + MD5_RESULTLEN, size - MD5_RESULTLEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_final(&ctx, md5_digest);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen return memcmp(md5_digest, raw_password, MD5_RESULTLEN) == 0;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void
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{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *raw_password_r = (const unsigned char *)plaintext,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *size_r = strlen(plaintext);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainencram_md5_generate(const char *plaintext, const char *user ATTR_UNUSED,
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct hmac_md5_context ctx;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned char *context_digest;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen context_digest = t_malloc(CRAM_MD5_CONTEXTLEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen hmac_md5_init(&ctx, (const unsigned char *)plaintext,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen strlen(plaintext));
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen hmac_md5_get_cram_context(&ctx, context_digest);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *raw_password_r = context_digest;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *size_r = CRAM_MD5_CONTEXTLEN;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainendigest_md5_generate(const char *plaintext, const char *user,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen{
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen const char *realm, *str;
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen unsigned char *digest;
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen if (user == NULL)
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen i_fatal("digest_md5_generate(): username not given");
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen /* user:realm:passwd */
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen realm = strchr(user, '@');
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen if (realm != NULL) realm++; else realm = "";
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
1ce47e48d7231da6f18f02eab6bab6451b4ef12aTimo Sirainen digest = t_malloc(MD5_RESULTLEN);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen str = t_strdup_printf("%s:%s:%s", t_strcut(user, '@'),
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen realm, plaintext);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_get_digest(str, strlen(str), digest);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen *raw_password_r = digest;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen *size_r = MD5_RESULTLEN;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void
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{
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned char *digest;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen digest = t_malloc(MD4_RESULTLEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md4_get_digest(plaintext, strlen(plaintext), digest);
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen *raw_password_r = digest;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen *size_r = MD4_RESULTLEN;
3340fc9aeaa655dc3bb8f329ebdfcb38a5121949Timo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenplain_md5_generate(const char *plaintext, const char *user ATTR_UNUSED,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen const unsigned char **raw_password_r, size_t *size_r)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen unsigned char *digest;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen digest = t_malloc(MD5_RESULTLEN);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen md5_get_digest(plaintext, strlen(plaintext), digest);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen *raw_password_r = digest;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen *size_r = MD5_RESULTLEN;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen}
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenstatic void
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{
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen unsigned char *digest;
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen digest = t_malloc(LM_HASH_SIZE);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen lm_hash(plaintext, digest);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen *raw_password_r = digest;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen *size_r = LM_HASH_SIZE;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen}
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic void
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{
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen unsigned char *digest;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen digest = t_malloc(NTLMSSP_HASH_SIZE);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen ntlm_v1_hash(plaintext, digest);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen *raw_password_r = digest;
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen *size_r = NTLMSSP_HASH_SIZE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainenstatic bool otp_verify(const char *plaintext, const char *user ATTR_UNUSED,
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen const unsigned char *raw_password, size_t size)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen{
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen const char *password;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen password = t_strndup(raw_password, size);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen return strcasecmp(password,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen password_generate_otp(plaintext, password, -1)) == 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
459b483806babd159daa8b461377281d89bb3bdcTimo Sirainenotp_generate(const char *plaintext, const char *user ATTR_UNUSED,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const unsigned char **raw_password_r, size_t *size_r)
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen{
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen const char *password;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen password = password_generate_otp(plaintext, NULL, OTP_HASH_SHA1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *raw_password_r = (const unsigned char *)password;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen *size_r = strlen(password);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainenstatic void
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{
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const char *password;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen password = password_generate_otp(plaintext, NULL, OTP_HASH_MD4);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen *raw_password_r = (const unsigned char *)password;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen *size_r = strlen(password);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen}
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainenstatic void
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{
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen unsigned char *digest;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen digest = t_malloc(MD5_RESULTLEN);
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen password_generate_rpa(plaintext, digest);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *raw_password_r = digest;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *size_r = MD5_RESULTLEN;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen}
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
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 { "MD5-CRYPT", PW_ENCODING_NONE, 0,
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen md5_crypt_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 NULL, sha256_generate },
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,
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen NULL, cram_md5_generate },
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "DIGEST-MD5", PW_ENCODING_HEX, MD5_RESULTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen NULL, digest_md5_generate },
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen { "PLAIN-MD4", PW_ENCODING_HEX, MD4_RESULTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen NULL, plain_md4_generate },
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "PLAIN-MD5", PW_ENCODING_HEX, MD5_RESULTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen NULL, plain_md5_generate },
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen { "LDAP-MD5", PW_ENCODING_BASE64, MD5_RESULTLEN,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen NULL, plain_md5_generate },
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 }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen};
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid password_scheme_register(const struct password_scheme *scheme)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (password_scheme_lookup_name(scheme->name) != NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_panic("password_scheme_register(%s): Already registered",
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen scheme->name);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen array_append(&password_schemes, &scheme, 1);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen}
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenvoid password_scheme_unregister(const struct password_scheme *scheme)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen{
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen const struct password_scheme *const *schemes;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen unsigned int i, count;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
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 array_delete(&password_schemes, i, 1);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen return;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen }
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen i_panic("password_scheme_unregister(%s): Not registered", scheme->name);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen}
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenvoid password_schemes_init(void)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen{
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen unsigned int i;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen i_array_init(&password_schemes, N_ELEMENTS(builtin_schemes) + 4);
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen for (i = 0; i < N_ELEMENTS(builtin_schemes); i++)
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen password_scheme_register(&builtin_schemes[i]);
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen}
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenvoid password_schemes_deinit(void)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen array_free(&password_schemes);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen