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)
158 #define DEBUG_X(a,b) ;
160 extern int DEBUGLEVEL;
163 #include "auth-spa.h"
168 # define _BYTEORDER_H
170 # define RW_PCVAL(read,inbuf,outbuf,len) \
171 { if (read) { PCVAL (inbuf,0,outbuf,len); } \
172 else { PSCVAL(inbuf,0,outbuf,len); } }
174 # define RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
175 { if (read) { if (big_endian) { RPIVAL(inbuf,0,outbuf,len); } else { PIVAL(inbuf,0,outbuf,len); } } \
176 else { if (big_endian) { RPSIVAL(inbuf,0,outbuf,len); } else { PSIVAL(inbuf,0,outbuf,len); } } }
178 # define RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
179 { if (read) { if (big_endian) { RPSVAL(inbuf,0,outbuf,len); } else { PSVAL(inbuf,0,outbuf,len); } } \
180 else { if (big_endian) { RPSSVAL(inbuf,0,outbuf,len); } else { PSSVAL(inbuf,0,outbuf,len); } } }
182 # define RW_CVAL(read, inbuf, outbuf, offset) \
183 { if (read) { (outbuf) = CVAL (inbuf,offset); } \
184 else { SCVAL(inbuf,offset,outbuf); } }
186 # define RW_IVAL(read, big_endian, inbuf, outbuf, offset) \
187 { if (read) { (outbuf) = ((big_endian) ? RIVAL(inbuf,offset) : IVAL (inbuf,offset)); } \
188 else { if (big_endian) { RSIVAL(inbuf,offset,outbuf); } else { SIVAL(inbuf,offset,outbuf); } } }
190 # define RW_SVAL(read, big_endian, inbuf, outbuf, offset) \
191 { if (read) { (outbuf) = ((big_endian) ? RSVAL(inbuf,offset) : SVAL (inbuf,offset)); } \
192 else { if (big_endian) { RSSVAL(inbuf,offset,outbuf); } else { SSVAL(inbuf,offset,outbuf); } } }
194 # undef CAREFUL_ALIGNMENT
196 /* we know that the 386 can handle misalignment and has the "right"
199 # define CAREFUL_ALIGNMENT 0
202 # ifndef CAREFUL_ALIGNMENT
203 # define CAREFUL_ALIGNMENT 1
206 # define CVAL(buf,pos) ((US (buf))[pos])
207 # define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
208 # define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
211 # if CAREFUL_ALIGNMENT
213 # define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
214 # define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
215 # define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
216 # define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
217 # define SVALS(buf,pos) ((int16x)SVAL(buf,pos))
218 # define IVALS(buf,pos) ((int32x)IVAL(buf,pos))
219 # define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16x)(val)))
220 # define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32x)(val)))
221 # define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16x)(val)))
222 # define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32x)(val)))
224 # else /* CAREFUL_ALIGNMENT */
226 /* this handles things for architectures like the 386 that can handle
229 WARNING: This section is dependent on the length of int16x and int32x
233 /* get single value from an SMB buffer */
234 # define SVAL(buf,pos) (*(uint16x *)(CS (buf) + (pos)))
235 # define IVAL(buf,pos) (*(uint32x *)(CS (buf) + (pos)))
236 # define SVALS(buf,pos) (*(int16x *)(CS (buf) + (pos)))
237 # define IVALS(buf,pos) (*(int32x *)(CS (buf) + (pos)))
239 /* store single value in an SMB buffer */
240 # define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16x)(val))
241 # define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32x)(val))
242 # define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16x)(val))
243 # define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32x)(val))
245 # endif /* CAREFUL_ALIGNMENT */
247 /* macros for reading / writing arrays */
249 # define SMBMACRO(macro,buf,pos,val,len,size) \
250 { for (int l = 0; l < (len); l++) (val)[l] = macro((buf), (pos) + (size)*l); }
252 # define SSMBMACRO(macro,buf,pos,val,len,size) \
253 { for (int l = 0; l < (len); l++) macro((buf), (pos) + (size)*l, (val)[l]); }
255 /* reads multiple data from an SMB buffer */
256 # define PCVAL(buf,pos,val,len) SMBMACRO(CVAL,buf,pos,val,len,1)
257 # define PSVAL(buf,pos,val,len) SMBMACRO(SVAL,buf,pos,val,len,2)
258 # define PIVAL(buf,pos,val,len) SMBMACRO(IVAL,buf,pos,val,len,4)
259 # define PCVALS(buf,pos,val,len) SMBMACRO(CVALS,buf,pos,val,len,1)
260 # define PSVALS(buf,pos,val,len) SMBMACRO(SVALS,buf,pos,val,len,2)
261 # define PIVALS(buf,pos,val,len) SMBMACRO(IVALS,buf,pos,val,len,4)
263 /* stores multiple data in an SMB buffer */
264 # define PSCVAL(buf,pos,val,len) SSMBMACRO(SCVAL,buf,pos,val,len,1)
265 # define PSSVAL(buf,pos,val,len) SSMBMACRO(SSVAL,buf,pos,val,len,2)
266 # define PSIVAL(buf,pos,val,len) SSMBMACRO(SIVAL,buf,pos,val,len,4)
267 # define PSCVALS(buf,pos,val,len) SSMBMACRO(SCVALS,buf,pos,val,len,1)
268 # define PSSVALS(buf,pos,val,len) SSMBMACRO(SSVALS,buf,pos,val,len,2)
269 # define PSIVALS(buf,pos,val,len) SSMBMACRO(SIVALS,buf,pos,val,len,4)
272 /* now the reverse routines - these are used in nmb packets (mostly) */
273 # define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
274 # define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
276 # define RSVAL(buf,pos) SREV(SVAL(buf,pos))
277 # define RSVALS(buf,pos) SREV(SVALS(buf,pos))
278 # define RIVAL(buf,pos) IREV(IVAL(buf,pos))
279 # define RIVALS(buf,pos) IREV(IVALS(buf,pos))
280 # define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
281 # define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
282 # define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
283 # define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
285 /* reads multiple data from an SMB buffer (big-endian) */
286 # define RPSVAL(buf,pos,val,len) SMBMACRO(RSVAL,buf,pos,val,len,2)
287 # define RPIVAL(buf,pos,val,len) SMBMACRO(RIVAL,buf,pos,val,len,4)
288 # define RPSVALS(buf,pos,val,len) SMBMACRO(RSVALS,buf,pos,val,len,2)
289 # define RPIVALS(buf,pos,val,len) SMBMACRO(RIVALS,buf,pos,val,len,4)
291 /* stores multiple data in an SMB buffer (big-endian) */
292 # define RPSSVAL(buf,pos,val,len) SSMBMACRO(RSSVAL,buf,pos,val,len,2)
293 # define RPSIVAL(buf,pos,val,len) SSMBMACRO(RSIVAL,buf,pos,val,len,4)
294 # define RPSSVALS(buf,pos,val,len) SSMBMACRO(RSSVALS,buf,pos,val,len,2)
295 # define RPSIVALS(buf,pos,val,len) SSMBMACRO(RSIVALS,buf,pos,val,len,4)
297 # define DBG_RW_PCVAL(charmode,string,depth,base,read,inbuf,outbuf,len) \
298 { RW_PCVAL(read,inbuf,outbuf,len) \
299 DEBUG_X(5,("%s%04x %s: ", \
300 tab_depth(depth), base,string)); \
301 if (charmode) print_asc(5, US (outbuf), (len)); else \
302 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%02x ", (outbuf)[idx])); } \
305 # define DBG_RW_PSVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
306 { RW_PSVAL(read,big_endian,inbuf,outbuf,len) \
307 DEBUG_X(5,("%s%04x %s: ", \
308 tab_depth(depth), base,string)); \
309 if (charmode) print_asc(5, US (outbuf), 2*(len)); else \
310 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%04x ", (outbuf)[idx])); } \
313 # define DBG_RW_PIVAL(charmode,string,depth,base,read,big_endian,inbuf,outbuf,len) \
314 { RW_PIVAL(read,big_endian,inbuf,outbuf,len) \
315 DEBUG_X(5,("%s%04x %s: ", \
316 tab_depth(depth), base,string)); \
317 if (charmode) print_asc(5, US (outbuf), 4*(len)); else \
318 for (int idx = 0; idx < len; idx++) { DEBUG_X(5,("%08x ", (outbuf)[idx])); } \
321 # define DBG_RW_CVAL(string,depth,base,read,inbuf,outbuf) \
322 { RW_CVAL(read,inbuf,outbuf,0) \
323 DEBUG_X(5,("%s%04x %s: %02x\n", \
324 tab_depth(depth), base, string, outbuf)); }
326 # define DBG_RW_SVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
327 { RW_SVAL(read,big_endian,inbuf,outbuf,0) \
328 DEBUG_X(5,("%s%04x %s: %04x\n", \
329 tab_depth(depth), base, string, outbuf)); }
331 # define DBG_RW_IVAL(string,depth,base,read,big_endian,inbuf,outbuf) \
332 { RW_IVAL(read,big_endian,inbuf,outbuf,0) \
333 DEBUG_X(5,("%s%04x %s: %08x\n", \
334 tab_depth(depth), base, string, outbuf)); }
336 #endif /* _BYTEORDER_H */
338 void E_P16 (uschar *p14, uschar *p16);
339 void E_P24 (uschar *p21, uschar *c8, uschar *p24);
340 void D_P16 (uschar *p14, uschar *in, uschar *out);
341 void SMBOWFencrypt (uschar passwd[16], uschar * c8, uschar p24[24]);
343 void mdfour (uschar *out, uschar *in, int n);
347 * base64.c -- base-64 conversion routines.
349 * For license terms, see the file COPYING in this directory.
351 * This base 64 encoding is defined in RFC2045 section 6.8,
352 * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
356 static const char base64digits[] =
357 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
359 #define BAD (char) -1
360 static const char base64val[] = {
361 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
363 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
365 BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, 62, BAD, BAD, BAD,
367 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, BAD, BAD, BAD, BAD, BAD, BAD,
368 BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
369 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, BAD, BAD, BAD, BAD, BAD,
370 BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
371 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, BAD, BAD, BAD, BAD, BAD
373 #define DECODE64(c) (isascii(c) ? base64val[c] : BAD)
376 spa_bits_to_base64 (uschar *out, const uschar *in, int inlen)
377 /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
379 for (; inlen >= 3; inlen -= 3)
381 *out++ = base64digits[in[0] >> 2];
382 *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
383 *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
384 *out++ = base64digits[in[2] & 0x3f];
391 *out++ = base64digits[in[0] >> 2];
392 fragment = (in[0] << 4) & 0x30;
394 fragment |= in[1] >> 4;
395 *out++ = base64digits[fragment];
396 *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
403 /* The outlength parameter was added by PH, December 2004 */
406 spa_base64_to_bits (char *out, int outlength, const char *in)
407 /* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
410 uschar digit1, digit2, digit3, digit4;
412 if (in[0] == '+' && in[1] == ' ')
419 if (len >= outlength) /* Added by PH */
420 return -1; /* Added by PH */
422 if (DECODE64 (digit1) == BAD)
425 if (DECODE64 (digit2) == BAD)
428 if (digit3 != '=' && DECODE64 (digit3) == BAD)
431 if (digit4 != '=' && DECODE64 (digit4) == BAD)
434 *out++ = (DECODE64 (digit1) << 2) | (DECODE64 (digit2) >> 4);
438 if (len >= outlength) /* Added by PH */
439 return -1; /* Added by PH */
441 ((DECODE64 (digit2) << 4) & 0xf0) | (DECODE64 (digit3) >> 2);
445 if (len >= outlength) /* Added by PH */
446 return -1; /* Added by PH */
447 *out++ = ((DECODE64 (digit3) << 6) & 0xc0) | DECODE64 (digit4);
452 while (*in && *in != '\r' && digit4 != '=');
458 static uschar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
459 1, 58, 50, 42, 34, 26, 18,
460 10, 2, 59, 51, 43, 35, 27,
461 19, 11, 3, 60, 52, 44, 36,
462 63, 55, 47, 39, 31, 23, 15,
463 7, 62, 54, 46, 38, 30, 22,
464 14, 6, 61, 53, 45, 37, 29,
465 21, 13, 5, 28, 20, 12, 4
468 static uschar perm2[48] = { 14, 17, 11, 24, 1, 5,
469 3, 28, 15, 6, 21, 10,
470 23, 19, 12, 4, 26, 8,
471 16, 7, 27, 20, 13, 2,
472 41, 52, 31, 37, 47, 55,
473 30, 40, 51, 45, 33, 48,
474 44, 49, 39, 56, 34, 53,
475 46, 42, 50, 36, 29, 32
478 static uschar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
479 60, 52, 44, 36, 28, 20, 12, 4,
480 62, 54, 46, 38, 30, 22, 14, 6,
481 64, 56, 48, 40, 32, 24, 16, 8,
482 57, 49, 41, 33, 25, 17, 9, 1,
483 59, 51, 43, 35, 27, 19, 11, 3,
484 61, 53, 45, 37, 29, 21, 13, 5,
485 63, 55, 47, 39, 31, 23, 15, 7
488 static uschar perm4[48] = { 32, 1, 2, 3, 4, 5,
490 8, 9, 10, 11, 12, 13,
491 12, 13, 14, 15, 16, 17,
492 16, 17, 18, 19, 20, 21,
493 20, 21, 22, 23, 24, 25,
494 24, 25, 26, 27, 28, 29,
495 28, 29, 30, 31, 32, 1
498 static uschar perm5[32] = { 16, 7, 20, 21,
509 static uschar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
510 39, 7, 47, 15, 55, 23, 63, 31,
511 38, 6, 46, 14, 54, 22, 62, 30,
512 37, 5, 45, 13, 53, 21, 61, 29,
513 36, 4, 44, 12, 52, 20, 60, 28,
514 35, 3, 43, 11, 51, 19, 59, 27,
515 34, 2, 42, 10, 50, 18, 58, 26,
516 33, 1, 41, 9, 49, 17, 57, 25
520 static uschar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
522 static uschar sbox[8][4][16] = {
523 {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
524 {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
525 {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
526 {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
528 {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
529 {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
530 {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
531 {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
533 {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
534 {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
535 {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
536 {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
538 {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
539 {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
540 {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
541 {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
543 {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
544 {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
545 {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
546 {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
548 {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
549 {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
550 {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
551 {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
553 {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
554 {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
555 {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
556 {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
558 {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
559 {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
560 {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
561 {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
565 permute (char *out, char *in, uschar * p, int n)
567 for (int i = 0; i < n; i++)
568 out[i] = in[p[i] - 1];
572 lshift (char *d, int count, int n)
575 for (int i = 0; i < n; i++)
576 out[i] = d[(i + count) % n];
577 for (int i = 0; i < n; i++)
582 concat (char *out, char *in1, char *in2, int l1, int l2)
591 xor (char *out, char *in1, char *in2, int n)
593 for (int i = 0; i < n; i++)
594 out[i] = in1[i] ^ in2[i];
598 dohash (char *out, char *in, char *key, int forw)
610 permute (pk1, key, perm1, 56);
612 for (i = 0; i < 28; i++)
614 for (i = 0; i < 28; i++)
617 for (i = 0; i < 16; i++)
619 lshift (c, sc[i], 28);
620 lshift (d, sc[i], 28);
622 concat (cd, c, d, 28, 28);
623 permute (ki[i], cd, perm2, 48);
626 permute (pd1, in, perm3, 64);
628 for (j = 0; j < 32; j++)
634 for (i = 0; i < 16; i++)
643 permute (er, r, perm4, 48);
645 xor (erk, er, ki[forw ? i : 15 - i], 48);
647 for (j = 0; j < 8; j++)
648 for (k = 0; k < 6; k++)
649 b[j][k] = erk[j * 6 + k];
651 for (j = 0; j < 8; j++)
654 m = (b[j][0] << 1) | b[j][5];
656 n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << 1) | b[j][4];
658 for (k = 0; k < 4; k++)
659 b[j][k] = (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
662 for (j = 0; j < 8; j++)
663 for (k = 0; k < 4; k++)
664 cb[j * 4 + k] = b[j][k];
665 permute (pcb, cb, perm5, 32);
667 xor (r2, l, pcb, 32);
669 for (j = 0; j < 32; j++)
672 for (j = 0; j < 32; j++)
676 concat (rl, r, l, 32, 32);
678 permute (out, rl, perm6, 64);
682 str_to_key (uschar *str, uschar *key)
686 key[0] = str[0] >> 1;
687 key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
688 key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
689 key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
690 key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
691 key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
692 key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
693 key[7] = str[6] & 0x7F;
694 for (i = 0; i < 8; i++)
695 key[i] = (key[i] << 1);
700 smbhash (uschar *out, uschar *in, uschar *key, int forw)
708 str_to_key (key, key2);
710 for (i = 0; i < 64; i++)
712 inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
713 keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
717 dohash (outb, inb, keyb, forw);
719 for (i = 0; i < 8; i++)
722 for (i = 0; i < 64; i++)
724 out[i / 8] |= (1 << (7 - (i % 8)));
728 E_P16 (uschar *p14, uschar *p16)
730 uschar sp8[8] = { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
731 smbhash (p16, sp8, p14, 1);
732 smbhash (p16 + 8, sp8, p14 + 7, 1);
736 E_P24 (uschar *p21, uschar *c8, uschar *p24)
738 smbhash (p24, c8, p21, 1);
739 smbhash (p24 + 8, c8, p21 + 7, 1);
740 smbhash (p24 + 16, c8, p21 + 14, 1);
744 D_P16 (uschar *p14, uschar *in, uschar *out)
746 smbhash (out, in, p14, 0);
747 smbhash (out + 8, in + 8, p14 + 7, 0);
750 /****************************************************************************
751 Like strncpy but always null terminates. Make sure there is room!
752 The variable n should always be one less than the available size.
753 ****************************************************************************/
756 StrnCpy (char *dest, const char *src, size_t n)
766 while (n-- && (*d++ = *src++));
772 skip_multibyte_char (char c)
774 /* bogus if to get rid of unused compiler warning */
782 /*******************************************************************
783 safe string copy into a known length string. maxlength does not
784 include the terminating zero.
785 ********************************************************************/
788 safe_strcpy (char *dest, const char *src, size_t maxlength)
794 DEBUG_X (0, ("ERROR: NULL dest in safe_strcpy\n"));
808 DEBUG_X (0, ("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
809 (int) (len - maxlength), src));
813 memcpy (dest, src, len);
824 size_t skip = skip_multibyte_char (*s);
829 if (islower ((uschar)(*s)))
838 This implements the X/Open SMB password encryption
839 It takes a password, a 8 byte "crypt key" and puts 24 bytes of
840 encrypted password into p24
844 spa_smb_encrypt (uschar * passwd, uschar * c8, uschar * p24)
846 uschar p14[15], p21[21];
848 memset (p21, '\0', 21);
849 memset (p14, '\0', 14);
850 StrnCpy (CS p14, CS passwd, 14);
855 SMBOWFencrypt (p21, c8, p24);
857 #ifdef DEBUG_PASSWORD
858 DEBUG_X (100, ("spa_smb_encrypt: lm#, challenge, response\n"));
859 dump_data (100, CS p21, 16);
860 dump_data (100, CS c8, 8);
861 dump_data (100, CS p24, 24);
865 /* Routines for Windows NT MD4 Hash functions. */
867 _my_wcslen (int16x * str)
876 * Convert a string into an NT UNICODE string.
877 * Note that regardless of processor type
878 * this must be in intel (little-endian)
883 _my_mbstowcs (int16x * dst, uschar * src, int len)
888 for (i = 0; i < len; i++)
901 * Creates the MD4 Hash of the users password in NT UNICODE.
905 E_md4hash (uschar * passwd, uschar * p16)
910 /* Password cannot be longer than 128 characters */
911 len = strlen (CS passwd);
914 /* Password must be converted to NT unicode */
915 _my_mbstowcs (wpwd, passwd, len);
916 wpwd[len] = 0; /* Ensure string is null terminated */
917 /* Calculate length in bytes */
918 len = _my_wcslen (wpwd) * sizeof (int16x);
920 mdfour (p16, US wpwd, len);
923 /* Does both the NT and LM owfs of a user's password */
925 nt_lm_owf_gen (char *pwd, uschar nt_p16[16], uschar p16[16])
929 memset (passwd, '\0', 130);
930 safe_strcpy (passwd, pwd, sizeof (passwd) - 1);
932 /* Calculate the MD4 hash (NT compatible) of the password */
933 memset (nt_p16, '\0', 16);
934 E_md4hash (US passwd, nt_p16);
936 #ifdef DEBUG_PASSWORD
937 DEBUG_X (100, ("nt_lm_owf_gen: pwd, nt#\n"));
938 dump_data (120, passwd, strlen (passwd));
939 dump_data (100, CS nt_p16, 16);
942 /* Mangle the passwords into Lanman format */
946 /* Calculate the SMB (lanman) hash functions of the password */
948 memset (p16, '\0', 16);
949 E_P16 (US passwd, US p16);
951 #ifdef DEBUG_PASSWORD
952 DEBUG_X (100, ("nt_lm_owf_gen: pwd, lm#\n"));
953 dump_data (120, passwd, strlen (passwd));
954 dump_data (100, CS p16, 16);
956 /* clear out local copy of user's password (just being paranoid). */
957 memset (passwd, '\0', sizeof (passwd));
960 /* Does the des encryption from the NT or LM MD4 hash. */
962 SMBOWFencrypt (uschar passwd[16], uschar * c8, uschar p24[24])
966 memset (p21, '\0', 21);
968 memcpy (p21, passwd, 16);
969 E_P24 (p21, c8, p24);
972 /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
974 NTLMSSPOWFencrypt (uschar passwd[8], uschar * ntlmchalresp, uschar p24[24])
978 memset (p21, '\0', 21);
979 memcpy (p21, passwd, 8);
980 memset (p21 + 8, 0xbd, 8);
982 E_P24 (p21, ntlmchalresp, p24);
983 #ifdef DEBUG_PASSWORD
984 DEBUG_X (100, ("NTLMSSPOWFencrypt: p21, c8, p24\n"));
985 dump_data (100, CS p21, 21);
986 dump_data (100, CS ntlmchalresp, 8);
987 dump_data (100, CS p24, 24);
992 /* Does the NT MD4 hash then des encryption. */
995 spa_smb_nt_encrypt (uschar * passwd, uschar * c8, uschar * p24)
999 memset (p21, '\0', 21);
1001 E_md4hash (passwd, p21);
1002 SMBOWFencrypt (p21, c8, p24);
1004 #ifdef DEBUG_PASSWORD
1005 DEBUG_X (100, ("spa_smb_nt_encrypt: nt#, challenge, response\n"));
1006 dump_data (100, CS p21, 16);
1007 dump_data (100, CS c8, 8);
1008 dump_data (100, CS p24, 24);
1012 static uint32x A, B, C, D;
1015 F (uint32x X, uint32x Y, uint32x Z)
1017 return (X & Y) | ((~X) & Z);
1021 G (uint32x X, uint32x Y, uint32x Z)
1023 return (X & Y) | (X & Z) | (Y & Z);
1027 H (uint32x X, uint32x Y, uint32x Z)
1033 lshift_a (uint32x x, int s)
1036 return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
1039 #define ROUND1(a,b,c,d,k,s) a = lshift_a(a + F(b,c,d) + X[k], s)
1040 #define ROUND2(a,b,c,d,k,s) a = lshift_a(a + G(b,c,d) + X[k] + (uint32x)0x5A827999,s)
1041 #define ROUND3(a,b,c,d,k,s) a = lshift_a(a + H(b,c,d) + X[k] + (uint32x)0x6ED9EBA1,s)
1043 /* this applies md4 to 64 byte chunks */
1045 spa_mdfour64 (uint32x * M)
1048 uint32x AA, BB, CC, DD;
1051 for (j = 0; j < 16; j++)
1059 ROUND1 (A, B, C, D, 0, 3);
1060 ROUND1 (D, A, B, C, 1, 7);
1061 ROUND1 (C, D, A, B, 2, 11);
1062 ROUND1 (B, C, D, A, 3, 19);
1063 ROUND1 (A, B, C, D, 4, 3);
1064 ROUND1 (D, A, B, C, 5, 7);
1065 ROUND1 (C, D, A, B, 6, 11);
1066 ROUND1 (B, C, D, A, 7, 19);
1067 ROUND1 (A, B, C, D, 8, 3);
1068 ROUND1 (D, A, B, C, 9, 7);
1069 ROUND1 (C, D, A, B, 10, 11);
1070 ROUND1 (B, C, D, A, 11, 19);
1071 ROUND1 (A, B, C, D, 12, 3);
1072 ROUND1 (D, A, B, C, 13, 7);
1073 ROUND1 (C, D, A, B, 14, 11);
1074 ROUND1 (B, C, D, A, 15, 19);
1076 ROUND2 (A, B, C, D, 0, 3);
1077 ROUND2 (D, A, B, C, 4, 5);
1078 ROUND2 (C, D, A, B, 8, 9);
1079 ROUND2 (B, C, D, A, 12, 13);
1080 ROUND2 (A, B, C, D, 1, 3);
1081 ROUND2 (D, A, B, C, 5, 5);
1082 ROUND2 (C, D, A, B, 9, 9);
1083 ROUND2 (B, C, D, A, 13, 13);
1084 ROUND2 (A, B, C, D, 2, 3);
1085 ROUND2 (D, A, B, C, 6, 5);
1086 ROUND2 (C, D, A, B, 10, 9);
1087 ROUND2 (B, C, D, A, 14, 13);
1088 ROUND2 (A, B, C, D, 3, 3);
1089 ROUND2 (D, A, B, C, 7, 5);
1090 ROUND2 (C, D, A, B, 11, 9);
1091 ROUND2 (B, C, D, A, 15, 13);
1093 ROUND3 (A, B, C, D, 0, 3);
1094 ROUND3 (D, A, B, C, 8, 9);
1095 ROUND3 (C, D, A, B, 4, 11);
1096 ROUND3 (B, C, D, A, 12, 15);
1097 ROUND3 (A, B, C, D, 2, 3);
1098 ROUND3 (D, A, B, C, 10, 9);
1099 ROUND3 (C, D, A, B, 6, 11);
1100 ROUND3 (B, C, D, A, 14, 15);
1101 ROUND3 (A, B, C, D, 1, 3);
1102 ROUND3 (D, A, B, C, 9, 9);
1103 ROUND3 (C, D, A, B, 5, 11);
1104 ROUND3 (B, C, D, A, 13, 15);
1105 ROUND3 (A, B, C, D, 3, 3);
1106 ROUND3 (D, A, B, C, 11, 9);
1107 ROUND3 (C, D, A, B, 7, 11);
1108 ROUND3 (B, C, D, A, 15, 15);
1120 for (j = 0; j < 16; j++)
1125 copy64 (uint32x * M, uschar *in)
1129 for (i = 0; i < 16; i++)
1130 M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
1131 (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
1135 copy4 (uschar *out, uint32x x)
1138 out[1] = (x >> 8) & 0xFF;
1139 out[2] = (x >> 16) & 0xFF;
1140 out[3] = (x >> 24) & 0xFF;
1143 /* produce a md4 message digest from data of length n bytes */
1145 mdfour (uschar *out, uschar *in, int n)
1165 for (i = 0; i < 128; i++)
1167 memcpy (buf, in, n);
1172 copy4 (buf + 56, b);
1178 copy4 (buf + 120, b);
1181 copy64 (M, buf + 64);
1185 for (i = 0; i < 128; i++)
1192 copy4 (out + 12, D);
1197 char versionString[] = "libntlm version 0.21";
1199 /* Utility routines that handle NTLM auth structures. */
1201 /* The [IS]VAL macros are to take care of byte order for non-Intel
1202 * Machines -- I think this file is OK, but it hasn't been tested.
1203 * The other files (the ones stolen from Samba) should be OK.
1207 /* I am not crazy about these macros -- they seem to have gotten
1208 * a bit complex. A new scheme for handling string/buffer fields
1209 * in the structures probably needs to be designed
1212 #define spa_bytes_add(ptr, header, buf, count) \
1214 if (buf && (count) != 0) /* we hate -Wint-in-bool-contex */ \
1216 SSVAL(&ptr->header.len,0,count); \
1217 SSVAL(&ptr->header.maxlen,0,count); \
1218 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1219 memcpy(ptr->buffer+ptr->bufIndex, buf, count); \
1220 ptr->bufIndex += count; \
1225 ptr->header.maxlen = 0; \
1226 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1230 #define spa_string_add(ptr, header, string) \
1234 if (p) len = strlen(p); \
1235 spa_bytes_add(ptr, header, (US p), len); \
1238 #define spa_unicode_add_string(ptr, header, string) \
1246 b = strToUnicode(p); \
1248 spa_bytes_add(ptr, header, b, len*2); \
1252 #define GetUnicodeString(structPtr, header) \
1253 unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
1254 #define GetString(structPtr, header) \
1255 toString(((CS structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
1259 #define DumpBuffer(fp, structPtr, header) \
1260 dumpRaw(fp,(US structPtr)+IVAL(&structPtr->header.offset,0),SVAL(&structPtr->header.len,0))
1264 dumpRaw (FILE * fp, uschar *buf, size_t len)
1268 for (i = 0; i < len; ++i)
1269 fprintf (fp, "%02x ", buf[i]);
1277 unicodeToString (char *p, size_t len)
1280 static char buf[1024];
1282 assert (len + 1 < sizeof buf);
1284 for (i = 0; i < len; ++i)
1295 strToUnicode (char *p)
1297 static uschar buf[1024];
1298 size_t l = strlen (p);
1301 assert (l * 2 < sizeof buf);
1313 toString (char *p, size_t len)
1315 static uschar buf[1024];
1317 assert (len + 1 < sizeof buf);
1319 memcpy (buf, p, len);
1327 dumpSmbNtlmAuthRequest (FILE * fp, SPAAuthRequest * request)
1329 fprintf (fp, "NTLM Request:\n");
1330 fprintf (fp, " Ident = %s\n", request->ident);
1331 fprintf (fp, " mType = %d\n", IVAL (&request->msgType, 0));
1332 fprintf (fp, " Flags = %08x\n", IVAL (&request->flags, 0));
1333 fprintf (fp, " User = %s\n", GetString (request, user));
1334 fprintf (fp, " Domain = %s\n", GetString (request, domain));
1338 dumpSmbNtlmAuthChallenge (FILE * fp, SPAAuthChallenge * challenge)
1340 fprintf (fp, "NTLM Challenge:\n");
1341 fprintf (fp, " Ident = %s\n", challenge->ident);
1342 fprintf (fp, " mType = %d\n", IVAL (&challenge->msgType, 0));
1343 fprintf (fp, " Domain = %s\n", GetUnicodeString (challenge, uDomain));
1344 fprintf (fp, " Flags = %08x\n", IVAL (&challenge->flags, 0));
1345 fprintf (fp, " Challenge = ");
1346 dumpRaw (fp, challenge->challengeData, 8);
1350 dumpSmbNtlmAuthResponse (FILE * fp, SPAAuthResponse * response)
1352 fprintf (fp, "NTLM Response:\n");
1353 fprintf (fp, " Ident = %s\n", response->ident);
1354 fprintf (fp, " mType = %d\n", IVAL (&response->msgType, 0));
1355 fprintf (fp, " LmResp = ");
1356 DumpBuffer (fp, response, lmResponse);
1357 fprintf (fp, " NTResp = ");
1358 DumpBuffer (fp, response, ntResponse);
1359 fprintf (fp, " Domain = %s\n", GetUnicodeString (response, uDomain));
1360 fprintf (fp, " User = %s\n", GetUnicodeString (response, uUser));
1361 fprintf (fp, " Wks = %s\n", GetUnicodeString (response, uWks));
1362 fprintf (fp, " sKey = ");
1363 DumpBuffer (fp, response, sessionKey);
1364 fprintf (fp, " Flags = %08x\n", IVAL (&response->flags, 0));
1369 spa_build_auth_request (SPAAuthRequest * request, char *user, char *domain)
1371 char *u = strdup (user);
1372 char *p = strchr (u, '@');
1381 request->bufIndex = 0;
1382 memcpy (request->ident, "NTLMSSP\0\0\0", 8);
1383 SIVAL (&request->msgType, 0, 1);
1384 SIVAL (&request->flags, 0, 0x0000b207); /* have to figure out what these mean */
1385 spa_string_add (request, user, u);
1386 spa_string_add (request, domain, domain);
1393 spa_build_auth_challenge (SPAAuthRequest * request, SPAAuthChallenge * challenge)
1397 int p = (int)getpid();
1398 int random_seed = (int)time(NULL) ^ ((p << 16) | p);
1400 /* Ensure challenge data is cleared, in case it isn't all used. This
1401 patch added by PH on suggestion of Russell King */
1403 memset(challenge, 0, sizeof(SPAAuthChallenge));
1405 challenge->bufIndex = 0;
1406 memcpy (challenge->ident, "NTLMSSP\0", 8);
1407 SIVAL (&challenge->msgType, 0, 2);
1408 SIVAL (&challenge->flags, 0, 0x00008201);
1409 SIVAL (&challenge->uDomain.len, 0, 0x0000);
1410 SIVAL (&challenge->uDomain.maxlen, 0, 0x0000);
1411 SIVAL (&challenge->uDomain.offset, 0, 0x00002800);
1413 /* generate eight pseudo random bytes (method ripped from host.c) */
1417 chalstr[i] = (uschar)(random_seed >> 16) % 256;
1418 random_seed = (1103515245 - (chalstr[i])) * random_seed + 12345;
1421 memcpy(challenge->challengeData,chalstr,8);
1427 /* This is the original source of this function, preserved here for reference.
1428 The new version below was re-organized by PH following a patch and some further
1429 suggestions from Mark Lyda to fix the problem that is described at the head of
1430 this module. At the same time, I removed the untidiness in the code below that
1431 involves the "d" and "domain" variables. */
1435 spa_build_auth_response (SPAAuthChallenge * challenge,
1436 SPAAuthResponse * response, char *user,
1439 uint8x lmRespData[24];
1440 uint8x ntRespData[24];
1441 char *d = strdup (GetUnicodeString (challenge, uDomain));
1443 char *u = strdup (user);
1444 char *p = strchr (u, '@');
1452 spa_smb_encrypt (US password, challenge->challengeData, lmRespData);
1453 spa_smb_nt_encrypt (US password, challenge->challengeData, ntRespData);
1455 response->bufIndex = 0;
1456 memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1457 SIVAL (&response->msgType, 0, 3);
1459 spa_bytes_add (response, lmResponse, lmRespData, 24);
1460 spa_bytes_add (response, ntResponse, ntRespData, 24);
1461 spa_unicode_add_string (response, uDomain, domain);
1462 spa_unicode_add_string (response, uUser, u);
1463 spa_unicode_add_string (response, uWks, u);
1464 spa_string_add (response, sessionKey, NULL);
1466 response->flags = challenge->flags;
1474 /* This is the re-organized version (see comments above) */
1477 spa_build_auth_response (SPAAuthChallenge * challenge,
1478 SPAAuthResponse * response, char *user,
1481 uint8x lmRespData[24];
1482 uint8x ntRespData[24];
1483 uint32x cf = IVAL(&challenge->flags, 0);
1484 char *u = strdup (user);
1485 char *p = strchr (u, '@');
1495 else domain = d = strdup((cf & 0x1)?
1496 CCS GetUnicodeString(challenge, uDomain) :
1497 CCS GetString(challenge, uDomain));
1499 spa_smb_encrypt (US password, challenge->challengeData, lmRespData);
1500 spa_smb_nt_encrypt (US password, challenge->challengeData, ntRespData);
1502 response->bufIndex = 0;
1503 memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1504 SIVAL (&response->msgType, 0, 3);
1506 spa_bytes_add (response, lmResponse, lmRespData, (cf & 0x200) ? 24 : 0);
1507 spa_bytes_add (response, ntResponse, ntRespData, (cf & 0x8000) ? 24 : 0);
1509 if (cf & 0x1) { /* Unicode Text */
1510 spa_unicode_add_string (response, uDomain, domain);
1511 spa_unicode_add_string (response, uUser, u);
1512 spa_unicode_add_string (response, uWks, u);
1513 } else { /* OEM Text */
1514 spa_string_add (response, uDomain, domain);
1515 spa_string_add (response, uUser, u);
1516 spa_string_add (response, uWks, u);
1519 spa_string_add (response, sessionKey, NULL);
1520 response->flags = challenge->flags;
1522 if (d != NULL) free (d);