This patch adds NTLM authentication mechanism itself. Depends on NTLM password scheme. src/auth/Makefile.am | 1 src/auth/mech-ntlm.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/auth/mech.c | 4 + 3 files changed, 206 insertions(+) diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/auth/mech.c dovecot-1.0-test30/src/auth/mech.c --- dovecot-1.0-test30.vanilla/src/auth/mech.c 2004-07-27 10:03:23.000000000 +0400 +++ dovecot-1.0-test30/src/auth/mech.c 2004-07-27 10:19:51.000000000 +0400 @@ -388,6 +388,7 @@ extern struct mech_module mech_login; extern struct mech_module mech_apop; extern struct mech_module mech_cram_md5; extern struct mech_module mech_digest_md5; +extern struct mech_module mech_ntlm; extern struct mech_module mech_anonymous; void mech_init(void) @@ -421,6 +422,8 @@ void mech_init(void) mech_register_module(&mech_cram_md5); else if (strcasecmp(*mechanisms, "DIGEST-MD5") == 0) mech_register_module(&mech_digest_md5); + else if (strcasecmp(*mechanisms, "NTLM") == 0) + mech_register_module(&mech_ntlm); else if (strcasecmp(*mechanisms, "ANONYMOUS") == 0) { if (anonymous_username == NULL) { i_fatal("ANONYMOUS listed in mechanisms, " @@ -481,5 +484,6 @@ void mech_deinit(void) mech_unregister_module(&mech_apop); mech_unregister_module(&mech_cram_md5); mech_unregister_module(&mech_digest_md5); + mech_unregister_module(&mech_ntlm); mech_unregister_module(&mech_anonymous); } diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/auth/mech-ntlm.c dovecot-1.0-test30/src/auth/mech-ntlm.c --- dovecot-1.0-test30.vanilla/src/auth/mech-ntlm.c 1970-01-01 03:00:00.000000000 +0300 +++ dovecot-1.0-test30/src/auth/mech-ntlm.c 2004-07-27 11:46:54.000000000 +0400 @@ -0,0 +1,201 @@ +/* + * NTLM and NTLMv2 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 "mech.h" +#include "passdb.h" +#include "str.h" +#include "buffer.h" +#include "hex-binary.h" +#include "safe-memset.h" + +#include "ntlm.h" + +struct ntlm_auth_request { + struct auth_request auth_request; + + pool_t pool; + + /* requested: */ + const unsigned char *challenge; + + /* received: */ + struct ntlmssp_response *response; +}; + +static void +ntlm_credentials_callback(const char *credentials, + struct auth_request *auth_request) +{ + struct ntlm_auth_request *auth = + (struct ntlm_auth_request *)auth_request; + unsigned char hash[NTLMSSP_HASH_SIZE]; + buffer_t *hash_buffer; + int ret = FALSE; + + hash_buffer = buffer_create_data(auth_request->pool, hash, sizeof(hash)); + + hex_to_binary(credentials, hash_buffer); + + if (credentials != NULL) { + int response_length = ntlmssp_buffer_length(auth->response, ntlm_response); + const unsigned char *client_response = ntlmssp_buffer_data(auth->response, ntlm_response); + + if (response_length > NTLMSSP_RESPONSE_SIZE) { + unsigned char ntlm_v2_response[NTLMSSP_V2_RESPONSE_SIZE]; + const unsigned char *blob = client_response + NTLMSSP_V2_RESPONSE_SIZE; + + /* + * Authentication target == NULL because we are acting + * as a standalone server, not as NT domain member. + */ + ntlmssp_v2_response(auth_request->user, NULL, + hash, auth->challenge, blob, + response_length - NTLMSSP_V2_RESPONSE_SIZE, + ntlm_v2_response); + + ret = !memcmp(ntlm_v2_response, client_response, NTLMSSP_V2_RESPONSE_SIZE); + } else { + unsigned char ntlm_response[NTLMSSP_RESPONSE_SIZE]; + + ntlmssp_v1_response(hash, auth->challenge, ntlm_response); + + ret = !memcmp(ntlm_response, client_response, NTLMSSP_RESPONSE_SIZE); + } + } + + mech_auth_finish(auth_request, NULL, 0, ret); +} + +static int +mech_ntlm_auth_continue(struct auth_request *auth_request, + const unsigned char *data, size_t data_size, + mech_callback_t *callback) +{ + struct ntlm_auth_request *auth = + (struct ntlm_auth_request *)auth_request; + struct auth_client_request_reply reply; + const char *error; + + auth_request->callback = callback; + + if (!auth->challenge) { + struct ntlmssp_request *request = (struct ntlmssp_request *) data; + const struct ntlmssp_challenge *message; + size_t message_size; + + if (!ntlmssp_check_request(request, data_size, &error)) { + if (verbose) + i_info("ntlm(%s): invalid NTLM request, %s", + get_log_prefix(auth_request), + error); + mech_auth_finish(auth_request, NULL, 0, FALSE); + return TRUE; + } + + message = ntlmssp_create_challenge(auth->pool, request, &message_size); + auth->challenge = message->challenge; + + mech_init_auth_client_reply(&reply); + reply.id = auth_request->id; + reply.result = AUTH_CLIENT_RESULT_CONTINUE; + + reply.reply_idx = 0; + reply.data_size = message_size; + callback(&reply, message, auth_request->conn); + } else { + struct ntlmssp_response *response = (struct ntlmssp_response *) data; + char *username; + + if (!ntlmssp_check_response(response, data_size, &error)) { + if (verbose) + i_info("ntlm(%s): invalid NTLM response, %s", + get_log_prefix(auth_request), + error); + mech_auth_finish(auth_request, NULL, 0, FALSE); + return TRUE; + } + + auth->response = p_malloc(auth->pool, data_size); + memcpy(auth->response, response, data_size); + + username = p_strdup(auth_request->pool, ntlmssp_t_str(auth->response, user)); + + if (!mech_is_valid_username(username)) { + if (verbose) + i_info("ntlm(%s): invalid username", get_log_prefix(auth_request)); + mech_auth_finish(auth_request, NULL, 0, FALSE); + return TRUE; + } + + auth_request->user = username; + + passdb->lookup_credentials(auth_request, PASSDB_CREDENTIALS_NTLM, + ntlm_credentials_callback); + } + + return TRUE; +} + +static int +mech_ntlm_auth_initial(struct auth_request *auth_request, + struct auth_client_request_new *request, + const unsigned char *data __attr_unused__, + mech_callback_t *callback) +{ + struct auth_client_request_reply reply; + + mech_init_auth_client_reply(&reply); + reply.id = request->id; + reply.result = AUTH_CLIENT_RESULT_CONTINUE; + + reply.reply_idx = 0; + reply.data_size = 0; + callback(&reply, "", auth_request->conn); + + return TRUE; +} + +static void +mech_ntlm_auth_free(struct auth_request *auth_request) +{ + pool_unref(auth_request->pool); +} + +static struct auth_request *mech_ntlm_auth_new(void) +{ + struct ntlm_auth_request *auth; + pool_t pool; + + pool = pool_alloconly_create("ntlm_auth_request", 256); + auth = p_new(pool, struct ntlm_auth_request, 1); + auth->pool = pool; + + auth->auth_request.refcount = 1; + auth->auth_request.pool = pool; + auth->auth_request.auth_initial = mech_ntlm_auth_initial; + auth->auth_request.auth_continue = mech_ntlm_auth_continue; + auth->auth_request.auth_free = mech_ntlm_auth_free; + + return &auth->auth_request; +} + +const struct mech_module mech_ntlm = { + "NTLM", + + MEMBER(plaintext) FALSE, + MEMBER(advertise) TRUE, + + MEMBER(passdb_need_plain) FALSE, + MEMBER(passdb_need_credentials) TRUE, + + mech_ntlm_auth_new, +}; diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/auth/Makefile.am dovecot-1.0-test30/src/auth/Makefile.am --- dovecot-1.0-test30.vanilla/src/auth/Makefile.am 2004-07-27 10:03:23.000000000 +0400 +++ dovecot-1.0-test30/src/auth/Makefile.am 2004-07-27 11:56:34.000000000 +0400 @@ -32,6 +34,7 @@ dovecot_auth_SOURCES = \ mech-login.c \ mech-cram-md5.c \ mech-digest-md5.c \ + mech-ntlm.c \ mech-apop.c \ mycrypt.c \ passdb.c \