[Dovecot] [PATCH 9/10] NTLM, authentication mechanism itself

Andrey Panin pazke at donpac.ru
Tue Jul 27 16:18:52 EEST 2004


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 at 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 \




More information about the dovecot mailing list