[Dovecot] [PATCH 6/10] NTLM, message handling functions

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


This patch adds code for checking ad creating NTLM messages.


 src/lib-ntlm/ntlm-message.c |  235 ++++++++++++++++++++++++++++++++++++++++++++
 src/lib-ntlm/ntlm-message.h |   10 +
 2 files changed, 245 insertions(+)

diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-message.c dovecot-1.0-test30/src/lib-ntlm/ntlm-message.c
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-message.c	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm-message.c	2004-07-27 14:03:13.000000000 +0400
@@ -0,0 +1,235 @@
+/*
+ * NTLM message handling.
+ *
+ * Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
+ *
+ * This library 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 <stdarg.h>
+#include <ctype.h>
+
+#include "lib.h"
+#include "str.h"
+#include "buffer.h"
+#include "hostpid.h"
+#include "randgen.h"
+
+#include "ntlm.h"
+#include "ntlm-message.h"
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+const char * __ntlmssp_t_str(void *message, struct ntlmssp_buffer *buffer)
+{
+	int len = read_le16(&buffer->length) / sizeof(ucs2le_t);
+	string_t *str = t_str_new(len / 2);
+	char *p = ((char *) message) + read_le32(&buffer->offset);
+
+	while (len--) {
+		str_append_c(str, *p & 0x7f);
+		p += sizeof(ucs2le_t);
+	}
+
+	str_append_c(str, '\0');
+
+	return str_c(str);
+}
+
+static unsigned int append_string(buffer_t *buf, const char *str, int ucase)
+{
+	unsigned int length = 0;
+
+	while (*str) {
+		char c = ucase ? toupper(*str) : *str;
+		buffer_append_c(buf, c);
+		buffer_append_c(buf, 0);
+		length += sizeof(ucs2le_t);
+		str++;
+	}
+
+	return length;
+}
+
+static void ntlmssp_append_string(buffer_t *buf, size_t buffer_offset, const char *str)
+{
+	struct ntlmssp_buffer buffer;
+	unsigned int length;
+
+	write_le32(&buffer.offset, buffer_get_used_size(buf));
+
+	length = append_string(buf, str, 0);
+
+	write_le16(&buffer.length, length);
+	write_le16(&buffer.space, length);
+	buffer_write(buf, buffer_offset, &buffer, sizeof(buffer));
+}
+
+static void ntlmssp_append_target_info(buffer_t *buf, size_t buffer_offset, ...)
+{
+	struct ntlmssp_v2_target_info info;
+	struct ntlmssp_buffer buffer;
+	va_list args;
+	unsigned int length, total_length = 0;
+	int type;
+
+	write_le32(&buffer.offset, buffer_get_used_size(buf));
+
+	va_start(args, buffer_offset);
+
+	do {
+		type = va_arg(args, int);
+		const char *data;
+
+		memset(&info, 0, sizeof(info));
+		write_le16(&info.type, type);
+
+		switch (type) {
+			case NTPLMSSP_V2_TARGET_END:
+				buffer_append(buf, &info, sizeof(info));
+				length = sizeof(info);
+				break;
+			case NTPLMSSP_V2_TARGET_SERVER:
+			case NTPLMSSP_V2_TARGET_DOMAIN:
+			case NTPLMSSP_V2_TARGET_FQDN:
+			case NTPLMSSP_V2_TARGET_DNS:
+				data = va_arg(args, char *);
+				write_le16(&info.length, strlen(data) * sizeof(ucs2le_t));
+				buffer_append(buf, &info, sizeof(info));
+				length = append_string(buf, data, 0);
+				break;
+			default:
+				i_panic("Invalid NTLM target info block type %u", type);
+		}
+
+		total_length += length;
+	
+	} while (type != NTPLMSSP_V2_TARGET_END);
+
+	va_end(args);
+
+	write_le16(&buffer.length, total_length);
+	write_le16(&buffer.space, total_length);
+	buffer_write(buf, buffer_offset, &buffer, sizeof(buffer));
+}
+
+static inline uint32_t ntlmssp_flags(uint32_t client_flags)
+{
+	uint32_t flags = NTLMSSP_NEGOTIATE_UNICODE |
+			 NTLMSSP_NEGOTIATE_NTLM |
+			 NTLMSSP_NEGOTIATE_TARGET_INFO;
+
+	if (client_flags & NTLMSSP_REQUEST_TARGET)
+		flags |= NTLMSSP_REQUEST_TARGET | NTLMSSP_TARGET_TYPE_SERVER;
+
+	return flags;
+}
+
+const struct ntlmssp_challenge *
+ntlmssp_create_challenge(pool_t pool, const struct ntlmssp_request *request, size_t *size)
+{
+	buffer_t *buf = buffer_create_dynamic(pool, sizeof(struct ntlmssp_challenge), 4096);
+	uint32_t flags = ntlmssp_flags(read_le32(&request->flags));
+	struct ntlmssp_challenge c;
+
+	memset(&c, 0, sizeof(c));
+	write_le64(&c.magic, NTLMSSP_MAGIC);
+	write_le32(&c.type, NTLMSSP_MSG_TYPE2);
+	write_le32(&c.flags, flags);
+	random_fill(c.challenge, sizeof(c.challenge));
+
+	buffer_write(buf, 0, &c, sizeof(c));
+
+	if (flags & NTLMSSP_TARGET_TYPE_SERVER)
+		ntlmssp_append_string(buf,
+			offsetof(struct ntlmssp_challenge, target_name),
+			my_hostname);
+
+	ntlmssp_append_target_info(buf, offsetof(struct ntlmssp_challenge, target_info),
+				   NTPLMSSP_V2_TARGET_FQDN, my_hostname,
+				   NTPLMSSP_V2_TARGET_END);
+
+	*size = buffer_get_used_size(buf);
+	return buffer_free_without_data(buf);
+}
+
+static int ntlmssp_check_buffer(struct ntlmssp_buffer *buffer, size_t data_size, const char **error)
+{
+	uint32_t offset = read_le32(&buffer->offset);
+
+	if (offset <= data_size) {
+		*error = "buffer offset out of bounds";
+		return 0;
+	}
+
+	if (offset + read_le16(&buffer->space) > data_size) {
+		*error = "buffer end out of bounds";
+		return 0;
+	}
+
+	return 1;
+}
+
+int ntlmssp_check_request(struct ntlmssp_request *request, size_t data_size, const char **error)
+{
+	uint32_t flags;
+
+	if (data_size < sizeof(struct ntlmssp_request)) {
+		*error = "request too short";
+		return 0;
+	}
+
+	if (read_le64(&request->magic) != NTLMSSP_MAGIC) {
+		*error = "signature mismatch";
+		return 0;
+	}
+
+	if (read_le32(&request->type) != NTLMSSP_MSG_TYPE1) {
+		*error = "message type mismatch";
+		return 0;
+	}
+
+	flags = read_le32(&request->flags);
+
+	if ((flags & NTLMSSP_NEGOTIATE_UNICODE) == 0) {
+		*error = "client doesn't advertise Unicode support";
+		return 0;
+	}
+
+	if ((flags & NTLMSSP_NEGOTIATE_NTLM) == 0) {
+		*error = "client doesn't advertise NTLM support";
+		return 0;
+	}
+
+	return 1;
+}
+
+int ntlmssp_check_response(struct ntlmssp_response *response, size_t data_size, const char **error)
+{
+	if (data_size < sizeof(struct ntlmssp_response)) {
+		*error = "response too short";
+		return 0;
+	}
+
+	if (read_le64(&response->magic) != NTLMSSP_MAGIC) {
+		*error = "signature mismatch";
+		return 0;
+	}
+
+	if (read_le32(&response->type) != NTLMSSP_MSG_TYPE3) {
+		*error = "message type mismatch";
+		return 0;
+	}
+
+	if (ntlmssp_check_buffer(&response->lm_response, data_size, error) ||
+	    ntlmssp_check_buffer(&response->ntlm_response, data_size, error) ||
+	    ntlmssp_check_buffer(&response->domain, data_size, error) ||
+	    ntlmssp_check_buffer(&response->user, data_size, error) ||
+	    ntlmssp_check_buffer(&response->workstation, data_size, error))
+		return 0;
+
+	return 1;
+}
diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-message.h dovecot-1.0-test30/src/lib-ntlm/ntlm-message.h
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-message.h	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm-message.h	2004-07-27 11:04:46.000000000 +0400
@@ -0,0 +1,10 @@
+#ifndef __NTLM_MESSAGE_H__
+#define __NTLM_MESSAGE_H__
+
+const struct ntlmssp_challenge *
+ntlmssp_create_challenge(pool_t pool, const struct ntlmssp_request *request, size_t *size);
+
+int ntlmssp_check_request(struct ntlmssp_request *request, size_t data_size, const char **error);
+int ntlmssp_check_response(struct ntlmssp_response *response, size_t data_size, const char **error);
+
+#endif	/* __NTLM_MESSAGE_H__ */




More information about the dovecot mailing list