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