[Dovecot] [PATCH 0/10] NTLM patchset submission

Andrey Panin pazke at donpac.ru
Wed Jul 28 16:15:27 EEST 2004


On 210, 07 28, 2004 at 12:36:30AM +0300, Timo Sirainen wrote:
> On 27.7.2004, at 16:18, Andrey Panin wrote:
> 
> >It contains common code in src/lib-ntlm directory, Samba compatible
> >NTLM password scheme and authentication mechanism itself.
> 
> So now Dovecot has md4, md5, sha1 and des code. Maybe there should be a 
> lib-crypto or something similiar for those.. Or anyway md4 and des 
> would be better in lib/ than lib-ntlm/.

md4 and hmac-md5 can be moved to lib/ easily. I'm not sure about usefulness
of ntlm-des.c outside of NTLM authentication code.

> >Please take a look.
> 
> HMAC-MD5 code looks quite similiar to 
> src/auth/password-scheme-cram-md5.c. Could they be merged somehow?

I'll take a look at them later today.

> You use "char var[0]" in end of some structures. I've tried to avoid 
> them so far everywhere since C89 doesn't support it. But I guess it's 
> common enough feature that it could be allowed the way C99 supports it, 
> var[].

We can safely remove this fields, now they serve to illustrate NTLM
message structure only. 

> +	int len = strlen(passwd);
> +	ucs2le_t wpwd[len + 1];
> 
> Another C99ism.. Are there enough C99 compilers that it'd be good idea 
> to require it? gcc of course works, but how about others?

Reworked using buffer API.

> +ntlmssp_v1_response(const unsigned char *hash,
> ..
> +	memset(des_hash + NTLMSSP_HASH_SIZE, 0, sizeof(hash) - 
> NTLMSSP_HASH_SIZE);
> 
> sizeof(des_hash)

Fixed.

> +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
> 
> offsetof() is ansi-c and defined in stddef.h

Removed.

> +const char * __ntlmssp_t_str(void *message, struct ntlmssp_buffer 
> *buffer)
> ..
> +	str_append_c(str, '\0');
> +
> +	return str_c(str);
> 
> str_c() nul-terminates the returned string so str_append_c() isn't 
> needed there.

Fixed.

> +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;
> +	}
> 
> offset >= data_size I'd think?

Fixed.

Updated patches attached.

-- 
Andrey Panin		| Linux and UNIX system administrator
pazke at donpac.ru		| PGP key: wwwkeys.pgp.net
-------------- next part --------------
diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-types.h dovecot-1.0-test30/src/lib-ntlm/ntlm-types.h
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-types.h	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm-types.h	2004-07-28 17:04:41.000000000 +0400
@@ -0,0 +1,130 @@
+/*
+ * NTLM data structures.
+ *
+ * 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.
+ */
+
+#ifndef __NTLM_TYPES_H__
+#define __NTLM_TYPES_H__
+
+#define NTLMSSP_MAGIC			0x005053534d4c544eULL
+
+#define	NTLMSSP_MSG_TYPE1		1
+#define	NTLMSSP_MSG_TYPE2		2
+#define	NTLMSSP_MSG_TYPE3		3
+
+#define NTLMSSP_DES_KEY_LENGTH		7
+
+#define NTLMSSP_CHALLENGE_SIZE		8
+
+#define NTLMSSP_HASH_SIZE		16
+#define NTLMSSP_RESPONSE_SIZE		24
+
+#define NTLMSSP_V2_HASH_SIZE		16
+#define NTLMSSP_V2_RESPONSE_SIZE	16
+
+
+typedef uint16_t ucs2le_t;
+
+struct ntlmssp_buffer {
+	uint16_t length;	/* length of the buffer */
+	uint16_t space;		/* space allocated space for buffer */
+	uint32_t offset;	/* data offset from the start of the message */
+};
+
+typedef struct ntlmssp_buffer ntlmssp_buffer_t;
+
+
+/*
+ * 
+ */
+struct ntlmssp_message {
+	uint64_t magic;			/* NTLMSSP\0 */
+	uint32_t type;			/* Should be 1 */
+};
+
+/*
+ * Type 1 message, client sends it to start NTLM authentication sequence.
+ */
+struct ntlmssp_request {
+	uint64_t magic;			/* NTLMSSP\0 */
+	uint32_t type;			/* Should be 1 */
+	uint32_t flags;			/* Flags */
+	ntlmssp_buffer_t domain;	/* Domain name (optional) */
+	ntlmssp_buffer_t workstation;	/* Workstation name (optional) */
+	/* Start of the data block */
+};
+
+/*
+ * The Type 2 message is sent by the server to the client in response to
+ * the client's Type 1 message. It serves to complete the negotiation of
+ * options with the client, and also provides a challenge to the client.
+ */
+struct ntlmssp_challenge {
+	uint64_t magic;			/* NTLMSSP\0 */
+	uint32_t type;			/* Should be 2 */
+	ntlmssp_buffer_t target_name;	/* Name of authentication target */
+	uint32_t flags;			/* Flags */
+	uint8_t challenge[NTLMSSP_CHALLENGE_SIZE];	/* Server challenge */
+	uint32_t context[2];		/* Local authentication context handle */
+	ntlmssp_buffer_t target_info;	/* Target information block (for NTLMv2) */
+	/* Start of the data block */
+};
+
+/*
+ * The Type 3 message is the final step in authentication. This message
+ * contains the client's responses to the Type 2 challenge, which demonstrate
+ * that the client has knowledge of the account password without sending the
+ * password directly. The Type 3 message also indicates the domain and username
+ * of the authenticating account, as well as the client workstation name.
+ */
+struct ntlmssp_response {
+	uint64_t magic;			/* NTLMSSP\0 */
+	uint32_t type;			/* Should be 3 */
+	ntlmssp_buffer_t lm_response;	/* LM/LMv2 recponse */
+	ntlmssp_buffer_t ntlm_response;	/* NTLM/NTLMv2 recponse */
+	ntlmssp_buffer_t domain;	/* Domain name */
+	ntlmssp_buffer_t user;		/* User name */
+	ntlmssp_buffer_t workstation;	/* Workstation name */
+	ntlmssp_buffer_t session_key;	/* Session key (optional */
+	uint32_t flags;			/* Flags (optional) */
+	/* Start of the data block */
+};
+
+/*
+ * NTLMv2 Target Information Block item.
+ */
+struct ntlmssp_v2_target_info {
+	uint16_t type;			/* Data type (see below) */
+	uint16_t length;		/* Length of content field */
+	/* Content (always in ucs2-le) */
+};
+
+/*
+ * NTLMv2 Target Information Block item data type.
+ */
+enum {
+	NTPLMSSP_V2_TARGET_END = 0,	/* End of list  */
+	NTPLMSSP_V2_TARGET_SERVER,	/* NetBIOS server name */ 
+	NTPLMSSP_V2_TARGET_DOMAIN,	/* NT Domain NetBIOS name */
+	NTPLMSSP_V2_TARGET_FQDN,	/* Fully qualified host name */
+	NTPLMSSP_V2_TARGET_DNS,		/* DNS domain name */
+};
+
+/*
+ * NTLMv2 Authentication data blob.
+ */
+struct ntlmssp_v2_blob {
+	uint32_t magic;			/* Should be 0x01010000 */
+	uint32_t reserved;		/* Always 0 */
+	uint64_t timestamp;		/* Timestamp */
+	uint32_t unknown;		/* Unknown something */
+	/* Target Information Block */
+};
+
+#endif	/* __NTLM_TYPES_H__ */
diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-flags.h dovecot-1.0-test30/src/lib-ntlm/ntlm-flags.h
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-flags.h	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm-flags.h	2004-07-27 15:48:44.000000000 +0400
@@ -0,0 +1,139 @@
+/*
+ * NTLM message flags.
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ */
+
+#ifndef __NTLM_FLAGS_H__
+#define __NTLM_FLAGS_H__
+
+/*
+ * Indicates that Unicode strings are supported for use in security
+ * buffer data. 
+ */
+#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 
+
+/*
+ * Indicates that OEM strings are supported for use in security buffer data.
+ */
+#define NTLMSSP_NEGOTIATE_OEM 0x00000002 
+
+/*
+ * Requests that the server's authentication realm be included in the
+ * Type 2 message. 
+ */
+#define NTLMSSP_REQUEST_TARGET 0x00000004 
+
+/*
+ * Specifies that authenticated communication between the client and server
+ * should carry a digital signature (message integrity). 
+ */
+#define NTLMSSP_NEGOTIATE_SIGN 0x00000010 
+
+/*
+ * Specifies that authenticated communication between the client and server
+ * should be encrypted (message confidentiality).
+ */
+#define NTLMSSP_NEGOTIATE_SEAL 0x00000020 
+
+/*
+ * Indicates that datagram authentication is being used. 
+ */
+#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 
+
+/*
+ * Indicates that the LAN Manager session key should be
+ * used for signing and sealing authenticated communications.
+ */
+#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 
+
+/*
+ * Indicates that NTLM authentication is being used. 
+ */
+#define NTLMSSP_NEGOTIATE_NTLM 0x00000200 
+
+/*
+ * Sent by the client in the Type 1 message to indicate that the name of the
+ * domain in which the client workstation has membership is included in the
+ * message. This is used by the server to determine whether the client is
+ * eligible for local authentication. 
+ */
+#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 
+
+/*
+ * Sent by the client in the Type 1 message to indicate that the client
+ * workstation's name is included in the message. This is used by the server
+ * to determine whether the client is eligible for local authentication.
+ */
+#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 
+
+/*
+ * Sent by the server to indicate that the server and client are on the same
+ * machine. Implies that the client may use the established local credentials
+ * for authentication instead of calculating a response to the challenge.
+ */
+#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000 
+
+/*
+ * Indicates that authenticated communication between the client and server
+ * should be signed with a "dummy" signature. 
+ */
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 
+
+/*
+ * Sent by the server in the Type 2 message to indicate that the target
+ * authentication realm is a domain.
+ */
+#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 
+
+/*
+ * Sent by the server in the Type 2 message to indicate that the target
+ * authentication realm is a server. 
+ */
+#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 
+
+/*
+ * Sent by the server in the Type 2 message to indicate that the target
+ * authentication realm is a share. Presumably, this is for share-level
+ * authentication. Usage is unclear. 
+ */
+#define NTLMSSP_TARGET_TYPE_SHARE 0x00040000 
+
+/*
+ * Indicates that the NTLM2 signing and sealing scheme should be used for
+ * protecting authenticated communications. Note that this refers to a
+ * particular session security scheme, and is not related to the use of
+ * NTLMv2 authentication.
+ */ 
+#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000 
+
+/*
+ * Sent by the server in the Type 2 message to indicate that it is including
+ * a Target Information block in the message. The Target Information block
+ * is used in the calculation of the NTLMv2 response.
+ */
+#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 
+
+/*
+ * Indicates that 128-bit encryption is supported. 
+ */
+#define NTLMSSP_NEGOTIATE_128 0x20000000 
+
+/*
+ * Indicates that the client will provide an encrypted master session key in the
+ * "Session Key" field of the Type 3 message. This is used in signing and sealing,
+ * and is RC4-encrypted using the previous session key as the encryption key.
+ */
+#define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000 
+
+/*
+ * Indicates that 56-bit encryption is supported.
+ */
+#define NTLMSSP_NEGOTIATE_56 0x80000000 
+
+#endif	/* __NTLM_FLAGS_H__ */
diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-byteorder.h dovecot-1.0-test30/src/lib-ntlm/ntlm-byteorder.h
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-byteorder.h	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm-byteorder.h	2004-07-27 14:01:57.000000000 +0400
@@ -0,0 +1,111 @@
+/*
+ * Little-endian data access functions.
+ *
+ * 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.
+ */
+
+#ifndef __NTLM_BYTEORDER_H__
+#define __NTLM_BYTEORDER_H__
+
+#if defined(__i386__) || defined(__vax__)
+
+static inline uint16_t read_le16(const void *addr)
+{
+	return *((uint16_t *) addr);
+}
+
+static inline uint32_t read_le32(const void *addr)
+{
+	return *((uint32_t *) addr);
+}
+
+static inline uint64_t read_le64(const void *addr)
+{
+	return *((uint64_t *) addr);
+}
+
+static inline void write_le16(void *addr, const uint16_t value)
+{
+	*((uint16_t *) addr) = value;
+}
+
+static inline void write_le32(void *addr, const uint32_t value)
+{
+	*((uint32_t *) addr) = value;
+}
+
+static inline void write_le64(void *addr, const uint64_t value)
+{
+	*((uint64_t *) addr) = value;
+}
+
+#else
+
+/*
+ * Dumb and slow, but byteorder and alignment independent code.
+ */
+
+#define readb(addr, pos, type) ((type)(*(((uint8_t *) (addr)) + (pos))))
+
+static inline uint16_t read_le16(const void *addr)
+{
+	return readb(addr, 0, uint16_t) | (readb(addr, 1, uint16_t) << 8);
+}
+
+static inline uint32_t read_le32(const void *addr)
+{
+	return   readb(addr, 0, uint32_t) |
+		(readb(addr, 1, uint32_t) << 8) |
+		(readb(addr, 2, uint32_t) << 16) |
+		(readb(addr, 3, uint32_t) << 24);
+}
+
+static inline uint64_t read_le64(const void *addr)
+{
+	return   readb(addr, 0, uint64_t) |
+		(readb(addr, 1, uint64_t) << 8) |
+		(readb(addr, 2, uint64_t) << 16) |
+		(readb(addr, 3, uint64_t) << 24) |
+		(readb(addr, 4, uint64_t) << 32) |
+		(readb(addr, 5, uint64_t) << 40) |
+		(readb(addr, 6, uint64_t) << 48) |
+		(readb(addr, 7, uint64_t) << 56);
+}
+
+#define writeb(addr, pos, value) \
+	*(((uint8_t *)(addr)) + (pos)) = (uint8_t) (value)
+
+static inline void write_le16(void *addr, const uint16_t value)
+{
+	writeb(addr, 0, value & 0xff);
+	writeb(addr, 1, (value >> 8) & 0xff);
+}
+
+static inline void write_le32(void *addr, const uint32_t value)
+{
+	writeb(addr, 0, value & 0xff);
+	writeb(addr, 1, (value >> 8) & 0xff);
+	writeb(addr, 2, (value >> 16) & 0xff);
+	writeb(addr, 3, (value >> 24) & 0xff);
+}
+
+static inline void write_le64(void *addr, const uint64_t value)
+{
+	writeb(addr, 0, value & 0xff);
+	writeb(addr, 1, (value >> 8) & 0xff);
+	writeb(addr, 2, (value >> 16) & 0xff);
+	writeb(addr, 3, (value >> 24) & 0xff);
+	writeb(addr, 4, (value >> 32) & 0xff);
+	writeb(addr, 5, (value >> 40) & 0xff);
+	writeb(addr, 6, (value >> 48) & 0xff);
+	writeb(addr, 7, (value >> 56) & 0xff);
+}
+
+#endif
+
+#endif	/* __NTLM_BYTEORDER_H__ */
diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm.h dovecot-1.0-test30/src/lib-ntlm/ntlm.h
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm.h	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm.h	2004-07-27 11:36:05.000000000 +0400
@@ -0,0 +1,34 @@
+#ifndef __NTLM_H__
+#define __NTLM_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "ntlm-types.h"
+#include "ntlm-flags.h"
+#include "ntlm-byteorder.h"
+#include "ntlm-encrypt.h"
+#include "ntlm-message.h"
+
+#define ntlmssp_buffer_data(message, buffer) \
+	__ntlmssp_buffer_data((message), &message->buffer)
+
+static inline const void * __ntlmssp_buffer_data(void * message, struct ntlmssp_buffer *buffer)
+{
+	return ((char *) message) + read_le32(&buffer->offset);
+}
+
+#define ntlmssp_buffer_length(message, buffer) \
+	__ntlmssp_buffer_length(&message->buffer)
+
+static inline unsigned int __ntlmssp_buffer_length(struct ntlmssp_buffer *buffer)
+{
+	return read_le16(&buffer->length);
+}
+
+#define ntlmssp_t_str(message, buffer) \
+	__ntlmssp_t_str((message), &message->buffer)
+
+const char * __ntlmssp_t_str(void *message, struct ntlmssp_buffer *buffer);
+
+#endif
-------------- next part --------------
diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-encrypt.c dovecot-1.0-test30/src/lib-ntlm/ntlm-encrypt.c
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-encrypt.c	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm-encrypt.c	2004-07-28 16:56:01.000000000 +0400
@@ -0,0 +1,112 @@
+/*
+ * NTLM and NTLMv2 hash generation.
+ *
+ * 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 <ctype.h>
+
+#include "lib.h"
+#include "buffer.h"
+#include "compat.h"
+#include "safe-memset.h"
+#include "md4.h"
+#include "hmac-md5.h"
+#include "ntlm.h"
+#include "ntlm-des.h"
+
+static unsigned char *
+t_unicode_str(const char *src, int ucase, size_t *size)
+{
+	buffer_t *wstr = buffer_create_dynamic(unsafe_data_stack_pool, 32, 4096);
+
+	for ( ; *src; src++) {
+		buffer_append_c(wstr, ucase ? i_toupper(*src) : *src);
+		buffer_append_c(wstr, '\0');
+	}
+
+	*size = buffer_get_used_size(wstr);
+	return buffer_free_without_data(wstr);
+}
+
+static void
+ntlmssp_des_encrypt_triad(const unsigned char *hash,
+		 	  const unsigned char *challenge,
+			  unsigned char *response)
+{
+	deshash(response, hash, challenge);
+	deshash(response + 8, hash + 7, challenge);
+	deshash(response + 16, hash + 14, challenge);
+}
+
+const unsigned char *
+ntlm_v1_hash(const char *passwd, unsigned char hash[NTLMSSP_HASH_SIZE])
+{
+	size_t len;
+	void *wpwd = t_unicode_str(passwd, 0, &len);
+
+	md4_get_digest(wpwd, len, hash);
+
+	safe_memset(wpwd, 0, len);
+
+	return hash;
+}
+
+static void
+hmac_md5_ucs2le_string_ucase(struct hmac_md5_context *ctx, const char *str)
+{
+	size_t len;
+	unsigned char *wstr = t_unicode_str(str, 1, &len);
+
+	hmac_md5_update(ctx, wstr, len);
+}
+
+static void
+ntlm_v2_hash(const char *user, const char *target,
+	     const unsigned char *hash_v1,
+	     unsigned char hash[NTLMSSP_V2_HASH_SIZE])
+{
+	struct hmac_md5_context ctx;
+
+	hmac_md5_init(&ctx, hash_v1, NTLMSSP_HASH_SIZE);
+	hmac_md5_ucs2le_string_ucase(&ctx, user);
+	if (target)
+		hmac_md5_ucs2le_string_ucase(&ctx, target);
+	hmac_md5_final(&ctx, hash);
+}
+
+void
+ntlmssp_v1_response(const unsigned char *hash,
+		    const unsigned char *challenge,
+		    unsigned char response[NTLMSSP_RESPONSE_SIZE])
+{
+	unsigned char des_hash[NTLMSSP_DES_KEY_LENGTH * 3];
+
+	memcpy(des_hash, hash, NTLMSSP_HASH_SIZE);
+	memset(des_hash + NTLMSSP_HASH_SIZE, 0, sizeof(des_hash) - NTLMSSP_HASH_SIZE);
+
+	ntlmssp_des_encrypt_triad(des_hash, challenge, response);
+}
+
+void
+ntlmssp_v2_response(const char *user, const char *target,
+		    const unsigned char *hash_v1,
+		    const unsigned char *challenge,
+		    const unsigned char *blob, size_t blob_size,
+		    unsigned char response[NTLMSSP_V2_RESPONSE_SIZE])
+{
+	struct hmac_md5_context ctx;
+	unsigned char hash[NTLMSSP_V2_HASH_SIZE];
+
+	ntlm_v2_hash(user, target, hash_v1, hash);
+
+	hmac_md5_init(&ctx, hash, NTLMSSP_V2_HASH_SIZE);
+	hmac_md5_update(&ctx, challenge, NTLMSSP_CHALLENGE_SIZE);
+	hmac_md5_update(&ctx, blob, blob_size);
+	hmac_md5_final(&ctx, response);
+}
diff -urpNX /usr/share/dontdiff dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-encrypt.h dovecot-1.0-test30/src/lib-ntlm/ntlm-encrypt.h
--- dovecot-1.0-test30.vanilla/src/lib-ntlm/ntlm-encrypt.h	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test30/src/lib-ntlm/ntlm-encrypt.h	2004-07-27 10:28:05.000000000 +0400
@@ -0,0 +1,17 @@
+#ifndef __NTLM_ENCRYPT__
+#define __NTLM_ENCRYPT__
+
+const unsigned char *
+ntlm_v1_hash(const char *passwd, unsigned char hash[NTLMSSP_HASH_SIZE]);
+
+void ntlmssp_v1_response(const unsigned char *hash,
+			 const unsigned char *challenge,
+			 unsigned char response[NTLMSSP_RESPONSE_SIZE]);
+
+void ntlmssp_v2_response(const char *user, const char *target,
+			 const unsigned char *hash_v1,
+			 const unsigned char *challenge,
+			 const unsigned char *blob, size_t blob_size,
+			 unsigned char response[NTLMSSP_V2_RESPONSE_SIZE]);
+
+#endif	/* __NTLM_ENCRYPT__ */
-------------- next part --------------
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-28 14:39:57.000000000 +0400
@@ -0,0 +1,229 @@
+/*
+ * 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"
+
+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);
+	}
+
+	return str_c(str);
+}
+
+static unsigned int append_string(buffer_t *buf, const char *str, int ucase)
+{
+	unsigned int length = 0;
+
+	for ( ; *str; str++) {
+		buffer_append_c(buf, ucase ? toupper(*str) : *str);
+		buffer_append_c(buf, 0);
+		length += sizeof(ucs2le_t);
+	}
+
+	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__ */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://dovecot.org/pipermail/dovecot/attachments/20040728/7c09a8ee/attachment-0001.bin>


More information about the dovecot mailing list