[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