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