/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "hash.h"
#include "base64.h"
#include "hex-binary.h"
#include "md4.h"
#include "md5.h"
#include "hmac.h"
#include "hmac-cram-md5.h"
#include "ntlm.h"
#include "mycrypt.h"
#include "randgen.h"
#include "sha1.h"
#include "sha2.h"
#include "otp.h"
#include "str.h"
#include "password-scheme.h"
static const char salt_chars[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static const struct password_scheme *
{
}
/* Lookup scheme and encoding by given name. The encoding is taken from
".base64", ".b64" or ".hex" suffix if it exists, otherwise the default
encoding is used. */
static const struct password_scheme *
{
encoding++;
}
return NULL;
else {
/* unknown encoding. treat as invalid scheme. */
return NULL;
}
return scheme;
}
const struct password_generate_params *params,
const char *scheme, const unsigned char *raw_password,
{
const struct password_scheme *s;
const unsigned char *generated;
int ret;
if (s == NULL) {
*error_r = "Unknown password scheme";
return -1;
}
if (s->password_verify != NULL) {
error_r);
} else {
/* generic verification handler: generate the password and
compare it to the one in database */
&generated, &generated_size);
}
if (ret == 0)
return ret;
}
{
const char *p, *scheme;
return NULL;
/* $1$<salt>$<password>[$<ignored>] */
if (p != NULL) {
/* stop at next '$' after password */
if (p != NULL)
return "MD5-CRYPT";
}
}
if (**password != '{')
return NULL;
if (p == NULL)
return NULL;
*password = p + 1;
return scheme;
}
const char **error_r)
{
const struct password_scheme *s;
bool guessed_encoding;
if (s == NULL) {
*error_r = "Unknown scheme";
return 0;
}
/* encoding not specified. we can guess quite well between
base64 and hex encodings. the only problem is distinguishing
2 character strings, but there shouldn't be any that short
raw_password_lens. */
} else {
}
switch (encoding) {
case PW_ENCODING_NONE:
*raw_password_r = (const unsigned char *)password;
break;
case PW_ENCODING_HEX:
break;
}
if (!guessed_encoding) {
*error_r = "Input isn't valid HEX encoded data";
return -1;
}
/* check if it's base64-encoded after all. some input lengths
produce matching hex and base64 encoded lengths. */
/* fall through */
case PW_ENCODING_BASE64:
*error_r = "Input isn't valid base64 encoded data";
return -1;
}
break;
}
/* password has invalid length */
"Input length isn't valid (%u instead of %u)",
(unsigned int)*size_r, s->raw_password_len);
return -1;
}
return 1;
}
const char *scheme,
{
const struct password_scheme *s;
if (s == NULL)
return FALSE;
return TRUE;
}
bool password_generate_encoded(const char *plaintext, const struct password_generate_params *params,
const char *scheme, const char **password_r)
{
const struct password_scheme *s;
const unsigned char *raw_password;
if (s == NULL)
return FALSE;
switch (encoding) {
case PW_ENCODING_NONE:
break;
case PW_ENCODING_BASE64:
break;
case PW_ENCODING_HEX:
break;
}
return TRUE;
}
{
unsigned int i;
char *salt;
for (i = 0; i < len; i++)
return salt;
}
{
return FALSE;
return TRUE;
/* if they've the same generate function, they're equivalent */
}
const char *
const struct password_generate_params *params)
{
const char *key;
const unsigned char *raw_password;
const char *error;
&error) <= 0)
continue;
&error) > 0)
break;
}
return key;
}
const char **error_r)
{
if (size == 0) {
/* the default mycrypt() handler would return match */
return 0;
}
/* really shouldn't happen unless the system is broken */
return -1;
}
}
static int
{
const unsigned char *md5_password;
/* MD5-CRYPT */
*error_r = "Not a valid MD5-CRYPT or PLAIN-MD5 password";
return -1;
} else {
}
}
static int
const char **error_r ATTR_UNUSED)
{
}
static void
md5_crypt_generate(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
{
const char *password;
unsigned int i;
for (i = 0; i < sizeof(salt)-1; i++)
*raw_password_r = (const unsigned char *)password;
}
static void
{
unsigned char *digest;
*raw_password_r = digest;
*size_r = SHA1_RESULTLEN;
}
static void
{
unsigned char *digest;
*raw_password_r = digest;
}
static void
{
unsigned char *digest;
*raw_password_r = digest;
}
static void
{
*raw_password_r = digest;
}
static int ssha_verify(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
const char **error_r)
{
/* format: <SHA1 hash><salt> */
if (size <= SHA1_RESULTLEN) {
*error_r = "SSHA password is too short";
return -1;
}
}
static void
{
sha256_init(&ctx);
*raw_password_r = digest;
}
static int ssha256_verify(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
const char **error_r)
{
/* format: <SHA256 hash><salt> */
if (size <= SHA256_RESULTLEN) {
*error_r = "SSHA256 password is too short";
return -1;
}
sha256_init(&ctx);
size - SHA256_RESULTLEN);
SHA256_RESULTLEN) ? 1 : 0;
}
static void
{
sha512_init(&ctx);
*raw_password_r = digest;
}
static int ssha512_verify(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
const char **error_r)
{
/* format: <SHA512 hash><salt> */
if (size <= SHA512_RESULTLEN) {
*error_r = "SSHA512 password is too short";
return -1;
}
sha512_init(&ctx);
size - SHA512_RESULTLEN);
SHA512_RESULTLEN) ? 1 : 0;
}
static void
{
*raw_password_r = digest;
}
static int smd5_verify(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
const char **error_r)
{
/* format: <MD5 hash><salt> */
if (size <= MD5_RESULTLEN) {
*error_r = "SMD5 password is too short";
return -1;
}
}
static void
{
*raw_password_r = (const unsigned char *)plaintext,
}
static int
const char **error_r ATTR_UNUSED)
{
if (plaintext_len != size)
return 0;
}
static int
plain_trunc_verify(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
const char **error_r)
{
/* format: <length>-<password> */
for (i = 0; i < size; i++) {
else
break;
}
*error_r = "PLAIN-TRUNC missing length: prefix";
return -1;
}
i++;
/* possibly truncated password. allow the given password as
long as the prefix matches. */
}
return plaintext_len == size-i &&
}
static void
{
unsigned char *context_digest;
}
static void
{
unsigned char *digest;
i_fatal("digest_md5_generate(): username not given");
/* assume user@realm format for username. If user@domain is wanted
in the username, allow also user@domain@realm. */
realm++;
} else {
realm = "";
}
/* user:realm:passwd */
*raw_password_r = digest;
*size_r = MD5_RESULTLEN;
}
static void
plain_md4_generate(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
{
unsigned char *digest;
*raw_password_r = digest;
*size_r = MD4_RESULTLEN;
}
static void
plain_md5_generate(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
{
unsigned char *digest;
*raw_password_r = digest;
*size_r = MD5_RESULTLEN;
}
static void
{
unsigned char *digest;
*raw_password_r = digest;
*size_r = LM_HASH_SIZE;
}
static void
{
unsigned char *digest;
*raw_password_r = digest;
}
static int otp_verify(const char *plaintext, const struct password_generate_params *params ATTR_UNUSED,
const char **error_r)
{
*error_r = "Invalid OTP data in passdb";
return -1;
}
}
static void
{
const char *password;
i_unreached();
*raw_password_r = (const unsigned char *)password;
}
static void
{
const char *password;
i_unreached();
*raw_password_r = (const unsigned char *)password;
}
static void
{
unsigned char *digest;
*raw_password_r = digest;
*size_r = MD5_RESULTLEN;
}
{ "MD5-CRYPT", PW_ENCODING_NONE, 0,
NULL, sha256_generate },
NULL, sha512_generate },
};
{
i_panic("password_scheme_register(%s): Already registered",
}
}
{
}
{
const char *key;
}
}
void password_schemes_init(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(builtin_schemes); i++)
#ifdef HAVE_LIBSODIUM
#endif
}
void password_schemes_deinit(void)
{
}