Mercurial > dovecot > original-hg > dovecot-1.2
view src/auth/mech-cram-md5.c @ 6410:e4eb71ae8e96 HEAD
Changed .h ifdef/defines to use <NAME>_H format.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 16 Sep 2007 11:31:27 +0300 |
parents | 8591bc9961d9 |
children | 6a64e64fa3a3 |
line wrap: on
line source
/* Copyright (C) 2002,2003 Timo Sirainen / Joshua Goodall */ /* CRAM-MD5 SASL authentication, see RFC-2195 Joshua Goodall <joshua@roughtrade.net> */ #include "common.h" #include "ioloop.h" #include "buffer.h" #include "hex-binary.h" #include "hmac-md5.h" #include "randgen.h" #include "mech.h" #include "passdb.h" #include "hostpid.h" #include <stdlib.h> #include <time.h> struct cram_auth_request { struct auth_request auth_request; pool_t pool; /* requested: */ char *challenge; /* received: */ char *username; char *response; unsigned long maxbuf; }; static const char *get_cram_challenge(void) { unsigned char buf[17]; size_t i; hostpid_init(); random_fill(buf, sizeof(buf)-1); for (i = 0; i < sizeof(buf)-1; i++) buf[i] = (buf[i] % 10) + '0'; buf[sizeof(buf)-1] = '\0'; return t_strdup_printf("<%s.%s@%s>", (const char *)buf, dec2str(ioloop_time), my_hostname); } static bool verify_credentials(struct cram_auth_request *request, const unsigned char *credentials, size_t size) { unsigned char digest[MD5_RESULTLEN]; struct hmac_md5_context ctx; const char *response_hex; if (size != CRAM_MD5_CONTEXTLEN) { auth_request_log_error(&request->auth_request, "cram-md5", "invalid credentials length"); return FALSE; } hmac_md5_set_cram_context(&ctx, credentials); hmac_md5_update(&ctx, request->challenge, strlen(request->challenge)); hmac_md5_final(&ctx, digest); response_hex = binary_to_hex(digest, sizeof(digest)); if (memcmp(response_hex, request->response, sizeof(digest)*2) != 0) { auth_request_log_info(&request->auth_request, "cram-md5", "password mismatch"); return FALSE; } return TRUE; } static bool parse_cram_response(struct cram_auth_request *request, const unsigned char *data, size_t size, const char **error_r) { size_t i, space; *error_r = NULL; /* <username> SPACE <response>. Username may contain spaces, so assume the rightmost space is the response separator. */ for (i = space = 0; i < size; i++) { if (data[i] == ' ') space = i; } if (space == 0) { *error_r = "missing digest"; return FALSE; } request->username = p_strndup(request->pool, data, space); space++; request->response = p_strndup(request->pool, data + space, size - space); return TRUE; } static void credentials_callback(enum passdb_result result, const unsigned char *credentials, size_t size, struct auth_request *auth_request) { struct cram_auth_request *request = (struct cram_auth_request *)auth_request; switch (result) { case PASSDB_RESULT_OK: if (verify_credentials(request, credentials, size)) auth_request_success(auth_request, NULL, 0); else auth_request_fail(auth_request); break; case PASSDB_RESULT_INTERNAL_FAILURE: auth_request_internal_failure(auth_request); break; default: auth_request_fail(auth_request); break; } } static void mech_cram_md5_auth_continue(struct auth_request *auth_request, const unsigned char *data, size_t data_size) { struct cram_auth_request *request = (struct cram_auth_request *)auth_request; const char *error; if (parse_cram_response(request, data, data_size, &error)) { if (auth_request_set_username(auth_request, request->username, &error)) { auth_request_lookup_credentials(auth_request, "CRAM-MD5", credentials_callback); return; } } if (error == NULL) error = "authentication failed"; auth_request_log_info(auth_request, "cram-md5", "%s", error); auth_request_fail(auth_request); } static void mech_cram_md5_auth_initial(struct auth_request *auth_request, const unsigned char *data __attr_unused__, size_t data_size __attr_unused__) { struct cram_auth_request *request = (struct cram_auth_request *)auth_request; request->challenge = p_strdup(request->pool, get_cram_challenge()); auth_request->callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE, request->challenge, strlen(request->challenge)); } static struct auth_request *mech_cram_md5_auth_new(void) { struct cram_auth_request *request; pool_t pool; pool = pool_alloconly_create("cram_md5_auth_request", 2048); request = p_new(pool, struct cram_auth_request, 1); request->pool = pool; request->auth_request.pool = pool; return &request->auth_request; } const struct mech_module mech_cram_md5 = { "CRAM-MD5", MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE, MEMBER(passdb_need_plain) FALSE, MEMBER(passdb_need_credentials) TRUE, MEMBER(passdb_need_set_credentials) FALSE, mech_cram_md5_auth_new, mech_cram_md5_auth_initial, mech_cram_md5_auth_continue, mech_generic_auth_free };