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
+ *
+ * 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 \