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