885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose#include "lib.h"
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose#include "md5.h"
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose#include "str.h"
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose#include "var-expand.h"
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose#include "mail-user-hash.h"
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bosebool mail_user_hash(const char *username, const char *format,
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose unsigned int *hash_r, const char **error_r)
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose{
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose unsigned char md5[MD5_RESULTLEN];
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose unsigned int i, hash = 0;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose char *error_dup = NULL;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose int ret = 1;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose if (strcmp(format, "%u") == 0) {
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose /* fast path */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose md5_get_digest(username, strlen(username), md5);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose } else if (strcmp(format, "%Lu") == 0) {
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose /* almost as fast path */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose T_BEGIN {
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose md5_get_digest(t_str_lcase(username),
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose strlen(username), md5);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose } T_END;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose } else T_BEGIN {
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose const struct var_expand_table tab[] = {
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose { 'u', username, "user" },
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose { 'n', t_strcut(username, '@'), "username" },
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose { 'd', i_strchr_to_next(username, '@'), "domain" },
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose { '\0', NULL, NULL }
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose };
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose string_t *str = t_str_new(128);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose const char *error;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose ret = var_expand(str, format, tab, &error);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose i_assert(ret >= 0);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose if (ret == 0)
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose error_dup = i_strdup(error);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose md5_get_digest(str_data(str), str_len(str), md5);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose } T_END;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose for (i = 0; i < sizeof(hash); i++)
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose hash = (hash << CHAR_BIT) | md5[i];
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose if (hash == 0) {
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose /* Make sure we don't return the hash as 0, since it's often
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose treated in a special way that won't work well. For example
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose trying to insert it into a hash table will assert-crash. */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose hash = 1;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose }
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose *hash_r = hash;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose *error_r = t_strdup(error_dup);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose i_free(error_dup);
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose return ret > 0;
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose}
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose