Hello all, as I promised some days ago here is NTLM (aka SPA, aka MSN) authentication support patchset. It contains common code in src/lib-ntlm directory, Samba compatible NTLM password scheme and authentication mechanism itself. All patches are against 1.0-test30. Please take a look. Best regards. -- Andrey Panin | Linux and UNIX system administrator pazke at donpac.ru | PGP key: wwwkeys.pgp.net
Andrey Panin
2004-Jul-27 13:18 UTC
[Dovecot] [PATCH 1/10] NTLM, structures, constants etc.
This patch adds some header files with NTLM reated definitions. src/lib-ntlm/ntlm-byteorder.h | 111 +++++++++++++++++++++++++++++++++ src/lib-ntlm/ntlm-flags.h | 139 ++++++++++++++++++++++++++++++++++++++++++ src/lib-ntlm/ntlm-types.h | 130 +++++++++++++++++++++++++++++++++++++++ src/lib-ntlm/ntlm.h | 34 ++++++++++ 4 files changed, 414 insertions(+) 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-27 15:47:25.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) */ + uint8_t data[0]; /* 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) */ + uint8_t data[0]; /* 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) */ + uint8_t data[0]; /* 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 */ + ucs2le_t content[0]; /* 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 */ + struct ntlmssp_v2_target_info target[0]; +}; + +#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
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/.> Please take a look.HMAC-MD5 code looks quite similiar to src/auth/password-scheme-cram-md5.c. Could they be merged somehow? 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[]. + 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? +ntlmssp_v1_response(const unsigned char *hash, .. + memset(des_hash + NTLMSSP_HASH_SIZE, 0, sizeof(hash) - NTLMSSP_HASH_SIZE); sizeof(des_hash) +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) offsetof() is ansi-c and defined in stddef.h +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. +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? -------------- next part -------------- A non-text attachment was scrubbed... Name: PGP.sig Type: application/pgp-signature Size: 186 bytes Desc: This is a digitally signed message part URL: <http://dovecot.org/pipermail/dovecot/attachments/20040728/88f9b49c/attachment-0001.bin>
On Tue, 2004-07-27 at 17:36, Timo Sirainen wrote:> 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[].var[1] is safe and then malloc-1. Still C89-ok.> + 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?No. gcc on debian woody (stable) requires --std=c99 to do it. Use alloca() if it's available (more widely so than C99) instead.