Mercurial > dovecot > original-hg > dovecot-1.2
view src/auth/mech-cram-md5.c @ 2510:0f660149c7ef HEAD
Added auth_username_translation setting.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 28 Aug 2004 16:25:42 +0300 |
parents | 4f84a146d93a |
children | a07fb16b9a24 |
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 int verify_credentials(struct cram_auth_request *auth, const char *credentials) { unsigned char digest[16], context_digest[32]; struct hmac_md5_context ctx; buffer_t *context_digest_buf; const char *response_hex; if (credentials == NULL) return FALSE; context_digest_buf = buffer_create_data(pool_datastack_create(), context_digest, sizeof(context_digest)); if (hex_to_binary(credentials, context_digest_buf) <= 0) return FALSE; hmac_md5_set_cram_context(&ctx, context_digest); hmac_md5_update(&ctx, auth->challenge, strlen(auth->challenge)); hmac_md5_final(&ctx, digest); response_hex = binary_to_hex(digest, 16); if (memcmp(response_hex, auth->response, 32) != 0) { if (verbose) { i_info("cram-md5(%s): password mismatch", get_log_prefix(&auth->auth_request)); } return FALSE; } return TRUE; } static int parse_cram_response(struct cram_auth_request *auth, const unsigned char *data, size_t size, const char **error_r) { size_t i; *error_r = NULL; for (i = 0; i < size; i++) { if (data[i] == ' ') break; } if (i == size) { *error_r = "missing digest"; return FALSE; } auth->username = p_strndup(auth->pool, data, i); i++; auth->response = p_strndup(auth->pool, data + i, size - i); return TRUE; } static void credentials_callback(const char *result, struct auth_request *request) { struct cram_auth_request *auth = (struct cram_auth_request *) request; if (verify_credentials(auth, result)) mech_auth_finish(request, NULL, 0, TRUE); else { if (verbose) { i_info("cram-md5(%s): authentication failed", get_log_prefix(&auth->auth_request)); } mech_auth_finish(request, NULL, 0, FALSE); } } static int mech_cram_md5_auth_continue(struct auth_request *auth_request, const unsigned char *data, size_t data_size, mech_callback_t *callback) { struct cram_auth_request *auth = (struct cram_auth_request *)auth_request; const char *error; if (parse_cram_response(auth, data, data_size, &error)) { auth_request->callback = callback; auth_request->user = p_strdup(auth_request->pool, auth->username); if (mech_fix_username(auth_request->user)) { passdb->lookup_credentials(&auth->auth_request, PASSDB_CREDENTIALS_CRAM_MD5, credentials_callback); return TRUE; } error = "invalid username"; } if (error == NULL) error = "authentication failed"; if (verbose) { i_info("cram-md5(%s): %s", get_log_prefix(&auth->auth_request), error); } /* failed */ mech_auth_finish(auth_request, NULL, 0, FALSE); return FALSE; } static int mech_cram_md5_auth_initial(struct auth_request *auth_request, struct auth_client_request_new *request, const unsigned char *data __attr_unused__, mech_callback_t *callback) { struct cram_auth_request *auth = (struct cram_auth_request *)auth_request; struct auth_client_request_reply reply; if (AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request)) { /* No initial response in CRAM-MD5 */ return FALSE; } auth->challenge = p_strdup(auth->pool, get_cram_challenge()); /* initialize reply */ mech_init_auth_client_reply(&reply); reply.id = request->id; reply.result = AUTH_CLIENT_RESULT_CONTINUE; /* send the initial challenge */ reply.reply_idx = 0; reply.data_size = strlen(auth->challenge); callback(&reply, auth->challenge, auth_request->conn); return TRUE; } static void mech_cram_md5_auth_free(struct auth_request *auth_request) { pool_unref(auth_request->pool); } static struct auth_request *mech_cram_md5_auth_new(void) { struct cram_auth_request *auth; pool_t pool; pool = pool_alloconly_create("cram_md5_auth_request", 2048); auth = p_new(pool, struct cram_auth_request, 1); auth->pool = pool; auth->auth_request.refcount = 1; auth->auth_request.pool = pool; auth->auth_request.auth_initial = mech_cram_md5_auth_initial; auth->auth_request.auth_continue = mech_cram_md5_auth_continue; auth->auth_request.auth_free = mech_cram_md5_auth_free; return &auth->auth_request; } struct mech_module mech_cram_md5 = { "CRAM-MD5", MEMBER(plaintext) FALSE, MEMBER(advertise) TRUE, MEMBER(passdb_need_plain) FALSE, MEMBER(passdb_need_credentials) TRUE, mech_cram_md5_auth_new };