1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
6 * This file provides the necessary methods for authenticating with
7 * Microsoft's Secure Password Authentication.
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).
12 * Copyright (c) The Exim Maintainers 2021
14 * Tom Kistner provided additional code, adding spa_build_auth_challenge() to
15 * support server authentication mode.
17 * Mark Lyda provided a patch to solve this problem:
19 - Exim is indicating in its Authentication Request message (Type 1) that it
20 can transmit text in either Unicode or OEM format.
22 - Microsoft's SMTP server (smtp.email.msn.com) is responding in its
23 Challenge message (Type 2) that it will be expecting the OEM format.
25 - Exim does not pay attention to the text format requested by Microsoft's
26 SMTP server and, instead, defaults to using the Unicode format.
29 * http://www.innovation.ch/java/ntlm.html
30 * http://www.kuro5hin.org/story/2002/4/28/1436/66154
32 * It seems that some systems have existing but different definitions of some
33 * of the following types. I received a complaint about "int16" causing
34 * compilation problems. So I (PH) have renamed them all, to be on the safe
35 * side, by adding 'x' on the end.
37 * typedef signed short int16;
38 * typedef unsigned short uint16;
39 * typedef unsigned uint32;
40 * typedef unsigned char uint8;
42 * The API is extremely simple:
43 * 1. Form a SPA authentication request based on the username
44 * and (optional) domain
45 * 2. Send the request to the server and get an SPA challenge
46 * 3. Build the challenge response and send it back.
51 int main (int argc, char ** argv)
53 SPAAuthRequest request;
54 SPAAuthChallenge challenge;
55 SPAAuthResponse response;
58 char *username, *password, *domain, *challenge_str;
62 printf ("Usage: %s <username> <password> [SPA Challenge]\n",
71 spa_build_auth_request (&request, username, domain);
73 spa_bits_to_base64 (msgbuf, US &request,
74 spa_request_length(&request));
76 printf ("SPA Login request for username=%s:\n %s\n",
81 printf ("Run: %s <username> <password> [NTLM Challenge] " \
82 "to complete authenitcation\n", argv [0]);
86 challenge_str = argv [3];
88 if (spa_base64_to_bits (CS &challenge, sizeof(challenge),
89 CCS (challenge_str))<0)
91 printf("bad base64 data in challenge: %s\n", challenge_str);
95 spa_build_auth_response (&challenge, &response, username, password);
96 spa_bits_to_base64 (msgbuf, US &response,
97 spa_request_length(&response));
99 printf ("SPA Response to challenge:\n %s\n for " \
100 "username=%s, password=%s:\n %s\n",
101 argv[3], argv [1], argv [2], msgbuf);
106 * All the client code used here was torn by Marc Prud'hommeaux out of the
107 * Samba project (by Andrew Tridgell, Jeremy Allison, and others).
108 * Previous comments are below:
112 Unix SMB/Netbios implementation.
115 a partial implementation of DES designed for use in the
116 SMB authentication protocol
118 Copyright (C) Andrew Tridgell 1998
120 This program is free software; you can redistribute it and/or modify
121 it under the terms of the GNU General Public License as published by
122 the Free Software Foundation; either version 2 of the License, or
123 (at your option) any later version.
125 This program is distributed in the hope that it will be useful,
126 but WITHOUT ANY WARRANTY; without even the implied warranty of
127 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128 GNU General Public License for more details.
130 You should have received a copy of the GNU General Public License
131 along with this program; if not, write to the Free Software
132 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
138 This code makes no attempt to be fast! In fact, it is a very
141 This code is NOT a complete DES implementation. It implements only
142 the minimum necessary for SMB authentication, as used by all SMB
143 products (including every copy of Microsoft Windows95 ever sold)
145 In particular, it can only do a unchained forward DES pass. This
146 means it is not possible to use this code for encryption/decryption
147 of data, instead it is only useful as a "hash" algorithm.
149 There is no entry point into this code that allows normal DES operation.
151 I believe this means that this code does not come under ITAR
152 regulations but this is NOT a legal opinion. If you are concerned
153 about the applicability of ITAR regulations to this code then you
154 should confirm it for yourself (and maybe let me know if you come
155 up with a different answer to the one above)
161 #define DEBUG_X(a,b) ;
163 extern int DEBUGLEVEL;
166 #include "auth-spa.h"
171 # define _BYTEORDER_H
173 # define RW_PCVAL(read,inbuf,outbuf,len) \
174 { if (read) { PCVAL (inbuf,0,outbuf,len); } \
175 else { PSCVAL(inbuf,0,outbuf,len); } }
177 # define RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
178 { if (read) { if (big_endian) { RPIVAL(inbuf,0,outbuf,len); } else { PIVAL(inbuf,0,outbuf,len); } } \
179 else { if (big_endian) { RPSIVAL(inbuf,0,outbuf,len); } else { PSIVAL(inbuf,0,outbuf,len); } } }
181 # define RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
182 { if (read) { if (big_endian) { RPSVAL(inbuf,0,outbuf,len); } else { PSVAL(inbuf,0,outbuf,len); } } \
183 else { if (big_endian) { RPSSVAL(inbuf,0,outbuf,len); } else { PSSVAL(inbuf,0,outbuf,len); } } }
185 # define RW_CVAL(read, inbuf, outbuf, offset) \
186 { if (read) { (outbuf) = CVAL (inbuf,offset); } \
187 else { SCVAL(inbuf,offset,outbuf); } }
189 # define RW_IVAL(read, big_endian, inbuf, outbuf, offset) \
190 { if (read) { (outbuf) = ((big_endian) ? RIVAL(inbuf,offset) : IVAL (inbuf,offset)); } \
191 else { if (big_endian) { RSIVAL(inbuf,offset,outbuf); } else { SIVAL(inbuf,offset,outbuf); } } }
193 # define RW_SVAL(read, big_endian, inbuf, outbuf, offset) \
194 { if (read) { (outbuf) = ((big_endian) ? RSVAL(inbuf,offset) : SVAL (inbuf,offset)); } \
195 else { if (big_endian) { RSSVAL(inbuf,offset,outbuf); } else { SSVAL(inbuf,offset,outbuf); } } }
197 # undef CAREFUL_ALIGNMENT
199 /* we know that the 386 can handle misalignment and has the "right"
202 # define CAREFUL_ALIGNMENT 0
205 # ifndef CAREFUL_ALIGNMENT
206 # define CAREFUL_ALIGNMENT 1
209 # define CVAL(buf,pos) ((US (buf))[pos])
210 # define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
211 # define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
214 # if CAREFUL_ALIGNMENT
216 # define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
217 # define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
218 # define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
219 # define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
220 # define SVALS(buf,pos) ((int16x)SVAL(buf,pos))
221 # define IVALS(buf,pos) ((int32x)IVAL(buf,pos))
222 # define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16x)(val)))
223 # define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32x)(val)))
224 # define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16x)(val)))
225 # define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32x)(val)))
227 # else /* CAREFUL_ALIGNMENT */
229 /* this handles things for architectures like the 386 that can handle
232 WARNING: This section is dependent on the length of int16x and int32x
236 /* get single value from an SMB buffer */
237 # define SVAL(buf,pos) (*(uint16x *)(CS (buf) + (pos)))
238 # define IVAL(buf,pos) (*(uint32x *)(CS (buf) + (pos)))
239 # define SVALS(buf,pos) (*(int16x *)(CS (buf) + (pos)))
240 # define IVALS(buf,pos) (*(int32x *)(CS (buf) + (pos)))
242 /* store single value in an SMB buffer */
243 # define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16x)(val))
244 # define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32x)(val))
245 # define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16x)(val))
246 # define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32x)(val))
248 # endif /* CAREFUL_ALIGNMENT */
250 /* macros for reading / writing arrays */
252 # define SMBMACRO(macro,buf,pos,val,len,size) \
253 { for (int l = 0; l < (len); l++) (val)[l] = macro((buf), (pos) + (size)*l); }
255 # define SSMBMACRO(macro,buf,pos,val,len,size) \
256 { for (int l = 0; l < (len); l++) macro((buf), (pos) + (size)*l, (val)[l]); }
258 /* reads multiple data from an SMB buffer */
259 # define PCVAL(buf,pos,val,len) SMBMACRO(CVAL,buf,pos,val,len,1)
260 # define PSVAL(buf,pos,val,len) SMBMACRO(SVAL,buf,pos,val,len,2)
261 # define PIVAL(buf,pos,val,len) SMBMACRO(IVAL,buf,pos,val,len,4)
262 # define PCVALS(buf,pos,val,len) SMBMACRO(CVALS,buf,pos,val,len,1)
263 # define PSVALS(buf,pos,val,len) SMBMACRO(SVALS,buf,pos,val,len,2)
264 # define PIVALS(buf,pos,val,len) SMBMACRO(IVALS,buf,pos,val,len,4)
266 /* stores multiple data in an SMB buffer */
267 # define PSCVAL(buf,pos,val,len) SSMBMACRO(SCVAL,buf,pos,val,len,1)
268 # define PSSVAL(buf,pos,val,len) SSMBMACRO(SSVAL,buf,pos,val,len,2)
269 # define PSIVAL(buf,pos,val,len) SSMBMACRO(SIVAL,buf,pos,val,len,4)
270 # define PSCVALS(buf,pos,val,len) SSMBMACRO(SCVALS,buf,pos,val,len,1)
271 # define PSSVALS(buf,pos,val,len) SSMBMACRO(SSVALS,buf,pos,val,len,2)
272 # define PSIVALS(buf,pos,val,len) SSMBMACRO(SIVALS,buf,pos,val,len,4)
275 /* now the reverse routines - these are used in nmb packets (mostly) */
276 # define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
277 # define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
279 # define RSVAL(buf,pos) SREV(SVAL(buf,pos))
280 # define RSVALS(buf,pos) SREV(SVALS(buf,pos))
281 # define RIVAL(buf,pos) IREV(IVAL(buf,pos))
282 # define RIVALS(buf,pos) IREV(IVALS(buf,pos))
283 # define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
284 # define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
285 # define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
286 # define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
288 /* reads multiple data from an SMB buffer (big-endian) */
289 # define RPSVAL(buf,pos,val,len) SMBMACRO(RSVAL,buf,pos,val,len,2)
290 # define RPIVAL(buf,pos,val,len) SMBMACRO(RIVAL,buf,pos,val,len,4)
291 # define RPSVALS(buf,pos,val,len) SMBMACRO(RSVALS,buf,pos,val,len,2)
292 # define RPIVALS(buf,pos,val,len) SMBMACRO(RIVALS,buf,pos,val,len,4)
294 /* stores multiple data in an SMB buffer (big-endian) */
295 # define RPSSVAL(buf,pos,val,len) SSMBMACRO(RSSVAL,buf,pos,val,len,2)
296 # define RPSIVAL(buf,pos,val,len) SSMBMACRO(RSIVAL,buf,pos,val,len,4)
297 # define RPSSVALS(buf,pos,val,len) SSMBMACRO(RSSVALS,buf,pos,val,len,2)
298 # define RPSIVALS(buf,pos,val,len) SSMBMACRO(RSIVALS,buf,pos,val,len,4)
300 # define DBG_RW_PCVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
301 { RW_PCVAL(read,inbuf,outbuf,len) \
302 DEBUG_X(5,("%s%04x %s: ", \
303 tab_depth(depth), base,string)); \
304 if (charmode) print_asc(5, US (outbuf), (len)); else \
305 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%02x ", (outbuf)[idx])); } \
308 # define DBG_RW_PSVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
309 { RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
310 DEBUG_X(5,("%s%04x %s: ", \
311 tab_depth(depth), base,string)); \
312 if (charmode) print_asc(5, US (outbuf), 2*(len)); else \
313 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%04x ", (outbuf)[idx])); } \
316 # define DBG_RW_PIVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
317 { RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
318 DEBUG_X(5,("%s%04x %s: ", \
319 tab_depth(depth), base,string)); \
320 if (charmode) print_asc(5, US (outbuf), 4*(len)); else \
321 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%08x ", (outbuf)[idx])); } \
324 # define DBG_RW_CVAL(string,depth,base,read,inbuf,outbuf) \
325 { RW_CVAL(read,inbuf,outbuf,0) \
326 DEBUG_X(5,("%s%04x %s: %02x\n", \
327 tab_depth(depth), base, string, outbuf)); }
329 # define DBG_RW_SVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
330 { RW_SVAL(read,big_endian,inbuf,outbuf,0) \
331 DEBUG_X(5,("%s%04x %s: %04x\n", \
332 tab_depth(depth), base, string, outbuf)); }
334 # define DBG_RW_IVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
335 { RW_IVAL(read,big_endian,inbuf,outbuf,0) \
336 DEBUG_X(5,("%s%04x %s: %08x\n", \
337 tab_depth(depth), base, string, outbuf)); }
339 #endif /* _BYTEORDER_H */
341 void E_P16 (uschar *p14, uschar *p16);
342 void E_P24 (uschar *p21, uschar *c8, uschar *p24);
343 void D_P16 (uschar *p14, uschar *in, uschar *out);
344 void SMBOWFencrypt (uschar passwd[16], uschar * c8, uschar p24[24]);
346 void mdfour (uschar *out, uschar *in, int n);
350 * base64.c -- base-64 conversion routines.
352 * For license terms, see the file COPYING in this directory.
354 * This base 64 encoding is defined in RFC2045 section 6.8,
355 * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
359 static const char base64digits[] =
360 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
362 #define BAD (char) -1
363 static const char base64val[] = {
364 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
366 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
368 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 62, BAD, BAD, BAD,
370 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, BAD, BAD, BAD, BAD, BAD, BAD,
371 BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
372 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, BAD, BAD, BAD, BAD, BAD,
373 BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
374 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, BAD, BAD, BAD, BAD, BAD
376 #define DECODE64(c) (isascii(c) ? base64val[c] : BAD)
379 spa_bits_to_base64 (uschar *out, const uschar *in, int inlen)
380 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
382 for (; inlen >= 3; inlen -= 3)
384 *out++ = base64digits[in[0] >> 2];
385 *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
386 *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
387 *out++ = base64digits[in[2] & 0x3f];
394 *out++ = base64digits[in[0] >> 2];
395 fragment = (in[0] << 4) & 0x30;
397 fragment |= in[1] >> 4;
398 *out++ = base64digits[fragment];
399 *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
406 /* The outlength parameter was added by PH, December 2004 */
409 spa_base64_to_bits (char *out, int outlength, const char *in)
410 /* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
413 uschar digit1, digit2, digit3, digit4;
415 if (in[0] == '+' && in[1] == ' ')
422 if (len >= outlength) /* Added by PH */
423 return -1; /* Added by PH */
425 if (DECODE64 (digit1) == BAD)
428 if (DECODE64 (digit2) == BAD)
431 if (digit3 != '=' && DECODE64 (digit3) == BAD)
434 if (digit4 != '=' && DECODE64 (digit4) == BAD)
437 *out++ = (DECODE64 (digit1) << 2) | (DECODE64 (digit2) >> 4);
441 if (len >= outlength) /* Added by PH */
442 return -1; /* Added by PH */
444 ((DECODE64 (digit2) << 4) & 0xf0) | (DECODE64 (digit3) >> 2);
448 if (len >= outlength) /* Added by PH */
449 return -1; /* Added by PH */
450 *out++ = ((DECODE64 (digit3) << 6) & 0xc0) | DECODE64 (digit4);
455 while (*in && *in != '\r' && digit4 != '=');
461 static uschar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
462 1, 58, 50, 42, 34, 26, 18,
463 10, 2, 59, 51, 43, 35, 27,
464 19, 11, 3, 60, 52, 44, 36,
465 63, 55, 47, 39, 31, 23, 15,
466 7, 62, 54, 46, 38, 30, 22,
467 14, 6, 61, 53, 45, 37, 29,
468 21, 13, 5, 28, 20, 12, 4
471 static uschar perm2[48] = { 14, 17, 11, 24, 1, 5,
472 3, 28, 15, 6, 21, 10,
473 23, 19, 12, 4, 26, 8,
474 16, 7, 27, 20, 13, 2,
475 41, 52, 31, 37, 47, 55,
476 30, 40, 51, 45, 33, 48,
477 44, 49, 39, 56, 34, 53,
478 46, 42, 50, 36, 29, 32
481 static uschar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
482 60, 52, 44, 36, 28, 20, 12, 4,
483 62, 54, 46, 38, 30, 22, 14, 6,
484 64, 56, 48, 40, 32, 24, 16, 8,
485 57, 49, 41, 33, 25, 17, 9, 1,
486 59, 51, 43, 35, 27, 19, 11, 3,
487 61, 53, 45, 37, 29, 21, 13, 5,
488 63, 55, 47, 39, 31, 23, 15, 7
491 static uschar perm4[48] = { 32, 1, 2, 3, 4, 5,
493 8, 9, 10, 11, 12, 13,
494 12, 13, 14, 15, 16, 17,
495 16, 17, 18, 19, 20, 21,
496 20, 21, 22, 23, 24, 25,
497 24, 25, 26, 27, 28, 29,
498 28, 29, 30, 31, 32, 1
501 static uschar perm5[32] = { 16, 7, 20, 21,
512 static uschar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
513 39, 7, 47, 15, 55, 23, 63, 31,
514 38, 6, 46, 14, 54, 22, 62, 30,
515 37, 5, 45, 13, 53, 21, 61, 29,
516 36, 4, 44, 12, 52, 20, 60, 28,
517 35, 3, 43, 11, 51, 19, 59, 27,
518 34, 2, 42, 10, 50, 18, 58, 26,
519 33, 1, 41, 9, 49, 17, 57, 25
523 static uschar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
525 static uschar sbox[8][4][16] = {
526 {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
527 {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
528 {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
529 {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
531 {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
532 {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
533 {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
534 {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
536 {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
537 {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
538 {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
539 {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
541 {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
542 {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
543 {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
544 {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
546 {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
547 {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
548 {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
549 {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
551 {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
552 {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
553 {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
554 {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
556 {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
557 {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
558 {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
559 {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
561 {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
562 {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
563 {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
564 {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
568 permute (char *out, char *in, uschar * p, int n)
570 for (int i = 0; i < n; i++)
571 out[i] = in[p[i] - 1];
575 lshift (char *d, int count, int n)
578 for (int i = 0; i < n; i++)
579 out[i] = d[(i + count) % n];
580 for (int i = 0; i < n; i++)
585 concat (char *out, char *in1, char *in2, int l1, int l2)
594 xor (char *out, char *in1, char *in2, int n)
596 for (int i = 0; i < n; i++)
597 out[i] = in1[i] ^ in2[i];
601 dohash (char *out, char *in, char *key, int forw)
613 permute (pk1, key, perm1, 56);
615 for (i = 0; i < 28; i++)
617 for (i = 0; i < 28; i++)
620 for (i = 0; i < 16; i++)
622 lshift (c, sc[i], 28);
623 lshift (d, sc[i], 28);
625 concat (cd, c, d, 28, 28);
626 permute (ki[i], cd, perm2, 48);
629 permute (pd1, in, perm3, 64);
631 for (j = 0; j < 32; j++)
637 for (i = 0; i < 16; i++)
646 permute (er, r, perm4, 48);
648 xor (erk, er, ki[forw ? i : 15 - i], 48);
650 for (j = 0; j < 8; j++)
651 for (k = 0; k < 6; k++)
652 b[j][k] = erk[j * 6 + k];
654 for (j = 0; j < 8; j++)
657 m = (b[j][0] << 1) | b[j][5];
659 n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << 1) | b[j][4];
661 for (k = 0; k < 4; k++)
662 b[j][k] = (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
665 for (j = 0; j < 8; j++)
666 for (k = 0; k < 4; k++)
667 cb[j * 4 + k] = b[j][k];
668 permute (pcb, cb, perm5, 32);
670 xor (r2, l, pcb, 32);
672 for (j = 0; j < 32; j++)
675 for (j = 0; j < 32; j++)
679 concat (rl, r, l, 32, 32);
681 permute (out, rl, perm6, 64);
685 str_to_key (uschar *str, uschar *key)
689 key[0] = str[0] >> 1;
690 key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
691 key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
692 key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
693 key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
694 key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
695 key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
696 key[7] = str[6] & 0x7F;
697 for (i = 0; i < 8; i++)
698 key[i] = (key[i] << 1);
703 smbhash (uschar *out, uschar *in, uschar *key, int forw)
711 str_to_key (key, key2);
713 for (i = 0; i < 64; i++)
715 inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
716 keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
720 dohash (outb, inb, keyb, forw);
722 for (i = 0; i < 8; i++)
725 for (i = 0; i < 64; i++)
727 out[i / 8] |= (1 << (7 - (i % 8)));
731 E_P16 (uschar *p14, uschar *p16)
733 uschar sp8[8] = { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
734 smbhash (p16, sp8, p14, 1);
735 smbhash (p16 + 8, sp8, p14 + 7, 1);
739 E_P24 (uschar *p21, uschar *c8, uschar *p24)
741 smbhash (p24, c8, p21, 1);
742 smbhash (p24 + 8, c8, p21 + 7, 1);
743 smbhash (p24 + 16, c8, p21 + 14, 1);
747 D_P16 (uschar *p14, uschar *in, uschar *out)
749 smbhash (out, in, p14, 0);
750 smbhash (out + 8, in + 8, p14 + 7, 0);
753 /****************************************************************************
754 Like strncpy but always null terminates. Make sure there is room!
755 The variable n should always be one less than the available size.
756 ****************************************************************************/
759 StrnCpy (char *dest, const char *src, size_t n)
769 while (n-- && (*d++ = *src++));
775 skip_multibyte_char (char c)
777 /* bogus if to get rid of unused compiler warning */
785 /*******************************************************************
786 safe string copy into a known length string. maxlength does not
787 include the terminating zero.
788 ********************************************************************/
791 safe_strcpy (char *dest, const char *src, size_t maxlength)
797 DEBUG_X (0, ("ERROR: NULL dest in safe_strcpy\n"));
811 DEBUG_X (0, ("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
812 (int) (len - maxlength), src));
816 memcpy (dest, src, len);
827 size_t skip = skip_multibyte_char (*s);
832 if (islower ((uschar)(*s)))
841 This implements the X/Open SMB password encryption
842 It takes a password, a 8 byte "crypt key" and puts 24 bytes of
843 encrypted password into p24
847 spa_smb_encrypt (uschar * passwd, uschar * c8, uschar * p24)
849 uschar p14[15], p21[21];
851 memset (p21, '\0', 21);
852 memset (p14, '\0', 14);
853 StrnCpy (CS p14, CS passwd, 14);
858 SMBOWFencrypt (p21, c8, p24);
860 #ifdef DEBUG_PASSWORD
861 DEBUG_X (100, ("spa_smb_encrypt: lm#, challenge, response\n"));
862 dump_data (100, CS p21, 16);
863 dump_data (100, CS c8, 8);
864 dump_data (100, CS p24, 24);
868 /* Routines for Windows NT MD4 Hash functions. */
870 _my_wcslen (int16x * str)
879 * Convert a string into an NT UNICODE string.
880 * Note that regardless of processor type
881 * this must be in intel (little-endian)
886 _my_mbstowcs (int16x * dst, uschar * src, int len)
891 for (i = 0; i < len; i++)
904 * Creates the MD4 Hash of the users password in NT UNICODE.
908 E_md4hash (uschar * passwd, uschar * p16)
913 /* Password cannot be longer than 128 characters */
914 len = strlen (CS passwd);
917 /* Password must be converted to NT unicode */
918 _my_mbstowcs (wpwd, passwd, len);
919 wpwd[len] = 0; /* Ensure string is null terminated */
920 /* Calculate length in bytes */
921 len = _my_wcslen (wpwd) * sizeof (int16x);
923 mdfour (p16, US wpwd, len);
926 /* Does both the NT and LM owfs of a user's password */
928 nt_lm_owf_gen (char *pwd, uschar nt_p16[16], uschar p16[16])
932 memset (passwd, '\0', 130);
933 safe_strcpy (passwd, pwd, sizeof (passwd) - 1);
935 /* Calculate the MD4 hash (NT compatible) of the password */
936 memset (nt_p16, '\0', 16);
937 E_md4hash (US passwd, nt_p16);
939 #ifdef DEBUG_PASSWORD
940 DEBUG_X (100, ("nt_lm_owf_gen: pwd, nt#\n"));
941 dump_data (120, passwd, strlen (passwd));
942 dump_data (100, CS nt_p16, 16);
945 /* Mangle the passwords into Lanman format */
949 /* Calculate the SMB (lanman) hash functions of the password */
951 memset (p16, '\0', 16);
952 E_P16 (US passwd, US p16);
954 #ifdef DEBUG_PASSWORD
955 DEBUG_X (100, ("nt_lm_owf_gen: pwd, lm#\n"));
956 dump_data (120, passwd, strlen (passwd));
957 dump_data (100, CS p16, 16);
959 /* clear out local copy of user's password (just being paranoid). */
960 memset (passwd, '\0', sizeof (passwd));
963 /* Does the des encryption from the NT or LM MD4 hash. */
965 SMBOWFencrypt (uschar passwd[16], uschar * c8, uschar p24[24])
969 memset (p21, '\0', 21);
971 memcpy (p21, passwd, 16);
972 E_P24 (p21, c8, p24);
975 /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
977 NTLMSSPOWFencrypt (uschar passwd[8], uschar * ntlmchalresp, uschar p24[24])
981 memset (p21, '\0', 21);
982 memcpy (p21, passwd, 8);
983 memset (p21 + 8, 0xbd, 8);
985 E_P24 (p21, ntlmchalresp, p24);
986 #ifdef DEBUG_PASSWORD
987 DEBUG_X (100, ("NTLMSSPOWFencrypt: p21, c8, p24\n"));
988 dump_data (100, CS p21, 21);
989 dump_data (100, CS ntlmchalresp, 8);
990 dump_data (100, CS p24, 24);
995 /* Does the NT MD4 hash then des encryption. */
998 spa_smb_nt_encrypt (uschar * passwd, uschar * c8, uschar * p24)
1002 memset (p21, '\0', 21);
1004 E_md4hash (passwd, p21);
1005 SMBOWFencrypt (p21, c8, p24);
1007 #ifdef DEBUG_PASSWORD
1008 DEBUG_X (100, ("spa_smb_nt_encrypt: nt#, challenge, response\n"));
1009 dump_data (100, CS p21, 16);
1010 dump_data (100, CS c8, 8);
1011 dump_data (100, CS p24, 24);
1015 static uint32x A, B, C, D;
1018 F (uint32x X, uint32x Y, uint32x Z)
1020 return (X & Y) | ((~X) & Z);
1024 G (uint32x X, uint32x Y, uint32x Z)
1026 return (X & Y) | (X & Z) | (Y & Z);
1030 H (uint32x X, uint32x Y, uint32x Z)
1036 lshift_a (uint32x x, int s)
1039 return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
1042 #define ROUND1(a,b,c,d,k,s) a = lshift_a(a + F(b,c,d) + X[k], s)
1043 #define ROUND2(a,b,c,d,k,s) a = lshift_a(a + G(b,c,d) + X[k] + (uint32x)0x5A827999,s)
1044 #define ROUND3(a,b,c,d,k,s) a = lshift_a(a + H(b,c,d) + X[k] + (uint32x)0x6ED9EBA1,s)
1046 /* this applies md4 to 64 byte chunks */
1048 spa_mdfour64 (uint32x * M)
1051 uint32x AA, BB, CC, DD;
1054 for (j = 0; j < 16; j++)
1062 ROUND1 (A, B, C, D, 0, 3);
1063 ROUND1 (D, A, B, C, 1, 7);
1064 ROUND1 (C, D, A, B, 2, 11);
1065 ROUND1 (B, C, D, A, 3, 19);
1066 ROUND1 (A, B, C, D, 4, 3);
1067 ROUND1 (D, A, B, C, 5, 7);
1068 ROUND1 (C, D, A, B, 6, 11);
1069 ROUND1 (B, C, D, A, 7, 19);
1070 ROUND1 (A, B, C, D, 8, 3);
1071 ROUND1 (D, A, B, C, 9, 7);
1072 ROUND1 (C, D, A, B, 10, 11);
1073 ROUND1 (B, C, D, A, 11, 19);
1074 ROUND1 (A, B, C, D, 12, 3);
1075 ROUND1 (D, A, B, C, 13, 7);
1076 ROUND1 (C, D, A, B, 14, 11);
1077 ROUND1 (B, C, D, A, 15, 19);
1079 ROUND2 (A, B, C, D, 0, 3);
1080 ROUND2 (D, A, B, C, 4, 5);
1081 ROUND2 (C, D, A, B, 8, 9);
1082 ROUND2 (B, C, D, A, 12, 13);
1083 ROUND2 (A, B, C, D, 1, 3);
1084 ROUND2 (D, A, B, C, 5, 5);
1085 ROUND2 (C, D, A, B, 9, 9);
1086 ROUND2 (B, C, D, A, 13, 13);
1087 ROUND2 (A, B, C, D, 2, 3);
1088 ROUND2 (D, A, B, C, 6, 5);
1089 ROUND2 (C, D, A, B, 10, 9);
1090 ROUND2 (B, C, D, A, 14, 13);
1091 ROUND2 (A, B, C, D, 3, 3);
1092 ROUND2 (D, A, B, C, 7, 5);
1093 ROUND2 (C, D, A, B, 11, 9);
1094 ROUND2 (B, C, D, A, 15, 13);
1096 ROUND3 (A, B, C, D, 0, 3);
1097 ROUND3 (D, A, B, C, 8, 9);
1098 ROUND3 (C, D, A, B, 4, 11);
1099 ROUND3 (B, C, D, A, 12, 15);
1100 ROUND3 (A, B, C, D, 2, 3);
1101 ROUND3 (D, A, B, C, 10, 9);
1102 ROUND3 (C, D, A, B, 6, 11);
1103 ROUND3 (B, C, D, A, 14, 15);
1104 ROUND3 (A, B, C, D, 1, 3);
1105 ROUND3 (D, A, B, C, 9, 9);
1106 ROUND3 (C, D, A, B, 5, 11);
1107 ROUND3 (B, C, D, A, 13, 15);
1108 ROUND3 (A, B, C, D, 3, 3);
1109 ROUND3 (D, A, B, C, 11, 9);
1110 ROUND3 (C, D, A, B, 7, 11);
1111 ROUND3 (B, C, D, A, 15, 15);
1123 for (j = 0; j < 16; j++)
1128 copy64 (uint32x * M, uschar *in)
1132 for (i = 0; i < 16; i++)
1133 M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
1134 (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
1138 copy4 (uschar *out, uint32x x)
1141 out[1] = (x >> 8) & 0xFF;
1142 out[2] = (x >> 16) & 0xFF;
1143 out[3] = (x >> 24) & 0xFF;
1146 /* produce a md4 message digest from data of length n bytes */
1148 mdfour (uschar *out, uschar *in, int n)
1168 for (i = 0; i < 128; i++)
1170 memcpy (buf, in, n);
1175 copy4 (buf + 56, b);
1181 copy4 (buf + 120, b);
1184 copy64 (M, buf + 64);
1188 for (i = 0; i < 128; i++)
1195 copy4 (out + 12, D);
1200 char versionString[] = "libntlm version 0.21";
1202 /* Utility routines that handle NTLM auth structures. */
1204 /* The [IS]VAL macros are to take care of byte order for non-Intel
1205 * Machines -- I think this file is OK, but it hasn't been tested.
1206 * The other files (the ones stolen from Samba) should be OK.
1210 /* I am not crazy about these macros -- they seem to have gotten
1211 * a bit complex. A new scheme for handling string/buffer fields
1212 * in the structures probably needs to be designed
1215 #define spa_bytes_add(ptr, header, buf, count) \
1217 if ( buf && (count) != 0 /* we hate -Wint-in-bool-contex */ \
1218 && ptr->bufIndex + count < sizeof(ptr->buffer) \
1221 SSVAL(&ptr->header.len,0,count); \
1222 SSVAL(&ptr->header.maxlen,0,count); \
1223 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1224 memcpy(ptr->buffer+ptr->bufIndex, buf, count); \
1225 ptr->bufIndex += count; \
1230 ptr->header.maxlen = 0; \
1231 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1235 #define spa_string_add(ptr, header, string) \
1237 uschar * p = string; \
1239 if (p) len = Ustrlen(p); \
1240 spa_bytes_add(ptr, header, p, len); \
1243 #define spa_unicode_add_string(ptr, header, string) \
1245 uschar * p = string; \
1246 uschar * b = NULL; \
1251 b = US strToUnicode(CS p); \
1253 spa_bytes_add(ptr, header, b, len*2); \
1257 #define GetUnicodeString(structPtr, header) \
1258 unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
1259 #define GetString(structPtr, header) \
1260 toString(((CS structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
1264 #define DumpBuffer(fp, structPtr, header) \
1265 dumpRaw(fp,(US structPtr)+IVAL(&structPtr->header.offset,0),SVAL(&structPtr->header.len,0))
1269 dumpRaw (FILE * fp, uschar *buf, size_t len)
1273 for (i = 0; i < len; ++i)
1274 fprintf (fp, "%02x ", buf[i]);
1282 unicodeToString (char *p, size_t len)
1285 static char buf[1024];
1287 assert (len + 1 < sizeof buf);
1289 for (i = 0; i < len; ++i)
1300 strToUnicode (char *p)
1302 static uschar buf[1024];
1303 size_t l = strlen (p);
1306 assert (l * 2 < sizeof buf);
1318 toString (char *p, size_t len)
1320 static uschar buf[1024];
1322 assert (len + 1 < sizeof buf);
1324 memcpy (buf, p, len);
1332 dumpSmbNtlmAuthRequest (FILE * fp, SPAAuthRequest * request)
1334 fprintf (fp, "NTLM Request:\n");
1335 fprintf (fp, " Ident = %s\n", request->ident);
1336 fprintf (fp, " mType = %d\n", IVAL (&request->msgType, 0));
1337 fprintf (fp, " Flags = %08x\n", IVAL (&request->flags, 0));
1338 fprintf (fp, " User = %s\n", GetString (request, user));
1339 fprintf (fp, " Domain = %s\n", GetString (request, domain));
1343 dumpSmbNtlmAuthChallenge (FILE * fp, SPAAuthChallenge * challenge)
1345 fprintf (fp, "NTLM Challenge:\n");
1346 fprintf (fp, " Ident = %s\n", challenge->ident);
1347 fprintf (fp, " mType = %d\n", IVAL (&challenge->msgType, 0));
1348 fprintf (fp, " Domain = %s\n", GetUnicodeString (challenge, uDomain));
1349 fprintf (fp, " Flags = %08x\n", IVAL (&challenge->flags, 0));
1350 fprintf (fp, " Challenge = ");
1351 dumpRaw (fp, challenge->challengeData, 8);
1355 dumpSmbNtlmAuthResponse (FILE * fp, SPAAuthResponse * response)
1357 fprintf (fp, "NTLM Response:\n");
1358 fprintf (fp, " Ident = %s\n", response->ident);
1359 fprintf (fp, " mType = %d\n", IVAL (&response->msgType, 0));
1360 fprintf (fp, " LmResp = ");
1361 DumpBuffer (fp, response, lmResponse);
1362 fprintf (fp, " NTResp = ");
1363 DumpBuffer (fp, response, ntResponse);
1364 fprintf (fp, " Domain = %s\n", GetUnicodeString (response, uDomain));
1365 fprintf (fp, " User = %s\n", GetUnicodeString (response, uUser));
1366 fprintf (fp, " Wks = %s\n", GetUnicodeString (response, uWks));
1367 fprintf (fp, " sKey = ");
1368 DumpBuffer (fp, response, sessionKey);
1369 fprintf (fp, " Flags = %08x\n", IVAL (&response->flags, 0));
1374 spa_build_auth_request (SPAAuthRequest * request, uschar * user, uschar * domain)
1376 uschar * u = string_copy(user);
1377 uschar * p = Ustrchr(u, '@');
1386 request->bufIndex = 0;
1387 memcpy (request->ident, "NTLMSSP\0\0\0", 8);
1388 SIVAL (&request->msgType, 0, 1);
1389 SIVAL (&request->flags, 0, 0x0000b207); /* have to figure out what these mean */
1390 spa_string_add (request, user, u);
1391 spa_string_add (request, domain, domain);
1397 spa_build_auth_challenge (SPAAuthRequest * request, SPAAuthChallenge * challenge)
1401 int p = (int)getpid();
1402 int random_seed = (int)time(NULL) ^ ((p << 16) | p);
1404 /* Ensure challenge data is cleared, in case it isn't all used. This
1405 patch added by PH on suggestion of Russell King */
1407 memset(challenge, 0, sizeof(SPAAuthChallenge));
1409 challenge->bufIndex = 0;
1410 memcpy (challenge->ident, "NTLMSSP\0", 8);
1411 SIVAL (&challenge->msgType, 0, 2);
1412 SIVAL (&challenge->flags, 0, 0x00008201);
1413 SIVAL (&challenge->uDomain.len, 0, 0x0000);
1414 SIVAL (&challenge->uDomain.maxlen, 0, 0x0000);
1415 SIVAL (&challenge->uDomain.offset, 0, 0x00002800);
1417 /* generate eight pseudo random bytes (method ripped from host.c) */
1421 chalstr[i] = (uschar)(random_seed >> 16) % 256;
1422 random_seed = (1103515245 - (chalstr[i])) * random_seed + 12345;
1425 memcpy(challenge->challengeData,chalstr,8);
1431 /* This is the original source of this function, preserved here for reference.
1432 The new version below was re-organized by PH following a patch and some further
1433 suggestions from Mark Lyda to fix the problem that is described at the head of
1434 this module. At the same time, I removed the untidiness in the code below that
1435 involves the "d" and "domain" variables. */
1439 spa_build_auth_response (SPAAuthChallenge * challenge,
1440 SPAAuthResponse * response, char *user,
1443 uint8x lmRespData[24];
1444 uint8x ntRespData[24];
1445 char *d = strdup (GetUnicodeString (challenge, uDomain));
1447 char *u = strdup (user);
1448 char *p = strchr (u, '@');
1456 spa_smb_encrypt (US password, challenge->challengeData, lmRespData);
1457 spa_smb_nt_encrypt (US password, challenge->challengeData, ntRespData);
1459 response->bufIndex = 0;
1460 memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1461 SIVAL (&response->msgType, 0, 3);
1463 spa_bytes_add (response, lmResponse, lmRespData, 24);
1464 spa_bytes_add (response, ntResponse, ntRespData, 24);
1465 spa_unicode_add_string (response, uDomain, domain);
1466 spa_unicode_add_string (response, uUser, u);
1467 spa_unicode_add_string (response, uWks, u);
1468 spa_string_add (response, sessionKey, NULL);
1470 response->flags = challenge->flags;
1478 /* This is the re-organized version (see comments above) */
1481 spa_build_auth_response (SPAAuthChallenge * challenge,
1482 SPAAuthResponse * response, uschar * user,
1485 uint8x lmRespData[24];
1486 uint8x ntRespData[24];
1487 uint32x cf = IVAL(&challenge->flags, 0);
1488 uschar * u = string_copy(user);
1489 uschar * p = Ustrchr(u, '@');
1499 else domain = d = string_copy(cf & 0x1
1500 ? CUS GetUnicodeString(challenge, uDomain)
1501 : CUS GetString(challenge, uDomain));
1503 spa_smb_encrypt(password, challenge->challengeData, lmRespData);
1504 spa_smb_nt_encrypt(password, challenge->challengeData, ntRespData);
1506 response->bufIndex = 0;
1507 memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1508 SIVAL (&response->msgType, 0, 3);
1510 spa_bytes_add(response, lmResponse, lmRespData, cf & 0x200 ? 24 : 0);
1511 spa_bytes_add(response, ntResponse, ntRespData, cf & 0x8000 ? 24 : 0);
1513 if (cf & 0x1) { /* Unicode Text */
1514 spa_unicode_add_string(response, uDomain, domain);
1515 spa_unicode_add_string(response, uUser, u);
1516 spa_unicode_add_string(response, uWks, u);
1517 } else { /* OEM Text */
1518 spa_string_add(response, uDomain, domain);
1519 spa_string_add(response, uUser, u);
1520 spa_string_add(response, uWks, u);
1523 spa_string_add(response, sessionKey, NULL);
1524 response->flags = challenge->flags;
1528 #endif /*!MACRO_PREDEF*/