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