Mercurial > dovecot > core-2.2
changeset 2270:52a52b3a0357 HEAD
was missing from last commit
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 03 Jul 2004 13:43:12 +0300 |
parents | 945403a685f9 |
children | 15d959d262a4 |
files | src/auth/mech-apop.c |
diffstat | 1 files changed, 164 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/mech-apop.c Sat Jul 03 13:43:12 2004 +0300 @@ -0,0 +1,164 @@ +/* + * APOP (RFC-1460) authentication mechanism. + * + * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "common.h" +#include "safe-memset.h" +#include "mech.h" +#include "passdb.h" +#include "md5.h" +#include "buffer.h" +#include "auth-client-connection.h" +#include "auth-master-connection.h" + +#include <ctype.h> + +struct apop_auth_request { + struct auth_request auth_request; + + pool_t pool; + + /* requested: */ + char *challenge; + + /* received: */ + unsigned char digest[16]; +}; + +static void +apop_credentials_callback(const char *credentials, + struct auth_request *auth_request) +{ + struct apop_auth_request *auth = + (struct apop_auth_request *)auth_request; + unsigned char digest[16]; + struct md5_context ctx; + + md5_init(&ctx); + md5_update(&ctx, auth->challenge, strlen(auth->challenge)); + md5_update(&ctx, credentials, strlen(credentials)); + md5_final(&ctx, digest); + + mech_auth_finish(auth_request, NULL, 0, + memcmp(digest, auth->digest, 16) == 0); +} + +static int +mech_apop_auth_initial(struct auth_request *auth_request, + struct auth_client_request_new *request, + const unsigned char *data, + mech_callback_t *callback) +{ + struct apop_auth_request *auth = + (struct apop_auth_request *)auth_request; + const unsigned char *tmp, *end, *username = NULL; + const char *str; + + auth_request->callback = callback; + + if (!AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request)) { + /* Should never happen */ + if (verbose) { + i_info("apop(%s): no initial respone", + get_log_prefix(auth_request)); + } + mech_auth_finish(auth_request, NULL, 0, FALSE); + return TRUE; + } + + tmp = data = data + request->initial_resp_idx; + end = data + request->data_size - request->initial_resp_idx; + + while (tmp != end && *tmp != '\0') + tmp++; + + /* the challenge must begin with trusted unique ID. we trust only + ourself, so make sure it matches our connection specific UID + which we told to client in handshake. */ + str = t_strdup_printf("<%x.%x.", auth_request->conn->master->pid, + auth_request->conn->connect_uid); + if (memcmp(data, str, strlen(str)) != 0) { + if (verbose) { + i_info("apop(%s): invalid challenge", + get_log_prefix(auth_request)); + } + mech_auth_finish(auth_request, NULL, 0, FALSE); + return TRUE; + } + auth->challenge = p_strdup(auth->pool, data); + + if (tmp != end) { + username = ++tmp; + while (tmp != end && *tmp != '\0') + tmp++; + } + + if (tmp + 1 + 16 != end) { + /* Should never happen */ + if (verbose) { + i_info("apop(%s): malformed data", + get_log_prefix(auth_request)); + } + mech_auth_finish(auth_request, NULL, 0, FALSE); + return TRUE; + } + tmp++; + + auth_request->user = p_strdup(auth->pool, username); + if (!mech_is_valid_username(auth_request->user)) { + if (verbose) { + i_info("apop(%s): invalid username", + get_log_prefix(auth_request)); + } + mech_auth_finish(auth_request, NULL, 0, FALSE); + return TRUE; + } + + memcpy(auth->digest, tmp, sizeof(auth->digest)); + + passdb->lookup_credentials(auth_request, PASSDB_CREDENTIALS_PLAINTEXT, + apop_credentials_callback); + return TRUE; +} + +static void mech_apop_auth_free(struct auth_request *auth_request) +{ + pool_unref(auth_request->pool); +} + +static struct auth_request *mech_apop_auth_new(void) +{ + struct apop_auth_request *auth; + pool_t pool; + + pool = pool_alloconly_create("apop_auth_request", 256); + auth = p_new(pool, struct apop_auth_request, 1); + auth->pool = pool; + + auth->auth_request.refcount = 1; + auth->auth_request.pool = pool; + auth->auth_request.auth_initial = mech_apop_auth_initial; + auth->auth_request.auth_continue = NULL; + auth->auth_request.auth_free = mech_apop_auth_free; + + return &auth->auth_request; +} + +const struct mech_module mech_apop = { + "APOP", + + MEMBER(plaintext) FALSE, + MEMBER(advertise) FALSE, + + MEMBER(passdb_need_plain) FALSE, + MEMBER(passdb_need_credentials) TRUE, + + mech_apop_auth_new, +};