Use C99 initialisations for iterators
[exim.git] / src / src / auths / auth-spa.c
CommitLineData
0756eb3c
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
5/*
6 * This file provides the necessary methods for authenticating with
7 * Microsoft's Secure Password Authentication.
8
9 * All the original code used here was torn by Marc Prud'hommeaux out of the
10 * Samba project (by Andrew Tridgell, Jeremy Allison, and others).
11
12 * Tom Kistner provided additional code, adding spa_build_auth_challenge() to
13 * support server authentication mode.
14
15 * Mark Lyda provided a patch to solve this problem:
16
17 - Exim is indicating in its Authentication Request message (Type 1) that it
18 can transmit text in either Unicode or OEM format.
19
20 - Microsoft's SMTP server (smtp.email.msn.com) is responding in its
21 Challenge message (Type 2) that it will be expecting the OEM format.
22
23 - Exim does not pay attention to the text format requested by Microsoft's
24 SMTP server and, instead, defaults to using the Unicode format.
25
26 * References:
27 * http://www.innovation.ch/java/ntlm.html
28 * http://www.kuro5hin.org/story/2002/4/28/1436/66154
29
30 * It seems that some systems have existing but different definitions of some
31 * of the following types. I received a complaint about "int16" causing
32 * compilation problems. So I (PH) have renamed them all, to be on the safe
33 * side, by adding 'x' on the end.
34
35 * typedef signed short int16;
36 * typedef unsigned short uint16;
37 * typedef unsigned uint32;
38 * typedef unsigned char uint8;
39
40 * The API is extremely simple:
41 * 1. Form a SPA authentication request based on the username
42 * and (optional) domain
43 * 2. Send the request to the server and get an SPA challenge
44 * 3. Build the challenge response and send it back.
45 *
46 * Example usage is as
47 * follows:
48 *
49int main (int argc, char ** argv)
50{
51 SPAAuthRequest request;
52 SPAAuthChallenge challenge;
53 SPAAuthResponse response;
54 char msgbuf[2048];
55 char buffer[512];
56 char *username, *password, *domain, *challenge_str;
57
58 if (argc < 3)
59 {
60 printf ("Usage: %s <username> <password> [SPA Challenge]\n",
61 argv [0]);
62 exit (1);
63 }
64
65 username = argv [1];
66 password = argv [2];
67 domain = 0;
68
69 spa_build_auth_request (&request, username, domain);
70
2f4df477 71 spa_bits_to_base64 (msgbuf, US &request,
0756eb3c
PH
72 spa_request_length(&request));
73
74 printf ("SPA Login request for username=%s:\n %s\n",
75 argv [1], msgbuf);
76
77 if (argc < 4)
78 {
79 printf ("Run: %s <username> <password> [NTLM Challenge] " \
80 "to complete authenitcation\n", argv [0]);
81 exit (0);
82 }
83
84 challenge_str = argv [3];
85
5903c6ff
JH
86 if (spa_base64_to_bits (CS &challenge, sizeof(challenge),
87 CCS (challenge_str))<0)
661d7dfa
PH
88 {
89 printf("bad base64 data in challenge: %s\n", challenge_str);
90 exit (1);
91 }
92
0756eb3c 93 spa_build_auth_response (&challenge, &response, username, password);
2f4df477 94 spa_bits_to_base64 (msgbuf, US &response,
0756eb3c
PH
95 spa_request_length(&response));
96
97 printf ("SPA Response to challenge:\n %s\n for " \
98 "username=%s, password=%s:\n %s\n",
99 argv[3], argv [1], argv [2], msgbuf);
100 return 0;
101}
102 *
103 *
104 * All the client code used here was torn by Marc Prud'hommeaux out of the
105 * Samba project (by Andrew Tridgell, Jeremy Allison, and others).
106 * Previous comments are below:
107 */
108
109/*
110 Unix SMB/Netbios implementation.
111 Version 1.9.
112
113 a partial implementation of DES designed for use in the
114 SMB authentication protocol
115
116 Copyright (C) Andrew Tridgell 1998
117
118 This program is free software; you can redistribute it and/or modify
119 it under the terms of the GNU General Public License as published by
120 the Free Software Foundation; either version 2 of the License, or
121 (at your option) any later version.
122
123 This program is distributed in the hope that it will be useful,
124 but WITHOUT ANY WARRANTY; without even the implied warranty of
125 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
126 GNU General Public License for more details.
127
128 You should have received a copy of the GNU General Public License
129 along with this program; if not, write to the Free Software
130 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
131*/
132
133
134/* NOTES:
135
136 This code makes no attempt to be fast! In fact, it is a very
137 slow implementation
138
139 This code is NOT a complete DES implementation. It implements only
140 the minimum necessary for SMB authentication, as used by all SMB
141 products (including every copy of Microsoft Windows95 ever sold)
142
143 In particular, it can only do a unchained forward DES pass. This
144 means it is not possible to use this code for encryption/decryption
145 of data, instead it is only useful as a "hash" algorithm.
146
147 There is no entry point into this code that allows normal DES operation.
148
149 I believe this means that this code does not come under ITAR
150 regulations but this is NOT a legal opinion. If you are concerned
151 about the applicability of ITAR regulations to this code then you
152 should confirm it for yourself (and maybe let me know if you come
153 up with a different answer to the one above)
154*/
155
2f4df477 156#define DEBUG_X(a,b) ;
0756eb3c
PH
157
158extern int DEBUGLEVEL;
159
2f4df477 160#include "../exim.h"
0756eb3c
PH
161#include "auth-spa.h"
162#include <assert.h>
0756eb3c 163
0756eb3c
PH
164
165#ifndef _BYTEORDER_H
2f4df477 166# define _BYTEORDER_H
0756eb3c 167
2f4df477 168# define RW_PCVAL(read,inbuf,outbuf,len) \
0756eb3c
PH
169 { if (read) { PCVAL (inbuf,0,outbuf,len); } \
170 else { PSCVAL(inbuf,0,outbuf,len); } }
171
2f4df477 172# define RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
0756eb3c
PH
173 { if (read) { if (big_endian) { RPIVAL(inbuf,0,outbuf,len); } else { PIVAL(inbuf,0,outbuf,len); } } \
174 else { if (big_endian) { RPSIVAL(inbuf,0,outbuf,len); } else { PSIVAL(inbuf,0,outbuf,len); } } }
175
2f4df477 176# define RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
0756eb3c
PH
177 { if (read) { if (big_endian) { RPSVAL(inbuf,0,outbuf,len); } else { PSVAL(inbuf,0,outbuf,len); } } \
178 else { if (big_endian) { RPSSVAL(inbuf,0,outbuf,len); } else { PSSVAL(inbuf,0,outbuf,len); } } }
179
2f4df477 180# define RW_CVAL(read, inbuf, outbuf, offset) \
0756eb3c
PH
181 { if (read) { (outbuf) = CVAL (inbuf,offset); } \
182 else { SCVAL(inbuf,offset,outbuf); } }
183
2f4df477 184# define RW_IVAL(read, big_endian, inbuf, outbuf, offset) \
0756eb3c
PH
185 { if (read) { (outbuf) = ((big_endian) ? RIVAL(inbuf,offset) : IVAL (inbuf,offset)); } \
186 else { if (big_endian) { RSIVAL(inbuf,offset,outbuf); } else { SIVAL(inbuf,offset,outbuf); } } }
187
2f4df477 188# define RW_SVAL(read, big_endian, inbuf, outbuf, offset) \
0756eb3c
PH
189 { if (read) { (outbuf) = ((big_endian) ? RSVAL(inbuf,offset) : SVAL (inbuf,offset)); } \
190 else { if (big_endian) { RSSVAL(inbuf,offset,outbuf); } else { SSVAL(inbuf,offset,outbuf); } } }
191
2f4df477 192# undef CAREFUL_ALIGNMENT
0756eb3c
PH
193
194/* we know that the 386 can handle misalignment and has the "right"
195 byteorder */
2f4df477
JH
196# ifdef __i386__
197# define CAREFUL_ALIGNMENT 0
198# endif
0756eb3c 199
2f4df477
JH
200# ifndef CAREFUL_ALIGNMENT
201# define CAREFUL_ALIGNMENT 1
202# endif
0756eb3c 203
2f4df477
JH
204# define CVAL(buf,pos) ((US (buf))[pos])
205# define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
206# define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
0756eb3c
PH
207
208
2f4df477 209# if CAREFUL_ALIGNMENT
0756eb3c 210
2f4df477
JH
211# define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
212# define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
213# define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
214# define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
215# define SVALS(buf,pos) ((int16x)SVAL(buf,pos))
216# define IVALS(buf,pos) ((int32x)IVAL(buf,pos))
217# define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16x)(val)))
218# define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32x)(val)))
219# define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16x)(val)))
220# define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32x)(val)))
0756eb3c 221
2f4df477 222# else /* CAREFUL_ALIGNMENT */
0756eb3c
PH
223
224/* this handles things for architectures like the 386 that can handle
225 alignment errors */
226/*
227 WARNING: This section is dependent on the length of int16x and int32x
228 being correct
229*/
230
231/* get single value from an SMB buffer */
5903c6ff
JH
232# define SVAL(buf,pos) (*(uint16x *)(CS (buf) + (pos)))
233# define IVAL(buf,pos) (*(uint32x *)(CS (buf) + (pos)))
234# define SVALS(buf,pos) (*(int16x *)(CS (buf) + (pos)))
235# define IVALS(buf,pos) (*(int32x *)(CS (buf) + (pos)))
0756eb3c
PH
236
237/* store single value in an SMB buffer */
2f4df477
JH
238# define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16x)(val))
239# define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32x)(val))
240# define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16x)(val))
241# define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32x)(val))
0756eb3c 242
2f4df477 243# endif /* CAREFUL_ALIGNMENT */
0756eb3c
PH
244
245/* macros for reading / writing arrays */
246
2f4df477 247# define SMBMACRO(macro,buf,pos,val,len,size) \
d7978c0f 248{ for (int l = 0; l < (len); l++) (val)[l] = macro((buf), (pos) + (size)*l); }
0756eb3c 249
2f4df477 250# define SSMBMACRO(macro,buf,pos,val,len,size) \
d7978c0f 251{ for (int l = 0; l < (len); l++) macro((buf), (pos) + (size)*l, (val)[l]); }
0756eb3c
PH
252
253/* reads multiple data from an SMB buffer */
2f4df477
JH
254# define PCVAL(buf,pos,val,len) SMBMACRO(CVAL,buf,pos,val,len,1)
255# define PSVAL(buf,pos,val,len) SMBMACRO(SVAL,buf,pos,val,len,2)
256# define PIVAL(buf,pos,val,len) SMBMACRO(IVAL,buf,pos,val,len,4)
257# define PCVALS(buf,pos,val,len) SMBMACRO(CVALS,buf,pos,val,len,1)
258# define PSVALS(buf,pos,val,len) SMBMACRO(SVALS,buf,pos,val,len,2)
259# define PIVALS(buf,pos,val,len) SMBMACRO(IVALS,buf,pos,val,len,4)
0756eb3c
PH
260
261/* stores multiple data in an SMB buffer */
2f4df477
JH
262# define PSCVAL(buf,pos,val,len) SSMBMACRO(SCVAL,buf,pos,val,len,1)
263# define PSSVAL(buf,pos,val,len) SSMBMACRO(SSVAL,buf,pos,val,len,2)
264# define PSIVAL(buf,pos,val,len) SSMBMACRO(SIVAL,buf,pos,val,len,4)
265# define PSCVALS(buf,pos,val,len) SSMBMACRO(SCVALS,buf,pos,val,len,1)
266# define PSSVALS(buf,pos,val,len) SSMBMACRO(SSVALS,buf,pos,val,len,2)
267# define PSIVALS(buf,pos,val,len) SSMBMACRO(SIVALS,buf,pos,val,len,4)
0756eb3c
PH
268
269
270/* now the reverse routines - these are used in nmb packets (mostly) */
2f4df477
JH
271# define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
272# define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
273
274# define RSVAL(buf,pos) SREV(SVAL(buf,pos))
275# define RSVALS(buf,pos) SREV(SVALS(buf,pos))
276# define RIVAL(buf,pos) IREV(IVAL(buf,pos))
277# define RIVALS(buf,pos) IREV(IVALS(buf,pos))
278# define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
279# define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
280# define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
281# define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
0756eb3c
PH
282
283/* reads multiple data from an SMB buffer (big-endian) */
2f4df477
JH
284# define RPSVAL(buf,pos,val,len) SMBMACRO(RSVAL,buf,pos,val,len,2)
285# define RPIVAL(buf,pos,val,len) SMBMACRO(RIVAL,buf,pos,val,len,4)
286# define RPSVALS(buf,pos,val,len) SMBMACRO(RSVALS,buf,pos,val,len,2)
287# define RPIVALS(buf,pos,val,len) SMBMACRO(RIVALS,buf,pos,val,len,4)
0756eb3c
PH
288
289/* stores multiple data in an SMB buffer (big-endian) */
2f4df477
JH
290# define RPSSVAL(buf,pos,val,len) SSMBMACRO(RSSVAL,buf,pos,val,len,2)
291# define RPSIVAL(buf,pos,val,len) SSMBMACRO(RSIVAL,buf,pos,val,len,4)
292# define RPSSVALS(buf,pos,val,len) SSMBMACRO(RSSVALS,buf,pos,val,len,2)
293# define RPSIVALS(buf,pos,val,len) SSMBMACRO(RSIVALS,buf,pos,val,len,4)
0756eb3c 294
2f4df477 295# define DBG_RW_PCVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
0756eb3c 296 { RW_PCVAL(read,inbuf,outbuf,len) \
2f4df477 297 DEBUG_X(5,("%s%04x %s: ", \
0756eb3c 298 tab_depth(depth), base,string)); \
2f4df477 299 if (charmode) print_asc(5, US (outbuf), (len)); else \
d7978c0f 300 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%02x ", (outbuf)[idx])); } \
2f4df477 301 DEBUG_X(5,("\n")); }
0756eb3c 302
2f4df477 303# define DBG_RW_PSVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
0756eb3c 304 { RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
2f4df477 305 DEBUG_X(5,("%s%04x %s: ", \
0756eb3c 306 tab_depth(depth), base,string)); \
2f4df477 307 if (charmode) print_asc(5, US (outbuf), 2*(len)); else \
d7978c0f 308 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%04x ", (outbuf)[idx])); } \
2f4df477 309 DEBUG_X(5,("\n")); }
0756eb3c 310
2f4df477 311# define DBG_RW_PIVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
0756eb3c 312 { RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
2f4df477 313 DEBUG_X(5,("%s%04x %s: ", \
0756eb3c 314 tab_depth(depth), base,string)); \
2f4df477 315 if (charmode) print_asc(5, US (outbuf), 4*(len)); else \
d7978c0f 316 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%08x ", (outbuf)[idx])); } \
2f4df477 317 DEBUG_X(5,("\n")); }
0756eb3c 318
2f4df477 319# define DBG_RW_CVAL(string,depth,base,read,inbuf,outbuf) \
0756eb3c 320 { RW_CVAL(read,inbuf,outbuf,0) \
2f4df477 321 DEBUG_X(5,("%s%04x %s: %02x\n", \
0756eb3c
PH
322 tab_depth(depth), base, string, outbuf)); }
323
2f4df477 324# define DBG_RW_SVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
0756eb3c 325 { RW_SVAL(read,big_endian,inbuf,outbuf,0) \
2f4df477 326 DEBUG_X(5,("%s%04x %s: %04x\n", \
0756eb3c
PH
327 tab_depth(depth), base, string, outbuf)); }
328
2f4df477 329# define DBG_RW_IVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
0756eb3c 330 { RW_IVAL(read,big_endian,inbuf,outbuf,0) \
2f4df477 331 DEBUG_X(5,("%s%04x %s: %08x\n", \
0756eb3c
PH
332 tab_depth(depth), base, string, outbuf)); }
333
334#endif /* _BYTEORDER_H */
335
2f4df477
JH
336void E_P16 (uschar *p14, uschar *p16);
337void E_P24 (uschar *p21, uschar *c8, uschar *p24);
338void D_P16 (uschar *p14, uschar *in, uschar *out);
339void SMBOWFencrypt (uschar passwd[16], uschar * c8, uschar p24[24]);
0756eb3c 340
2f4df477 341void mdfour (uschar *out, uschar *in, int n);
0756eb3c
PH
342
343
344/*
345 * base64.c -- base-64 conversion routines.
346 *
347 * For license terms, see the file COPYING in this directory.
348 *
349 * This base 64 encoding is defined in RFC2045 section 6.8,
350 * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
351 * scheme used here.
352 */
353
354static const char base64digits[] =
355 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
356
b8fc75b3 357#define BAD (char) -1
0756eb3c
PH
358static const char base64val[] = {
359 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
360 BAD,
361 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
362 BAD,
363 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 62, BAD, BAD, BAD,
364 63,
365 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, BAD, BAD, BAD, BAD, BAD, BAD,
366 BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
367 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, BAD, BAD, BAD, BAD, BAD,
368 BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
369 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, BAD, BAD, BAD, BAD, BAD
370};
371#define DECODE64(c) (isascii(c) ? base64val[c] : BAD)
372
373void
2f4df477 374spa_bits_to_base64 (uschar *out, const uschar *in, int inlen)
0756eb3c
PH
375/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
376{
377 for (; inlen >= 3; inlen -= 3)
378 {
379 *out++ = base64digits[in[0] >> 2];
380 *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
381 *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
382 *out++ = base64digits[in[2] & 0x3f];
383 in += 3;
384 }
385 if (inlen > 0)
386 {
2f4df477 387 uschar fragment;
0756eb3c
PH
388
389 *out++ = base64digits[in[0] >> 2];
390 fragment = (in[0] << 4) & 0x30;
391 if (inlen > 1)
392 fragment |= in[1] >> 4;
393 *out++ = base64digits[fragment];
394 *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
395 *out++ = '=';
396 }
397 *out = '\0';
398}
399
85b87bc2
PH
400
401/* The outlength parameter was added by PH, December 2004 */
402
0756eb3c 403int
85b87bc2 404spa_base64_to_bits (char *out, int outlength, const char *in)
0756eb3c
PH
405/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
406{
407 int len = 0;
2f4df477 408 register uschar digit1, digit2, digit3, digit4;
0756eb3c
PH
409
410 if (in[0] == '+' && in[1] == ' ')
411 in += 2;
412 if (*in == '\r')
413 return (0);
414
415 do
416 {
85b87bc2
PH
417 if (len >= outlength) /* Added by PH */
418 return (-1); /* Added by PH */
0756eb3c
PH
419 digit1 = in[0];
420 if (DECODE64 (digit1) == BAD)
421 return (-1);
422 digit2 = in[1];
423 if (DECODE64 (digit2) == BAD)
424 return (-1);
425 digit3 = in[2];
426 if (digit3 != '=' && DECODE64 (digit3) == BAD)
427 return (-1);
428 digit4 = in[3];
429 if (digit4 != '=' && DECODE64 (digit4) == BAD)
430 return (-1);
431 in += 4;
432 *out++ = (DECODE64 (digit1) << 2) | (DECODE64 (digit2) >> 4);
433 ++len;
434 if (digit3 != '=')
435 {
85b87bc2
PH
436 if (len >= outlength) /* Added by PH */
437 return (-1); /* Added by PH */
0756eb3c
PH
438 *out++ =
439 ((DECODE64 (digit2) << 4) & 0xf0) | (DECODE64 (digit3) >> 2);
440 ++len;
441 if (digit4 != '=')
442 {
85b87bc2
PH
443 if (len >= outlength) /* Added by PH */
444 return (-1); /* Added by PH */
0756eb3c
PH
445 *out++ = ((DECODE64 (digit3) << 6) & 0xc0) | DECODE64 (digit4);
446 ++len;
447 }
448 }
449 }
450 while (*in && *in != '\r' && digit4 != '=');
451
452 return (len);
453}
454
455
2f4df477 456static uschar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
0756eb3c
PH
457 1, 58, 50, 42, 34, 26, 18,
458 10, 2, 59, 51, 43, 35, 27,
459 19, 11, 3, 60, 52, 44, 36,
460 63, 55, 47, 39, 31, 23, 15,
461 7, 62, 54, 46, 38, 30, 22,
462 14, 6, 61, 53, 45, 37, 29,
463 21, 13, 5, 28, 20, 12, 4
464};
465
2f4df477 466static uschar perm2[48] = { 14, 17, 11, 24, 1, 5,
0756eb3c
PH
467 3, 28, 15, 6, 21, 10,
468 23, 19, 12, 4, 26, 8,
469 16, 7, 27, 20, 13, 2,
470 41, 52, 31, 37, 47, 55,
471 30, 40, 51, 45, 33, 48,
472 44, 49, 39, 56, 34, 53,
473 46, 42, 50, 36, 29, 32
474};
475
2f4df477 476static uschar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
0756eb3c
PH
477 60, 52, 44, 36, 28, 20, 12, 4,
478 62, 54, 46, 38, 30, 22, 14, 6,
479 64, 56, 48, 40, 32, 24, 16, 8,
480 57, 49, 41, 33, 25, 17, 9, 1,
481 59, 51, 43, 35, 27, 19, 11, 3,
482 61, 53, 45, 37, 29, 21, 13, 5,
483 63, 55, 47, 39, 31, 23, 15, 7
484};
485
2f4df477 486static uschar perm4[48] = { 32, 1, 2, 3, 4, 5,
0756eb3c
PH
487 4, 5, 6, 7, 8, 9,
488 8, 9, 10, 11, 12, 13,
489 12, 13, 14, 15, 16, 17,
490 16, 17, 18, 19, 20, 21,
491 20, 21, 22, 23, 24, 25,
492 24, 25, 26, 27, 28, 29,
493 28, 29, 30, 31, 32, 1
494};
495
2f4df477 496static uschar perm5[32] = { 16, 7, 20, 21,
0756eb3c
PH
497 29, 12, 28, 17,
498 1, 15, 23, 26,
499 5, 18, 31, 10,
500 2, 8, 24, 14,
501 32, 27, 3, 9,
502 19, 13, 30, 6,
503 22, 11, 4, 25
504};
505
506
2f4df477 507static uschar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
0756eb3c
PH
508 39, 7, 47, 15, 55, 23, 63, 31,
509 38, 6, 46, 14, 54, 22, 62, 30,
510 37, 5, 45, 13, 53, 21, 61, 29,
511 36, 4, 44, 12, 52, 20, 60, 28,
512 35, 3, 43, 11, 51, 19, 59, 27,
513 34, 2, 42, 10, 50, 18, 58, 26,
514 33, 1, 41, 9, 49, 17, 57, 25
515};
516
517
2f4df477 518static uschar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
0756eb3c 519
2f4df477 520static uschar sbox[8][4][16] = {
0756eb3c
PH
521 {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
522 {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
523 {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
524 {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
525
526 {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
527 {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
528 {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
529 {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
530
531 {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
532 {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
533 {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
534 {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
535
536 {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
537 {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
538 {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
539 {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
540
541 {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
542 {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
543 {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
544 {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
545
546 {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
547 {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
548 {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
549 {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
550
551 {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
552 {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
553 {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
554 {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
555
556 {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
557 {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
558 {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
559 {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
560};
561
562static void
2f4df477 563permute (char *out, char *in, uschar * p, int n)
0756eb3c 564{
d7978c0f
JH
565for (int i = 0; i < n; i++)
566 out[i] = in[p[i] - 1];
0756eb3c
PH
567}
568
569static void
570lshift (char *d, int count, int n)
571{
d7978c0f
JH
572char out[64];
573for (int i = 0; i < n; i++)
574 out[i] = d[(i + count) % n];
575for (int i = 0; i < n; i++)
576 d[i] = out[i];
0756eb3c
PH
577}
578
579static void
580concat (char *out, char *in1, char *in2, int l1, int l2)
581{
d7978c0f
JH
582while (l1--)
583 *out++ = *in1++;
584while (l2--)
585 *out++ = *in2++;
0756eb3c
PH
586}
587
588static void
589xor (char *out, char *in1, char *in2, int n)
590{
d7978c0f
JH
591for (int i = 0; i < n; i++)
592 out[i] = in1[i] ^ in2[i];
0756eb3c
PH
593}
594
595static void
596dohash (char *out, char *in, char *key, int forw)
597{
d7978c0f
JH
598int i, j, k;
599char pk1[56];
600char c[28];
601char d[28];
602char cd[56];
603char ki[16][48];
604char pd1[64];
605char l[32], r[32];
606char rl[64];
607
608permute (pk1, key, perm1, 56);
609
610for (i = 0; i < 28; i++)
611 c[i] = pk1[i];
612for (i = 0; i < 28; i++)
613 d[i] = pk1[i + 28];
614
615for (i = 0; i < 16; i++)
616 {
617 lshift (c, sc[i], 28);
618 lshift (d, sc[i], 28);
619
620 concat (cd, c, d, 28, 28);
621 permute (ki[i], cd, perm2, 48);
622 }
0756eb3c 623
d7978c0f 624permute (pd1, in, perm3, 64);
0756eb3c 625
d7978c0f
JH
626for (j = 0; j < 32; j++)
627 {
628 l[j] = pd1[j];
629 r[j] = pd1[j + 32];
630 }
0756eb3c 631
d7978c0f
JH
632for (i = 0; i < 16; i++)
633 {
634 char er[48];
635 char erk[48];
636 char b[8][6];
637 char cb[32];
638 char pcb[32];
639 char r2[32];
0756eb3c 640
d7978c0f 641 permute (er, r, perm4, 48);
0756eb3c 642
d7978c0f 643 xor (erk, er, ki[forw ? i : 15 - i], 48);
0756eb3c 644
d7978c0f
JH
645 for (j = 0; j < 8; j++)
646 for (k = 0; k < 6; k++)
647 b[j][k] = erk[j * 6 + k];
0756eb3c 648
d7978c0f
JH
649 for (j = 0; j < 8; j++)
650 {
651 int m, n;
652 m = (b[j][0] << 1) | b[j][5];
0756eb3c 653
d7978c0f 654 n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << 1) | b[j][4];
0756eb3c 655
d7978c0f
JH
656 for (k = 0; k < 4; k++)
657 b[j][k] = (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
658 }
0756eb3c 659
d7978c0f
JH
660 for (j = 0; j < 8; j++)
661 for (k = 0; k < 4; k++)
662 cb[j * 4 + k] = b[j][k];
663 permute (pcb, cb, perm5, 32);
0756eb3c 664
d7978c0f 665 xor (r2, l, pcb, 32);
0756eb3c 666
d7978c0f
JH
667 for (j = 0; j < 32; j++)
668 l[j] = r[j];
0756eb3c 669
d7978c0f
JH
670 for (j = 0; j < 32; j++)
671 r[j] = r2[j];
672 }
0756eb3c 673
d7978c0f 674concat (rl, r, l, 32, 32);
0756eb3c 675
d7978c0f 676permute (out, rl, perm6, 64);
0756eb3c
PH
677}
678
679static void
2f4df477 680str_to_key (uschar *str, uschar *key)
0756eb3c 681{
d7978c0f
JH
682int i;
683
684key[0] = str[0] >> 1;
685key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
686key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
687key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
688key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
689key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
690key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
691key[7] = str[6] & 0x7F;
692for (i = 0; i < 8; i++)
693 key[i] = (key[i] << 1);
0756eb3c
PH
694}
695
696
697static void
2f4df477 698smbhash (uschar *out, uschar *in, uschar *key, int forw)
0756eb3c 699{
d7978c0f
JH
700int i;
701char outb[64];
702char inb[64];
703char keyb[64];
704uschar key2[8];
705
706str_to_key (key, key2);
707
708for (i = 0; i < 64; i++)
709 {
710 inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
711 keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
712 outb[i] = 0;
713 }
0756eb3c 714
d7978c0f 715dohash (outb, inb, keyb, forw);
0756eb3c 716
d7978c0f
JH
717for (i = 0; i < 8; i++)
718 out[i] = 0;
0756eb3c 719
d7978c0f
JH
720for (i = 0; i < 64; i++)
721 if (outb[i])
722 out[i / 8] |= (1 << (7 - (i % 8)));
0756eb3c
PH
723}
724
725void
2f4df477 726E_P16 (uschar *p14, uschar *p16)
0756eb3c 727{
d7978c0f
JH
728uschar sp8[8] = { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
729smbhash (p16, sp8, p14, 1);
730smbhash (p16 + 8, sp8, p14 + 7, 1);
0756eb3c
PH
731}
732
733void
2f4df477 734E_P24 (uschar *p21, uschar *c8, uschar *p24)
0756eb3c 735{
d7978c0f
JH
736smbhash (p24, c8, p21, 1);
737smbhash (p24 + 8, c8, p21 + 7, 1);
738smbhash (p24 + 16, c8, p21 + 14, 1);
0756eb3c
PH
739}
740
741void
2f4df477 742D_P16 (uschar *p14, uschar *in, uschar *out)
0756eb3c 743{
d7978c0f
JH
744smbhash (out, in, p14, 0);
745smbhash (out + 8, in + 8, p14 + 7, 0);
0756eb3c
PH
746}
747
748/****************************************************************************
749 Like strncpy but always null terminates. Make sure there is room!
750 The variable n should always be one less than the available size.
751****************************************************************************/
752
753char *
754StrnCpy (char *dest, const char *src, size_t n)
755{
d7978c0f
JH
756char *d = dest;
757if (!dest)
758 return (NULL);
759if (!src)
760 {
761 *dest = 0;
0756eb3c 762 return (dest);
d7978c0f
JH
763 }
764while (n-- && (*d++ = *src++));
765*d = 0;
766return (dest);
0756eb3c
PH
767}
768
769size_t
770skip_multibyte_char (char c)
771{
d7978c0f
JH
772/* bogus if to get rid of unused compiler warning */
773if (c)
774 return 0;
775else
776 return 0;
0756eb3c
PH
777}
778
779
780/*******************************************************************
781safe string copy into a known length string. maxlength does not
782include the terminating zero.
783********************************************************************/
784
785char *
786safe_strcpy (char *dest, const char *src, size_t maxlength)
787{
d7978c0f 788size_t len;
0756eb3c 789
d7978c0f
JH
790if (!dest)
791 {
792 DEBUG_X (0, ("ERROR: NULL dest in safe_strcpy\n"));
793 return NULL;
794 }
0756eb3c 795
d7978c0f
JH
796if (!src)
797 {
798 *dest = 0;
799 return dest;
800 }
0756eb3c 801
d7978c0f 802len = strlen (src);
0756eb3c 803
d7978c0f
JH
804if (len > maxlength)
805 {
806 DEBUG_X (0, ("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
807 (int) (len - maxlength), src));
808 len = maxlength;
809 }
0756eb3c 810
d7978c0f
JH
811memcpy (dest, src, len);
812dest[len] = 0;
813return dest;
0756eb3c
PH
814}
815
816
817void
818strupper (char *s)
819{
d7978c0f
JH
820while (*s)
821 {
822 size_t skip = skip_multibyte_char (*s);
823 if (skip != 0)
824 s += skip;
825 else
826 {
827 if (islower ((uschar)(*s)))
828 *s = toupper (*s);
829 s++;
830 }
831 }
0756eb3c
PH
832}
833
834
835/*
836 This implements the X/Open SMB password encryption
837 It takes a password, a 8 byte "crypt key" and puts 24 bytes of
838 encrypted password into p24
839 */
840
841void
2f4df477 842spa_smb_encrypt (uschar * passwd, uschar * c8, uschar * p24)
0756eb3c 843{
d7978c0f 844uschar p14[15], p21[21];
0756eb3c 845
d7978c0f
JH
846memset (p21, '\0', 21);
847memset (p14, '\0', 14);
848StrnCpy (CS p14, CS passwd, 14);
0756eb3c 849
d7978c0f
JH
850strupper (CS p14);
851E_P16 (p14, p21);
0756eb3c 852
d7978c0f 853SMBOWFencrypt (p21, c8, p24);
0756eb3c
PH
854
855#ifdef DEBUG_PASSWORD
d7978c0f
JH
856DEBUG_X (100, ("spa_smb_encrypt: lm#, challenge, response\n"));
857dump_data (100, CS p21, 16);
858dump_data (100, CS c8, 8);
859dump_data (100, CS p24, 24);
0756eb3c
PH
860#endif
861}
862
863/* Routines for Windows NT MD4 Hash functions. */
864static int
865_my_wcslen (int16x * str)
866{
d7978c0f
JH
867int len = 0;
868while (*str++ != 0)
869 len++;
870return len;
0756eb3c
PH
871}
872
873/*
874 * Convert a string into an NT UNICODE string.
875 * Note that regardless of processor type
876 * this must be in intel (little-endian)
877 * format.
878 */
879
880static int
2f4df477 881_my_mbstowcs (int16x * dst, uschar * src, int len)
0756eb3c 882{
d7978c0f
JH
883int i;
884int16x val;
885
886for (i = 0; i < len; i++)
887 {
888 val = *src;
889 SSVAL (dst, 0, val);
890 dst++;
891 src++;
892 if (val == 0)
893 break;
894 }
895return i;
0756eb3c
PH
896}
897
898/*
899 * Creates the MD4 Hash of the users password in NT UNICODE.
900 */
901
902void
2f4df477 903E_md4hash (uschar * passwd, uschar * p16)
0756eb3c 904{
d7978c0f
JH
905int len;
906int16x wpwd[129];
907
908/* Password cannot be longer than 128 characters */
909len = strlen (CS passwd);
910if (len > 128)
911 len = 128;
912/* Password must be converted to NT unicode */
913_my_mbstowcs (wpwd, passwd, len);
914wpwd[len] = 0; /* Ensure string is null terminated */
915/* Calculate length in bytes */
916len = _my_wcslen (wpwd) * sizeof (int16x);
917
918mdfour (p16, US wpwd, len);
0756eb3c
PH
919}
920
921/* Does both the NT and LM owfs of a user's password */
922void
2f4df477 923nt_lm_owf_gen (char *pwd, uschar nt_p16[16], uschar p16[16])
0756eb3c 924{
d7978c0f 925char passwd[130];
0756eb3c 926
d7978c0f
JH
927memset (passwd, '\0', 130);
928safe_strcpy (passwd, pwd, sizeof (passwd) - 1);
0756eb3c 929
d7978c0f
JH
930/* Calculate the MD4 hash (NT compatible) of the password */
931memset (nt_p16, '\0', 16);
932E_md4hash (US passwd, nt_p16);
0756eb3c
PH
933
934#ifdef DEBUG_PASSWORD
d7978c0f
JH
935DEBUG_X (100, ("nt_lm_owf_gen: pwd, nt#\n"));
936dump_data (120, passwd, strlen (passwd));
937dump_data (100, CS nt_p16, 16);
0756eb3c
PH
938#endif
939
d7978c0f
JH
940/* Mangle the passwords into Lanman format */
941passwd[14] = '\0';
942strupper (passwd);
0756eb3c 943
d7978c0f 944/* Calculate the SMB (lanman) hash functions of the password */
0756eb3c 945
d7978c0f
JH
946memset (p16, '\0', 16);
947E_P16 (US passwd, US p16);
0756eb3c
PH
948
949#ifdef DEBUG_PASSWORD
d7978c0f
JH
950DEBUG_X (100, ("nt_lm_owf_gen: pwd, lm#\n"));
951dump_data (120, passwd, strlen (passwd));
952dump_data (100, CS p16, 16);
0756eb3c 953#endif
d7978c0f
JH
954/* clear out local copy of user's password (just being paranoid). */
955memset (passwd, '\0', sizeof (passwd));
0756eb3c
PH
956}
957
958/* Does the des encryption from the NT or LM MD4 hash. */
959void
2f4df477 960SMBOWFencrypt (uschar passwd[16], uschar * c8, uschar p24[24])
0756eb3c 961{
d7978c0f 962uschar p21[21];
0756eb3c 963
d7978c0f 964memset (p21, '\0', 21);
0756eb3c 965
d7978c0f
JH
966memcpy (p21, passwd, 16);
967E_P24 (p21, c8, p24);
0756eb3c
PH
968}
969
970/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
971void
2f4df477 972NTLMSSPOWFencrypt (uschar passwd[8], uschar * ntlmchalresp, uschar p24[24])
0756eb3c 973{
d7978c0f 974uschar p21[21];
0756eb3c 975
d7978c0f
JH
976memset (p21, '\0', 21);
977memcpy (p21, passwd, 8);
978memset (p21 + 8, 0xbd, 8);
0756eb3c 979
d7978c0f 980E_P24 (p21, ntlmchalresp, p24);
0756eb3c 981#ifdef DEBUG_PASSWORD
d7978c0f
JH
982DEBUG_X (100, ("NTLMSSPOWFencrypt: p21, c8, p24\n"));
983dump_data (100, CS p21, 21);
984dump_data (100, CS ntlmchalresp, 8);
985dump_data (100, CS p24, 24);
0756eb3c
PH
986#endif
987}
988
989
990/* Does the NT MD4 hash then des encryption. */
991
992void
2f4df477 993spa_smb_nt_encrypt (uschar * passwd, uschar * c8, uschar * p24)
0756eb3c 994{
d7978c0f 995uschar p21[21];
0756eb3c 996
d7978c0f 997memset (p21, '\0', 21);
0756eb3c 998
d7978c0f
JH
999E_md4hash (passwd, p21);
1000SMBOWFencrypt (p21, c8, p24);
0756eb3c
PH
1001
1002#ifdef DEBUG_PASSWORD
d7978c0f
JH
1003DEBUG_X (100, ("spa_smb_nt_encrypt: nt#, challenge, response\n"));
1004dump_data (100, CS p21, 16);
1005dump_data (100, CS c8, 8);
1006dump_data (100, CS p24, 24);
0756eb3c
PH
1007#endif
1008}
1009
1010static uint32x A, B, C, D;
1011
1012static uint32x
1013F (uint32x X, uint32x Y, uint32x Z)
1014{
d7978c0f 1015return (X & Y) | ((~X) & Z);
0756eb3c
PH
1016}
1017
1018static uint32x
1019G (uint32x X, uint32x Y, uint32x Z)
1020{
d7978c0f 1021return (X & Y) | (X & Z) | (Y & Z);
0756eb3c
PH
1022}
1023
1024static uint32x
1025H (uint32x X, uint32x Y, uint32x Z)
1026{
d7978c0f 1027return X ^ Y ^ Z;
0756eb3c
PH
1028}
1029
1030static uint32x
1031lshift_a (uint32x x, int s)
1032{
d7978c0f
JH
1033x &= 0xFFFFFFFF;
1034return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
0756eb3c
PH
1035}
1036
1037#define ROUND1(a,b,c,d,k,s) a = lshift_a(a + F(b,c,d) + X[k], s)
1038#define ROUND2(a,b,c,d,k,s) a = lshift_a(a + G(b,c,d) + X[k] + (uint32x)0x5A827999,s)
1039#define ROUND3(a,b,c,d,k,s) a = lshift_a(a + H(b,c,d) + X[k] + (uint32x)0x6ED9EBA1,s)
1040
1041/* this applies md4 to 64 byte chunks */
1042static void
1043spa_mdfour64 (uint32x * M)
1044{
d7978c0f
JH
1045int j;
1046uint32x AA, BB, CC, DD;
1047uint32x X[16];
1048
1049for (j = 0; j < 16; j++)
1050 X[j] = M[j];
1051
1052AA = A;
1053BB = B;
1054CC = C;
1055DD = D;
1056
1057ROUND1 (A, B, C, D, 0, 3);
1058ROUND1 (D, A, B, C, 1, 7);
1059ROUND1 (C, D, A, B, 2, 11);
1060ROUND1 (B, C, D, A, 3, 19);
1061ROUND1 (A, B, C, D, 4, 3);
1062ROUND1 (D, A, B, C, 5, 7);
1063ROUND1 (C, D, A, B, 6, 11);
1064ROUND1 (B, C, D, A, 7, 19);
1065ROUND1 (A, B, C, D, 8, 3);
1066ROUND1 (D, A, B, C, 9, 7);
1067ROUND1 (C, D, A, B, 10, 11);
1068ROUND1 (B, C, D, A, 11, 19);
1069ROUND1 (A, B, C, D, 12, 3);
1070ROUND1 (D, A, B, C, 13, 7);
1071ROUND1 (C, D, A, B, 14, 11);
1072ROUND1 (B, C, D, A, 15, 19);
1073
1074ROUND2 (A, B, C, D, 0, 3);
1075ROUND2 (D, A, B, C, 4, 5);
1076ROUND2 (C, D, A, B, 8, 9);
1077ROUND2 (B, C, D, A, 12, 13);
1078ROUND2 (A, B, C, D, 1, 3);
1079ROUND2 (D, A, B, C, 5, 5);
1080ROUND2 (C, D, A, B, 9, 9);
1081ROUND2 (B, C, D, A, 13, 13);
1082ROUND2 (A, B, C, D, 2, 3);
1083ROUND2 (D, A, B, C, 6, 5);
1084ROUND2 (C, D, A, B, 10, 9);
1085ROUND2 (B, C, D, A, 14, 13);
1086ROUND2 (A, B, C, D, 3, 3);
1087ROUND2 (D, A, B, C, 7, 5);
1088ROUND2 (C, D, A, B, 11, 9);
1089ROUND2 (B, C, D, A, 15, 13);
1090
1091ROUND3 (A, B, C, D, 0, 3);
1092ROUND3 (D, A, B, C, 8, 9);
1093ROUND3 (C, D, A, B, 4, 11);
1094ROUND3 (B, C, D, A, 12, 15);
1095ROUND3 (A, B, C, D, 2, 3);
1096ROUND3 (D, A, B, C, 10, 9);
1097ROUND3 (C, D, A, B, 6, 11);
1098ROUND3 (B, C, D, A, 14, 15);
1099ROUND3 (A, B, C, D, 1, 3);
1100ROUND3 (D, A, B, C, 9, 9);
1101ROUND3 (C, D, A, B, 5, 11);
1102ROUND3 (B, C, D, A, 13, 15);
1103ROUND3 (A, B, C, D, 3, 3);
1104ROUND3 (D, A, B, C, 11, 9);
1105ROUND3 (C, D, A, B, 7, 11);
1106ROUND3 (B, C, D, A, 15, 15);
1107
1108A += AA;
1109B += BB;
1110C += CC;
1111D += DD;
1112
1113A &= 0xFFFFFFFF;
1114B &= 0xFFFFFFFF;
1115C &= 0xFFFFFFFF;
1116D &= 0xFFFFFFFF;
1117
1118for (j = 0; j < 16; j++)
1119 X[j] = 0;
0756eb3c
PH
1120}
1121
1122static void
2f4df477 1123copy64 (uint32x * M, uschar *in)
0756eb3c 1124{
d7978c0f 1125int i;
0756eb3c 1126
d7978c0f
JH
1127for (i = 0; i < 16; i++)
1128 M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
1129 (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
0756eb3c
PH
1130}
1131
1132static void
2f4df477 1133copy4 (uschar *out, uint32x x)
0756eb3c 1134{
d7978c0f
JH
1135out[0] = x & 0xFF;
1136out[1] = (x >> 8) & 0xFF;
1137out[2] = (x >> 16) & 0xFF;
1138out[3] = (x >> 24) & 0xFF;
0756eb3c
PH
1139}
1140
1141/* produce a md4 message digest from data of length n bytes */
1142void
2f4df477 1143mdfour (uschar *out, uschar *in, int n)
0756eb3c 1144{
d7978c0f
JH
1145uschar buf[128];
1146uint32x M[16];
1147uint32x b = n * 8;
1148int i;
1149
1150A = 0x67452301;
1151B = 0xefcdab89;
1152C = 0x98badcfe;
1153D = 0x10325476;
1154
1155while (n > 64)
1156 {
1157 copy64 (M, in);
1158 spa_mdfour64 (M);
1159 in += 64;
1160 n -= 64;
1161 }
0756eb3c 1162
d7978c0f
JH
1163for (i = 0; i < 128; i++)
1164 buf[i] = 0;
1165memcpy (buf, in, n);
1166buf[n] = 0x80;
0756eb3c 1167
d7978c0f
JH
1168if (n <= 55)
1169 {
1170 copy4 (buf + 56, b);
0756eb3c 1171 copy64 (M, buf);
d7978c0f
JH
1172 spa_mdfour64 (M);
1173 }
1174else
1175 {
1176 copy4 (buf + 120, b);
1177 copy64 (M, buf);
1178 spa_mdfour64 (M);
1179 copy64 (M, buf + 64);
1180 spa_mdfour64 (M);
1181 }
0756eb3c 1182
d7978c0f
JH
1183for (i = 0; i < 128; i++)
1184 buf[i] = 0;
1185copy64 (M, buf);
0756eb3c 1186
d7978c0f
JH
1187copy4 (out, A);
1188copy4 (out + 4, B);
1189copy4 (out + 8, C);
1190copy4 (out + 12, D);
1191
1192A = B = C = D = 0;
0756eb3c
PH
1193}
1194
1195char versionString[] = "libntlm version 0.21";
1196
1197/* Utility routines that handle NTLM auth structures. */
1198
1199/* The [IS]VAL macros are to take care of byte order for non-Intel
1200 * Machines -- I think this file is OK, but it hasn't been tested.
1201 * The other files (the ones stolen from Samba) should be OK.
1202 */
1203
1204
1205/* I am not crazy about these macros -- they seem to have gotten
1206 * a bit complex. A new scheme for handling string/buffer fields
1207 * in the structures probably needs to be designed
1208 */
1209
1210#define spa_bytes_add(ptr, header, buf, count) \
1211{ \
13c7874e 1212if (buf != NULL && count != 0) /* we hate -Wint-in-bool-contex */ \
0756eb3c
PH
1213 { \
1214 SSVAL(&ptr->header.len,0,count); \
1215 SSVAL(&ptr->header.maxlen,0,count); \
1216 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1217 memcpy(ptr->buffer+ptr->bufIndex, buf, count); \
1218 ptr->bufIndex += count; \
1219 } \
1220else \
1221 { \
1222 ptr->header.len = \
1223 ptr->header.maxlen = 0; \
1224 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1225 } \
1226}
1227
1228#define spa_string_add(ptr, header, string) \
1229{ \
1230char *p = string; \
1231int len = 0; \
1232if (p) len = strlen(p); \
2f4df477 1233spa_bytes_add(ptr, header, (US p), len); \
0756eb3c
PH
1234}
1235
1236#define spa_unicode_add_string(ptr, header, string) \
1237{ \
1238char *p = string; \
2f4df477 1239uschar *b = NULL; \
0756eb3c
PH
1240int len = 0; \
1241if (p) \
1242 { \
1243 len = strlen(p); \
1244 b = strToUnicode(p); \
1245 } \
1246spa_bytes_add(ptr, header, b, len*2); \
1247}
1248
1249
1250#define GetUnicodeString(structPtr, header) \
1251unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
1252#define GetString(structPtr, header) \
5903c6ff 1253toString(((CS structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
d88f0784
JH
1254
1255#ifdef notdef
1256
0756eb3c 1257#define DumpBuffer(fp, structPtr, header) \
2f4df477 1258dumpRaw(fp,(US structPtr)+IVAL(&structPtr->header.offset,0),SVAL(&structPtr->header.len,0))
0756eb3c
PH
1259
1260
1261static void
2f4df477 1262dumpRaw (FILE * fp, uschar *buf, size_t len)
0756eb3c 1263{
d7978c0f 1264int i;
0756eb3c 1265
d7978c0f
JH
1266for (i = 0; i < len; ++i)
1267 fprintf (fp, "%02x ", buf[i]);
0756eb3c 1268
d7978c0f 1269fprintf (fp, "\n");
0756eb3c
PH
1270}
1271
d88f0784
JH
1272#endif
1273
0756eb3c
PH
1274char *
1275unicodeToString (char *p, size_t len)
1276{
d7978c0f
JH
1277int i;
1278static char buf[1024];
0756eb3c 1279
d7978c0f 1280assert (len + 1 < sizeof buf);
0756eb3c 1281
d7978c0f
JH
1282for (i = 0; i < len; ++i)
1283 {
1284 buf[i] = *p & 0x7f;
1285 p += 2;
1286 }
0756eb3c 1287
d7978c0f
JH
1288buf[i] = '\0';
1289return buf;
0756eb3c
PH
1290}
1291
2f4df477 1292static uschar *
0756eb3c
PH
1293strToUnicode (char *p)
1294{
d7978c0f
JH
1295static uschar buf[1024];
1296size_t l = strlen (p);
1297int i = 0;
0756eb3c 1298
d7978c0f 1299assert (l * 2 < sizeof buf);
0756eb3c 1300
d7978c0f
JH
1301while (l--)
1302 {
1303 buf[i++] = *p++;
1304 buf[i++] = 0;
1305 }
0756eb3c 1306
d7978c0f 1307return buf;
0756eb3c
PH
1308}
1309
2f4df477 1310static uschar *
0756eb3c
PH
1311toString (char *p, size_t len)
1312{
d7978c0f 1313static uschar buf[1024];
0756eb3c 1314
d7978c0f 1315assert (len + 1 < sizeof buf);
0756eb3c 1316
d7978c0f
JH
1317memcpy (buf, p, len);
1318buf[len] = 0;
1319return buf;
0756eb3c
PH
1320}
1321
d88f0784
JH
1322#ifdef notdef
1323
0756eb3c
PH
1324void
1325dumpSmbNtlmAuthRequest (FILE * fp, SPAAuthRequest * request)
1326{
d7978c0f
JH
1327fprintf (fp, "NTLM Request:\n");
1328fprintf (fp, " Ident = %s\n", request->ident);
1329fprintf (fp, " mType = %d\n", IVAL (&request->msgType, 0));
1330fprintf (fp, " Flags = %08x\n", IVAL (&request->flags, 0));
1331fprintf (fp, " User = %s\n", GetString (request, user));
1332fprintf (fp, " Domain = %s\n", GetString (request, domain));
0756eb3c
PH
1333}
1334
1335void
1336dumpSmbNtlmAuthChallenge (FILE * fp, SPAAuthChallenge * challenge)
1337{
d7978c0f
JH
1338fprintf (fp, "NTLM Challenge:\n");
1339fprintf (fp, " Ident = %s\n", challenge->ident);
1340fprintf (fp, " mType = %d\n", IVAL (&challenge->msgType, 0));
1341fprintf (fp, " Domain = %s\n", GetUnicodeString (challenge, uDomain));
1342fprintf (fp, " Flags = %08x\n", IVAL (&challenge->flags, 0));
1343fprintf (fp, " Challenge = ");
1344dumpRaw (fp, challenge->challengeData, 8);
0756eb3c
PH
1345}
1346
1347void
1348dumpSmbNtlmAuthResponse (FILE * fp, SPAAuthResponse * response)
1349{
d7978c0f
JH
1350fprintf (fp, "NTLM Response:\n");
1351fprintf (fp, " Ident = %s\n", response->ident);
1352fprintf (fp, " mType = %d\n", IVAL (&response->msgType, 0));
1353fprintf (fp, " LmResp = ");
1354DumpBuffer (fp, response, lmResponse);
1355fprintf (fp, " NTResp = ");
1356DumpBuffer (fp, response, ntResponse);
1357fprintf (fp, " Domain = %s\n", GetUnicodeString (response, uDomain));
1358fprintf (fp, " User = %s\n", GetUnicodeString (response, uUser));
1359fprintf (fp, " Wks = %s\n", GetUnicodeString (response, uWks));
1360fprintf (fp, " sKey = ");
1361DumpBuffer (fp, response, sessionKey);
1362fprintf (fp, " Flags = %08x\n", IVAL (&response->flags, 0));
0756eb3c 1363}
d88f0784 1364#endif
0756eb3c
PH
1365
1366void
1367spa_build_auth_request (SPAAuthRequest * request, char *user, char *domain)
1368{
d7978c0f
JH
1369char *u = strdup (user);
1370char *p = strchr (u, '@');
1371
1372if (p)
1373 {
1374 if (!domain)
1375 domain = p + 1;
1376 *p = '\0';
1377 }
0756eb3c 1378
d7978c0f
JH
1379request->bufIndex = 0;
1380memcpy (request->ident, "NTLMSSP\0\0\0", 8);
1381SIVAL (&request->msgType, 0, 1);
1382SIVAL (&request->flags, 0, 0x0000b207); /* have to figure out what these mean */
1383spa_string_add (request, user, u);
1384spa_string_add (request, domain, domain);
1385free (u);
0756eb3c
PH
1386}
1387
1388
1389
1390void
1391spa_build_auth_challenge (SPAAuthRequest * request, SPAAuthChallenge * challenge)
1392{
d7978c0f
JH
1393char chalstr[8];
1394int i;
1395int p = (int)getpid();
1396int random_seed = (int)time(NULL) ^ ((p << 16) | p);
0756eb3c 1397
d7978c0f 1398request = request; /* Added by PH to stop compilers whinging */
0756eb3c 1399
d7978c0f
JH
1400/* Ensure challenge data is cleared, in case it isn't all used. This
1401patch added by PH on suggestion of Russell King */
0756eb3c 1402
d7978c0f 1403memset(challenge, 0, sizeof(SPAAuthChallenge));
0756eb3c 1404
d7978c0f
JH
1405challenge->bufIndex = 0;
1406memcpy (challenge->ident, "NTLMSSP\0", 8);
1407SIVAL (&challenge->msgType, 0, 2);
1408SIVAL (&challenge->flags, 0, 0x00008201);
1409SIVAL (&challenge->uDomain.len, 0, 0x0000);
1410SIVAL (&challenge->uDomain.maxlen, 0, 0x0000);
1411SIVAL (&challenge->uDomain.offset, 0, 0x00002800);
0756eb3c 1412
d7978c0f 1413/* generate eight pseudo random bytes (method ripped from host.c) */
0756eb3c 1414
d7978c0f
JH
1415for(i=0;i<8;i++)
1416 {
1417 chalstr[i] = (uschar)(random_seed >> 16) % 256;
1418 random_seed = (1103515245 - (chalstr[i])) * random_seed + 12345;
1419 }
0756eb3c 1420
d7978c0f 1421memcpy(challenge->challengeData,chalstr,8);
0756eb3c
PH
1422}
1423
1424
1425
1426
1427/* This is the original source of this function, preserved here for reference.
1428The new version below was re-organized by PH following a patch and some further
1429suggestions from Mark Lyda to fix the problem that is described at the head of
1430this module. At the same time, I removed the untidiness in the code below that
1431involves the "d" and "domain" variables. */
1432
1433#ifdef NEVER
1434void
1435spa_build_auth_response (SPAAuthChallenge * challenge,
1436 SPAAuthResponse * response, char *user,
1437 char *password)
1438{
d7978c0f
JH
1439uint8x lmRespData[24];
1440uint8x ntRespData[24];
1441char *d = strdup (GetUnicodeString (challenge, uDomain));
1442char *domain = d;
1443char *u = strdup (user);
1444char *p = strchr (u, '@');
1445
1446if (p)
1447 {
1448 domain = p + 1;
1449 *p = '\0';
1450 }
0756eb3c 1451
d7978c0f
JH
1452spa_smb_encrypt (US password, challenge->challengeData, lmRespData);
1453spa_smb_nt_encrypt (US password, challenge->challengeData, ntRespData);
0756eb3c 1454
d7978c0f
JH
1455response->bufIndex = 0;
1456memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1457SIVAL (&response->msgType, 0, 3);
0756eb3c 1458
d7978c0f
JH
1459spa_bytes_add (response, lmResponse, lmRespData, 24);
1460spa_bytes_add (response, ntResponse, ntRespData, 24);
1461spa_unicode_add_string (response, uDomain, domain);
1462spa_unicode_add_string (response, uUser, u);
1463spa_unicode_add_string (response, uWks, u);
1464spa_string_add (response, sessionKey, NULL);
0756eb3c 1465
d7978c0f 1466response->flags = challenge->flags;
0756eb3c 1467
d7978c0f
JH
1468free (d);
1469free (u);
0756eb3c
PH
1470}
1471#endif
1472
1473
1474/* This is the re-organized version (see comments above) */
1475
1476void
1477spa_build_auth_response (SPAAuthChallenge * challenge,
1478 SPAAuthResponse * response, char *user,
1479 char *password)
1480{
d7978c0f
JH
1481uint8x lmRespData[24];
1482uint8x ntRespData[24];
1483uint32x cf = IVAL(&challenge->flags, 0);
1484char *u = strdup (user);
1485char *p = strchr (u, '@');
1486char *d = NULL;
1487char *domain;
1488
1489if (p)
1490 {
1491 domain = p + 1;
1492 *p = '\0';
1493 }
0756eb3c 1494
d7978c0f
JH
1495else domain = d = strdup((cf & 0x1)?
1496 CCS GetUnicodeString(challenge, uDomain) :
1497 CCS GetString(challenge, uDomain));
0756eb3c 1498
d7978c0f
JH
1499spa_smb_encrypt (US password, challenge->challengeData, lmRespData);
1500spa_smb_nt_encrypt (US password, challenge->challengeData, ntRespData);
0756eb3c 1501
d7978c0f
JH
1502response->bufIndex = 0;
1503memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1504SIVAL (&response->msgType, 0, 3);
0756eb3c 1505
d7978c0f
JH
1506spa_bytes_add (response, lmResponse, lmRespData, (cf & 0x200) ? 24 : 0);
1507spa_bytes_add (response, ntResponse, ntRespData, (cf & 0x8000) ? 24 : 0);
0756eb3c 1508
d7978c0f
JH
1509if (cf & 0x1) { /* Unicode Text */
1510 spa_unicode_add_string (response, uDomain, domain);
1511 spa_unicode_add_string (response, uUser, u);
1512 spa_unicode_add_string (response, uWks, u);
1513} else { /* OEM Text */
1514 spa_string_add (response, uDomain, domain);
1515 spa_string_add (response, uUser, u);
1516 spa_string_add (response, uWks, u);
1517}
0756eb3c 1518
d7978c0f
JH
1519spa_string_add (response, sessionKey, NULL);
1520response->flags = challenge->flags;
0756eb3c 1521
d7978c0f
JH
1522if (d != NULL) free (d);
1523free (u);
0756eb3c 1524}