2
* Authentication module for the Micr$oft NTLM mechanism.
4
* This file is part of libESMTP, a library for submission of RFC 2822
5
* formatted electronic mail messages using the SMTP protocol described
8
* Copyright (C) 2002 Brian Stafford <brian@stafford.uklinux.net>
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public
12
* License as published by the Free Software Foundation; either
13
* version 2.1 of the License, or (at your option) any later version.
15
* This library is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public
21
* License along with this library; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31
#ifdef WORDS_BIGENDIAN
35
/* Must have at least 32 bits in an int (at least pending a more thorough
36
code review - this module is still experimental) */
37
#if SIZEOF_UNSIGNED_INT < 32 / 8
38
# error "unsigned int is less than 32 bits wide"
41
#if SIZEOF_UNSIGNED_SHORT == 16 / 8
42
typedef unsigned short unsigned16_t;
44
#include <sys/types.h>
45
typedef uint16 unsigned16_t;
48
#if SIZEOF_UNSIGNED_INT == 32 / 8
49
typedef unsigned int unsigned32_t;
50
#elif SIZEOF_UNSIGNED_LONG == 32 / 8
51
typedef unsigned long unsigned32_t;
53
#include <sys/types.h>
54
typedef uint32 unsigned32_t;
60
write_uint16 (char *buf, size_t offset, unsigned int value)
62
unsigned16_t i16 = value;
64
assert (sizeof i16 == 2);
65
#ifdef WORDS_BIGENDIAN
68
memcpy (buf + offset, &i16, sizeof i16);
72
write_uint32 (char *buf, size_t offset, unsigned int value)
74
unsigned32_t i32 = value;
76
assert (sizeof i32 == 4);
77
#ifdef WORDS_BIGENDIAN
80
memcpy (buf + offset, &i32, sizeof i32);
83
static inline unsigned int
84
read_uint16 (const char *buf, size_t offset)
88
assert (sizeof i16 == 2);
89
memcpy (&i16, buf + offset, sizeof i16);
90
#ifdef WORDS_BIGENDIAN
96
static inline unsigned int
97
read_uint32 (const char *buf, size_t offset)
101
assert (sizeof i32 == 4);
102
memcpy (&i32, buf + offset, sizeof i32);
103
#ifdef WORDS_BIGENDIAN
104
i32 = bswap_32 (i32);
110
write_string (char *buf, size_t offset, size_t *str_offset,
111
const void *data, size_t len)
115
write_uint16 (buf, offset, len);
116
write_uint16 (buf, offset + 2, len);
117
write_uint32 (buf, offset + 4, *str_offset);
119
memcpy (buf + *str_offset, data, len);
123
/* Offsets into on-the-wire NTLM structures */
124
#define PROTOCOL 0 /* "NTLMSSP" */
125
#define MSGTYPE 8 /* 1..3 */
127
#define T1FLAGS 12 /* 0xb203 */
128
#define T1DOMAIN 16 /* domain to authenticate in */
129
#define T1WKSTN 24 /* client workstation name */
132
#define T2AUTHTARGET 12 /* domain/server */
133
#define T2FLAGS 20 /* 0x8201 */
134
#define T2NONCE 24 /* server challenge */
135
#define T2RESERVED 32
138
#define T3LMRESPONSE 12 /* lanmanager hash */
139
#define T3NTRESPONSE 20 /* nt hash */
140
#define T3DOMAIN 28 /* domain to authenticate against */
141
#define T3USER 36 /* user name */
142
#define T3WKSTN 44 /* client workstation name */
143
#define T3SESSIONKEY 52 /* client workstation name */
144
#define T3FLAGS 60 /* 0xb203 */
147
static const char NTLMSSP[] = "NTLMSSP";
149
/* Build a NTLM type 1 structure in the buffer.
150
domain - the NT domain the workstation belongs to
151
workstation - the NT (netbios) name of the workstation */
153
ntlm_build_type_1 (char *buf, size_t buflen,
154
const char *domain, const char *workstation)
156
size_t offset = T1SIZE;
163
memcpy (buf, NTLMSSP, 8);
164
write_uint32 (buf, MSGTYPE, 1);
165
write_uint32 (buf, T1FLAGS, 0xB203);
170
len = strlen (domain);
171
if (offset + len > buflen)
173
lm_uccpy (string, len, domain);
175
write_string (buf, T1DOMAIN, &offset, string, len);
178
if (workstation != NULL)
180
len = strlen (workstation);
181
if (offset + len > buflen)
183
lm_uccpy (string, len, workstation);
185
write_string (buf, T1WKSTN, &offset, string, len);
189
/* Build a NTLM type 2 structure in the buffer */
191
ntlm_build_type_2 (char *buf, size_t buflen,
192
const unsigned char *nonce, const char *domain)
194
size_t offset = T2SIZE;
201
memcpy (buf, NTLMSSP, 8);
202
write_uint32 (buf, MSGTYPE, 2);
207
len = strlen (domain);
208
if (offset + 2 * len > buflen)
210
up = nt_unicode (lm_uccpy (string, len, domain), 2 * len);
212
write_string (buf, T2AUTHTARGET, &offset, up, len);
215
write_uint32 (buf, T2FLAGS, 0x8201);
216
memcpy (buf + T2NONCE, nonce, 8);
217
memset (buf + T2RESERVED, 0, 8);
221
/* Build a NTLM type 3 structure in the buffer */
223
ntlm_build_type_3 (char *buf, size_t buflen,
224
const unsigned char *lm_resp, const unsigned char *nt_resp,
225
const char *domain, const char *user, const char *workstation)
227
size_t offset = T3SIZE;
232
if (buflen + 24 + 24 < offset)
234
memcpy (buf, NTLMSSP, 8);
235
write_uint32 (buf, MSGTYPE, 3);
236
write_string (buf, T3LMRESPONSE, &offset, lm_resp, 24);
237
write_string (buf, T3NTRESPONSE, &offset, nt_resp, 24);
242
len = strlen (domain);
243
if (offset + 2 * len > buflen)
245
up = nt_unicode (lm_uccpy (string, len, domain), 2 * len);
247
write_string (buf, T3DOMAIN, &offset, up, 2 * len);
255
if (offset + 2 * len > buflen)
257
up = nt_unicode (lm_uccpy (string, len, user), 2 * len);
259
write_string (buf, T3USER, &offset, up, 2 * len);
264
if (workstation != NULL)
266
len = strlen (workstation);
267
if (offset + 2 * len > buflen)
269
up = nt_unicode (lm_uccpy (string, len, workstation), 2 * len);
271
write_string (buf, T3WKSTN, &offset, up, 2 * len);
274
write_string (buf, T3SESSIONKEY, &offset, NULL, 0);
275
write_uint32 (buf, T3FLAGS, 0x8201);
281
/* Parse a NTLM type 2 structure in the buffer (partial implementation).
282
Verify that the packet is a type 2 structure and copy the nonce to the
283
supplied buffer (which must be eight bytes long) */
285
ntlm_parse_type_2 (const char *buf, size_t buflen,
286
unsigned char *nonce, char **domain)
290
if (memcmp (buf, NTLMSSP, 8) != 0)
292
if (read_uint32 (buf, MSGTYPE) != 2)
295
memcpy (nonce, buf + T2NONCE, 8);