password-scheme.c revision f1d759d0b4860cac29b5077ee423f9de8bb7d300
/* Copyright (c) 2003-2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.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 *
password_scheme_lookup_name(const char *name)
{
const struct password_scheme *const *schemes;
return scheme;
}
return NULL;
}
/* 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 *
{
const struct password_scheme *scheme;
break;
}
}
return NULL;
else {
/* unknown encoding. treat as invalid scheme. */
return NULL;
}
return scheme;
}
const char **error_r)
{
const struct password_scheme *s;
enum password_encoding encoding;
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)
*error_r = "Password mismatch";
return ret;
}
const char *password_get_scheme(const char **password)
{
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;
enum password_encoding encoding;
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;
}
/* fall through, just in case it was base64-encoded after
all. some input lengths produce matching hex and base64
encoded lengths. */
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;
enum password_encoding encoding;
if (s == NULL)
return FALSE;
return TRUE;
}
const char *scheme, const char **password_r)
{
const struct password_scheme *s;
const unsigned char *raw_password;
enum password_encoding encoding;
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 TRUE;
}
/* if they've the same generate function, they're equivalent */
}
const char *
const char *user)
{
const struct password_scheme *const *schemes;
unsigned int i, count;
const unsigned char *raw_password;
const char *error;
for (i = 0; i < count; i++) {
&error) <= 0)
continue;
&error) > 0)
}
return NULL;
}
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
{
const char *password;
char salt[9];
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
{
#define SSHA_SALT_LEN 4
*raw_password_r = digest;
}
const char **error_r)
{
unsigned char sha1_digest[SHA1_RESULTLEN];
/* format: <SHA1 hash><salt> */
if (size <= SHA1_RESULTLEN) {
*error_r = "SSHA password is too short";
return -1;
}
}
static void
{
#define SSHA256_SALT_LEN 4
struct sha256_ctx ctx;
sha256_init(&ctx);
*raw_password_r = digest;
}
const char **error_r)
{
unsigned char sha256_digest[SHA256_RESULTLEN];
struct sha256_ctx ctx;
/* 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) == 0 ? 1 : 0;
}
static void
{
#define SSHA512_SALT_LEN 4
struct sha512_ctx ctx;
sha512_init(&ctx);
*raw_password_r = digest;
}
const char **error_r)
{
unsigned char sha512_digest[SHA512_RESULTLEN];
struct sha512_ctx ctx;
/* 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) == 0 ? 1 : 0;
}
static void
{
#define SMD5_SALT_LEN 4
struct md5_context ctx;
*raw_password_r = digest;
}
const char **error_r)
{
unsigned char md5_digest[MD5_RESULTLEN];
struct md5_context ctx;
/* 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
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
{
struct hmac_context ctx;
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
{
unsigned char *digest;
*raw_password_r = digest;
*size_r = MD4_RESULTLEN;
}
static void
{
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;
}
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;
}
static const struct password_scheme builtin_schemes[] = {
{ "MD5-CRYPT", PW_ENCODING_NONE, 0,
NULL, sha256_generate },
NULL, sha512_generate },
};
{
i_panic("password_scheme_register(%s): Already registered",
}
}
{
const struct password_scheme *const *schemes;
unsigned int idx;
return;
}
}
}
void password_schemes_init(void)
{
unsigned int i;
for (i = 0; i < N_ELEMENTS(builtin_schemes); i++)
}
void password_schemes_deinit(void)
{
}