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