Added a ChangeLog entry for Tom (Remove one case of BASE64 error
[exim.git] / src / src / auths / auth-spa.c
CommitLineData
85b87bc2 1/* $Cambridge: exim/src/src/auths/auth-spa.c,v 1.2 2004/12/29 10:55:58 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
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
153extern 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
166typedef unsigned char uchar;
167#endif
168
169
170typedef 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
345void E_P16 (unsigned char *p14, unsigned char *p16);
346void E_P24 (unsigned char *p21, unsigned char *c8, unsigned char *p24);
347void D_P16 (unsigned char *p14, unsigned char *in, unsigned char *out);
348void SMBOWFencrypt (uchar passwd[16], uchar * c8, uchar p24[24]);
349
350void 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
363static const char base64digits[] =
364 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
365
366#define BAD -1
367static 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
382void
383spa_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
85b87bc2
PH
409
410/* The outlength parameter was added by PH, December 2004 */
411
0756eb3c 412int
85b87bc2 413spa_base64_to_bits (char *out, int outlength, const char *in)
0756eb3c
PH
414/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
415{
416 int len = 0;
417 register unsigned char digit1, digit2, digit3, digit4;
418
419 if (in[0] == '+' && in[1] == ' ')
420 in += 2;
421 if (*in == '\r')
422 return (0);
423
424 do
425 {
85b87bc2
PH
426 if (len >= outlength) /* Added by PH */
427 return (-1); /* Added by PH */
0756eb3c
PH
428 digit1 = in[0];
429 if (DECODE64 (digit1) == BAD)
430 return (-1);
431 digit2 = in[1];
432 if (DECODE64 (digit2) == BAD)
433 return (-1);
434 digit3 = in[2];
435 if (digit3 != '=' && DECODE64 (digit3) == BAD)
436 return (-1);
437 digit4 = in[3];
438 if (digit4 != '=' && DECODE64 (digit4) == BAD)
439 return (-1);
440 in += 4;
441 *out++ = (DECODE64 (digit1) << 2) | (DECODE64 (digit2) >> 4);
442 ++len;
443 if (digit3 != '=')
444 {
85b87bc2
PH
445 if (len >= outlength) /* Added by PH */
446 return (-1); /* Added by PH */
0756eb3c
PH
447 *out++ =
448 ((DECODE64 (digit2) << 4) & 0xf0) | (DECODE64 (digit3) >> 2);
449 ++len;
450 if (digit4 != '=')
451 {
85b87bc2
PH
452 if (len >= outlength) /* Added by PH */
453 return (-1); /* Added by PH */
0756eb3c
PH
454 *out++ = ((DECODE64 (digit3) << 6) & 0xc0) | DECODE64 (digit4);
455 ++len;
456 }
457 }
458 }
459 while (*in && *in != '\r' && digit4 != '=');
460
461 return (len);
462}
463
464
465#define uchar unsigned char
466
467static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
468 1, 58, 50, 42, 34, 26, 18,
469 10, 2, 59, 51, 43, 35, 27,
470 19, 11, 3, 60, 52, 44, 36,
471 63, 55, 47, 39, 31, 23, 15,
472 7, 62, 54, 46, 38, 30, 22,
473 14, 6, 61, 53, 45, 37, 29,
474 21, 13, 5, 28, 20, 12, 4
475};
476
477static uchar perm2[48] = { 14, 17, 11, 24, 1, 5,
478 3, 28, 15, 6, 21, 10,
479 23, 19, 12, 4, 26, 8,
480 16, 7, 27, 20, 13, 2,
481 41, 52, 31, 37, 47, 55,
482 30, 40, 51, 45, 33, 48,
483 44, 49, 39, 56, 34, 53,
484 46, 42, 50, 36, 29, 32
485};
486
487static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
488 60, 52, 44, 36, 28, 20, 12, 4,
489 62, 54, 46, 38, 30, 22, 14, 6,
490 64, 56, 48, 40, 32, 24, 16, 8,
491 57, 49, 41, 33, 25, 17, 9, 1,
492 59, 51, 43, 35, 27, 19, 11, 3,
493 61, 53, 45, 37, 29, 21, 13, 5,
494 63, 55, 47, 39, 31, 23, 15, 7
495};
496
497static uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
498 4, 5, 6, 7, 8, 9,
499 8, 9, 10, 11, 12, 13,
500 12, 13, 14, 15, 16, 17,
501 16, 17, 18, 19, 20, 21,
502 20, 21, 22, 23, 24, 25,
503 24, 25, 26, 27, 28, 29,
504 28, 29, 30, 31, 32, 1
505};
506
507static uchar perm5[32] = { 16, 7, 20, 21,
508 29, 12, 28, 17,
509 1, 15, 23, 26,
510 5, 18, 31, 10,
511 2, 8, 24, 14,
512 32, 27, 3, 9,
513 19, 13, 30, 6,
514 22, 11, 4, 25
515};
516
517
518static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
519 39, 7, 47, 15, 55, 23, 63, 31,
520 38, 6, 46, 14, 54, 22, 62, 30,
521 37, 5, 45, 13, 53, 21, 61, 29,
522 36, 4, 44, 12, 52, 20, 60, 28,
523 35, 3, 43, 11, 51, 19, 59, 27,
524 34, 2, 42, 10, 50, 18, 58, 26,
525 33, 1, 41, 9, 49, 17, 57, 25
526};
527
528
529static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
530
531static uchar sbox[8][4][16] = {
532 {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
533 {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
534 {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
535 {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
536
537 {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
538 {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
539 {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
540 {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
541
542 {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
543 {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
544 {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
545 {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
546
547 {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
548 {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
549 {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
550 {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
551
552 {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
553 {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
554 {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
555 {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
556
557 {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
558 {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
559 {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
560 {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
561
562 {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
563 {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
564 {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
565 {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
566
567 {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
568 {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
569 {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
570 {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
571};
572
573static void
574permute (char *out, char *in, uchar * p, int n)
575{
576 int i;
577 for (i = 0; i < n; i++)
578 out[i] = in[p[i] - 1];
579}
580
581static void
582lshift (char *d, int count, int n)
583{
584 char out[64];
585 int i;
586 for (i = 0; i < n; i++)
587 out[i] = d[(i + count) % n];
588 for (i = 0; i < n; i++)
589 d[i] = out[i];
590}
591
592static void
593concat (char *out, char *in1, char *in2, int l1, int l2)
594{
595 while (l1--)
596 *out++ = *in1++;
597 while (l2--)
598 *out++ = *in2++;
599}
600
601static void
602xor (char *out, char *in1, char *in2, int n)
603{
604 int i;
605 for (i = 0; i < n; i++)
606 out[i] = in1[i] ^ in2[i];
607}
608
609static void
610dohash (char *out, char *in, char *key, int forw)
611{
612 int i, j, k;
613 char pk1[56];
614 char c[28];
615 char d[28];
616 char cd[56];
617 char ki[16][48];
618 char pd1[64];
619 char l[32], r[32];
620 char rl[64];
621
622 permute (pk1, key, perm1, 56);
623
624 for (i = 0; i < 28; i++)
625 c[i] = pk1[i];
626 for (i = 0; i < 28; i++)
627 d[i] = pk1[i + 28];
628
629 for (i = 0; i < 16; i++)
630 {
631 lshift (c, sc[i], 28);
632 lshift (d, sc[i], 28);
633
634 concat (cd, c, d, 28, 28);
635 permute (ki[i], cd, perm2, 48);
636 }
637
638 permute (pd1, in, perm3, 64);
639
640 for (j = 0; j < 32; j++)
641 {
642 l[j] = pd1[j];
643 r[j] = pd1[j + 32];
644 }
645
646 for (i = 0; i < 16; i++)
647 {
648 char er[48];
649 char erk[48];
650 char b[8][6];
651 char cb[32];
652 char pcb[32];
653 char r2[32];
654
655 permute (er, r, perm4, 48);
656
657 xor (erk, er, ki[forw ? i : 15 - i], 48);
658
659 for (j = 0; j < 8; j++)
660 for (k = 0; k < 6; k++)
661 b[j][k] = erk[j * 6 + k];
662
663 for (j = 0; j < 8; j++)
664 {
665 int m, n;
666 m = (b[j][0] << 1) | b[j][5];
667
668 n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << 1) | b[j][4];
669
670 for (k = 0; k < 4; k++)
671 b[j][k] = (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
672 }
673
674 for (j = 0; j < 8; j++)
675 for (k = 0; k < 4; k++)
676 cb[j * 4 + k] = b[j][k];
677 permute (pcb, cb, perm5, 32);
678
679 xor (r2, l, pcb, 32);
680
681 for (j = 0; j < 32; j++)
682 l[j] = r[j];
683
684 for (j = 0; j < 32; j++)
685 r[j] = r2[j];
686 }
687
688 concat (rl, r, l, 32, 32);
689
690 permute (out, rl, perm6, 64);
691}
692
693static void
694str_to_key (unsigned char *str, unsigned char *key)
695{
696 int i;
697
698 key[0] = str[0] >> 1;
699 key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
700 key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
701 key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
702 key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
703 key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
704 key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
705 key[7] = str[6] & 0x7F;
706 for (i = 0; i < 8; i++)
707 {
708 key[i] = (key[i] << 1);
709 }
710}
711
712
713static void
714smbhash (unsigned char *out, unsigned char *in, unsigned char *key, int forw)
715{
716 int i;
717 char outb[64];
718 char inb[64];
719 char keyb[64];
720 unsigned char key2[8];
721
722 str_to_key (key, key2);
723
724 for (i = 0; i < 64; i++)
725 {
726 inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
727 keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
728 outb[i] = 0;
729 }
730
731 dohash (outb, inb, keyb, forw);
732
733 for (i = 0; i < 8; i++)
734 {
735 out[i] = 0;
736 }
737
738 for (i = 0; i < 64; i++)
739 {
740 if (outb[i])
741 out[i / 8] |= (1 << (7 - (i % 8)));
742 }
743}
744
745void
746E_P16 (unsigned char *p14, unsigned char *p16)
747{
748 unsigned char sp8[8] = { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
749 smbhash (p16, sp8, p14, 1);
750 smbhash (p16 + 8, sp8, p14 + 7, 1);
751}
752
753void
754E_P24 (unsigned char *p21, unsigned char *c8, unsigned char *p24)
755{
756 smbhash (p24, c8, p21, 1);
757 smbhash (p24 + 8, c8, p21 + 7, 1);
758 smbhash (p24 + 16, c8, p21 + 14, 1);
759}
760
761void
762D_P16 (unsigned char *p14, unsigned char *in, unsigned char *out)
763{
764 smbhash (out, in, p14, 0);
765 smbhash (out + 8, in + 8, p14 + 7, 0);
766}
767
768/****************************************************************************
769 Like strncpy but always null terminates. Make sure there is room!
770 The variable n should always be one less than the available size.
771****************************************************************************/
772
773char *
774StrnCpy (char *dest, const char *src, size_t n)
775{
776 char *d = dest;
777 if (!dest)
778 return (NULL);
779 if (!src)
780 {
781 *dest = 0;
782 return (dest);
783 }
784 while (n-- && (*d++ = *src++));
785 *d = 0;
786 return (dest);
787}
788
789size_t
790skip_multibyte_char (char c)
791{
792 /* bogus if to get rid of unused compiler warning */
793 if (c)
794 return 0;
795 else
796 return 0;
797}
798
799
800/*******************************************************************
801safe string copy into a known length string. maxlength does not
802include the terminating zero.
803********************************************************************/
804
805char *
806safe_strcpy (char *dest, const char *src, size_t maxlength)
807{
808 size_t len;
809
810 if (!dest)
811 {
812 DEBUG (0, ("ERROR: NULL dest in safe_strcpy\n"));
813 return NULL;
814 }
815
816 if (!src)
817 {
818 *dest = 0;
819 return dest;
820 }
821
822 len = strlen (src);
823
824 if (len > maxlength)
825 {
826 DEBUG (0, ("ERROR: string overflow by %d in safe_strcpy [%.50s]\n",
827 (int) (len - maxlength), src));
828 len = maxlength;
829 }
830
831 memcpy (dest, src, len);
832 dest[len] = 0;
833 return dest;
834}
835
836
837void
838strupper (char *s)
839{
840 while (*s)
841 {
842 {
843 size_t skip = skip_multibyte_char (*s);
844 if (skip != 0)
845 s += skip;
846 else
847 {
848 if (islower ((unsigned char)(*s)))
849 *s = toupper (*s);
850 s++;
851 }
852 }
853 }
854}
855
856
857/*
858 This implements the X/Open SMB password encryption
859 It takes a password, a 8 byte "crypt key" and puts 24 bytes of
860 encrypted password into p24
861 */
862
863void
864spa_smb_encrypt (uchar * passwd, uchar * c8, uchar * p24)
865{
866 uchar p14[15], p21[21];
867
868 memset (p21, '\0', 21);
869 memset (p14, '\0', 14);
870 StrnCpy ((char *) p14, (char *) passwd, 14);
871
872 strupper ((char *) p14);
873 E_P16 (p14, p21);
874
875 SMBOWFencrypt (p21, c8, p24);
876
877#ifdef DEBUG_PASSWORD
878 DEBUG (100, ("spa_smb_encrypt: lm#, challenge, response\n"));
879 dump_data (100, (char *) p21, 16);
880 dump_data (100, (char *) c8, 8);
881 dump_data (100, (char *) p24, 24);
882#endif
883}
884
885/* Routines for Windows NT MD4 Hash functions. */
886static int
887_my_wcslen (int16x * str)
888{
889 int len = 0;
890 while (*str++ != 0)
891 len++;
892 return len;
893}
894
895/*
896 * Convert a string into an NT UNICODE string.
897 * Note that regardless of processor type
898 * this must be in intel (little-endian)
899 * format.
900 */
901
902static int
903_my_mbstowcs (int16x * dst, uchar * src, int len)
904{
905 int i;
906 int16x val;
907
908 for (i = 0; i < len; i++)
909 {
910 val = *src;
911 SSVAL (dst, 0, val);
912 dst++;
913 src++;
914 if (val == 0)
915 break;
916 }
917 return i;
918}
919
920/*
921 * Creates the MD4 Hash of the users password in NT UNICODE.
922 */
923
924void
925E_md4hash (uchar * passwd, uchar * p16)
926{
927 int len;
928 int16x wpwd[129];
929
930 /* Password cannot be longer than 128 characters */
931 len = strlen ((char *) passwd);
932 if (len > 128)
933 len = 128;
934 /* Password must be converted to NT unicode */
935 _my_mbstowcs (wpwd, passwd, len);
936 wpwd[len] = 0; /* Ensure string is null terminated */
937 /* Calculate length in bytes */
938 len = _my_wcslen (wpwd) * sizeof (int16x);
939
940 mdfour (p16, (unsigned char *) wpwd, len);
941}
942
943/* Does both the NT and LM owfs of a user's password */
944void
945nt_lm_owf_gen (char *pwd, uchar nt_p16[16], uchar p16[16])
946{
947 char passwd[130];
948
949 memset (passwd, '\0', 130);
950 safe_strcpy (passwd, pwd, sizeof (passwd) - 1);
951
952 /* Calculate the MD4 hash (NT compatible) of the password */
953 memset (nt_p16, '\0', 16);
954 E_md4hash ((uchar *) passwd, nt_p16);
955
956#ifdef DEBUG_PASSWORD
957 DEBUG (100, ("nt_lm_owf_gen: pwd, nt#\n"));
958 dump_data (120, passwd, strlen (passwd));
959 dump_data (100, (char *) nt_p16, 16);
960#endif
961
962 /* Mangle the passwords into Lanman format */
963 passwd[14] = '\0';
964 strupper (passwd);
965
966 /* Calculate the SMB (lanman) hash functions of the password */
967
968 memset (p16, '\0', 16);
969 E_P16 ((uchar *) passwd, (uchar *) p16);
970
971#ifdef DEBUG_PASSWORD
972 DEBUG (100, ("nt_lm_owf_gen: pwd, lm#\n"));
973 dump_data (120, passwd, strlen (passwd));
974 dump_data (100, (char *) p16, 16);
975#endif
976 /* clear out local copy of user's password (just being paranoid). */
977 memset (passwd, '\0', sizeof (passwd));
978}
979
980/* Does the des encryption from the NT or LM MD4 hash. */
981void
982SMBOWFencrypt (uchar passwd[16], uchar * c8, uchar p24[24])
983{
984 uchar p21[21];
985
986 memset (p21, '\0', 21);
987
988 memcpy (p21, passwd, 16);
989 E_P24 (p21, c8, p24);
990}
991
992/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
993void
994NTLMSSPOWFencrypt (uchar passwd[8], uchar * ntlmchalresp, uchar p24[24])
995{
996 uchar p21[21];
997
998 memset (p21, '\0', 21);
999 memcpy (p21, passwd, 8);
1000 memset (p21 + 8, 0xbd, 8);
1001
1002 E_P24 (p21, ntlmchalresp, p24);
1003#ifdef DEBUG_PASSWORD
1004 DEBUG (100, ("NTLMSSPOWFencrypt: p21, c8, p24\n"));
1005 dump_data (100, (char *) p21, 21);
1006 dump_data (100, (char *) ntlmchalresp, 8);
1007 dump_data (100, (char *) p24, 24);
1008#endif
1009}
1010
1011
1012/* Does the NT MD4 hash then des encryption. */
1013
1014void
1015spa_smb_nt_encrypt (uchar * passwd, uchar * c8, uchar * p24)
1016{
1017 uchar p21[21];
1018
1019 memset (p21, '\0', 21);
1020
1021 E_md4hash (passwd, p21);
1022 SMBOWFencrypt (p21, c8, p24);
1023
1024#ifdef DEBUG_PASSWORD
1025 DEBUG (100, ("spa_smb_nt_encrypt: nt#, challenge, response\n"));
1026 dump_data (100, (char *) p21, 16);
1027 dump_data (100, (char *) c8, 8);
1028 dump_data (100, (char *) p24, 24);
1029#endif
1030}
1031
1032static uint32x A, B, C, D;
1033
1034static uint32x
1035F (uint32x X, uint32x Y, uint32x Z)
1036{
1037 return (X & Y) | ((~X) & Z);
1038}
1039
1040static uint32x
1041G (uint32x X, uint32x Y, uint32x Z)
1042{
1043 return (X & Y) | (X & Z) | (Y & Z);
1044}
1045
1046static uint32x
1047H (uint32x X, uint32x Y, uint32x Z)
1048{
1049 return X ^ Y ^ Z;
1050}
1051
1052static uint32x
1053lshift_a (uint32x x, int s)
1054{
1055 x &= 0xFFFFFFFF;
1056 return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
1057}
1058
1059#define ROUND1(a,b,c,d,k,s) a = lshift_a(a + F(b,c,d) + X[k], s)
1060#define ROUND2(a,b,c,d,k,s) a = lshift_a(a + G(b,c,d) + X[k] + (uint32x)0x5A827999,s)
1061#define ROUND3(a,b,c,d,k,s) a = lshift_a(a + H(b,c,d) + X[k] + (uint32x)0x6ED9EBA1,s)
1062
1063/* this applies md4 to 64 byte chunks */
1064static void
1065spa_mdfour64 (uint32x * M)
1066{
1067 int j;
1068 uint32x AA, BB, CC, DD;
1069 uint32x X[16];
1070
1071 for (j = 0; j < 16; j++)
1072 X[j] = M[j];
1073
1074 AA = A;
1075 BB = B;
1076 CC = C;
1077 DD = D;
1078
1079 ROUND1 (A, B, C, D, 0, 3);
1080 ROUND1 (D, A, B, C, 1, 7);
1081 ROUND1 (C, D, A, B, 2, 11);
1082 ROUND1 (B, C, D, A, 3, 19);
1083 ROUND1 (A, B, C, D, 4, 3);
1084 ROUND1 (D, A, B, C, 5, 7);
1085 ROUND1 (C, D, A, B, 6, 11);
1086 ROUND1 (B, C, D, A, 7, 19);
1087 ROUND1 (A, B, C, D, 8, 3);
1088 ROUND1 (D, A, B, C, 9, 7);
1089 ROUND1 (C, D, A, B, 10, 11);
1090 ROUND1 (B, C, D, A, 11, 19);
1091 ROUND1 (A, B, C, D, 12, 3);
1092 ROUND1 (D, A, B, C, 13, 7);
1093 ROUND1 (C, D, A, B, 14, 11);
1094 ROUND1 (B, C, D, A, 15, 19);
1095
1096 ROUND2 (A, B, C, D, 0, 3);
1097 ROUND2 (D, A, B, C, 4, 5);
1098 ROUND2 (C, D, A, B, 8, 9);
1099 ROUND2 (B, C, D, A, 12, 13);
1100 ROUND2 (A, B, C, D, 1, 3);
1101 ROUND2 (D, A, B, C, 5, 5);
1102 ROUND2 (C, D, A, B, 9, 9);
1103 ROUND2 (B, C, D, A, 13, 13);
1104 ROUND2 (A, B, C, D, 2, 3);
1105 ROUND2 (D, A, B, C, 6, 5);
1106 ROUND2 (C, D, A, B, 10, 9);
1107 ROUND2 (B, C, D, A, 14, 13);
1108 ROUND2 (A, B, C, D, 3, 3);
1109 ROUND2 (D, A, B, C, 7, 5);
1110 ROUND2 (C, D, A, B, 11, 9);
1111 ROUND2 (B, C, D, A, 15, 13);
1112
1113 ROUND3 (A, B, C, D, 0, 3);
1114 ROUND3 (D, A, B, C, 8, 9);
1115 ROUND3 (C, D, A, B, 4, 11);
1116 ROUND3 (B, C, D, A, 12, 15);
1117 ROUND3 (A, B, C, D, 2, 3);
1118 ROUND3 (D, A, B, C, 10, 9);
1119 ROUND3 (C, D, A, B, 6, 11);
1120 ROUND3 (B, C, D, A, 14, 15);
1121 ROUND3 (A, B, C, D, 1, 3);
1122 ROUND3 (D, A, B, C, 9, 9);
1123 ROUND3 (C, D, A, B, 5, 11);
1124 ROUND3 (B, C, D, A, 13, 15);
1125 ROUND3 (A, B, C, D, 3, 3);
1126 ROUND3 (D, A, B, C, 11, 9);
1127 ROUND3 (C, D, A, B, 7, 11);
1128 ROUND3 (B, C, D, A, 15, 15);
1129
1130 A += AA;
1131 B += BB;
1132 C += CC;
1133 D += DD;
1134
1135 A &= 0xFFFFFFFF;
1136 B &= 0xFFFFFFFF;
1137 C &= 0xFFFFFFFF;
1138 D &= 0xFFFFFFFF;
1139
1140 for (j = 0; j < 16; j++)
1141 X[j] = 0;
1142}
1143
1144static void
1145copy64 (uint32x * M, unsigned char *in)
1146{
1147 int i;
1148
1149 for (i = 0; i < 16; i++)
1150 M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
1151 (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
1152}
1153
1154static void
1155copy4 (unsigned char *out, uint32x x)
1156{
1157 out[0] = x & 0xFF;
1158 out[1] = (x >> 8) & 0xFF;
1159 out[2] = (x >> 16) & 0xFF;
1160 out[3] = (x >> 24) & 0xFF;
1161}
1162
1163/* produce a md4 message digest from data of length n bytes */
1164void
1165mdfour (unsigned char *out, unsigned char *in, int n)
1166{
1167 unsigned char buf[128];
1168 uint32x M[16];
1169 uint32x b = n * 8;
1170 int i;
1171
1172 A = 0x67452301;
1173 B = 0xefcdab89;
1174 C = 0x98badcfe;
1175 D = 0x10325476;
1176
1177 while (n > 64)
1178 {
1179 copy64 (M, in);
1180 spa_mdfour64 (M);
1181 in += 64;
1182 n -= 64;
1183 }
1184
1185 for (i = 0; i < 128; i++)
1186 buf[i] = 0;
1187 memcpy (buf, in, n);
1188 buf[n] = 0x80;
1189
1190 if (n <= 55)
1191 {
1192 copy4 (buf + 56, b);
1193 copy64 (M, buf);
1194 spa_mdfour64 (M);
1195 }
1196 else
1197 {
1198 copy4 (buf + 120, b);
1199 copy64 (M, buf);
1200 spa_mdfour64 (M);
1201 copy64 (M, buf + 64);
1202 spa_mdfour64 (M);
1203 }
1204
1205 for (i = 0; i < 128; i++)
1206 buf[i] = 0;
1207 copy64 (M, buf);
1208
1209 copy4 (out, A);
1210 copy4 (out + 4, B);
1211 copy4 (out + 8, C);
1212 copy4 (out + 12, D);
1213
1214 A = B = C = D = 0;
1215}
1216
1217char versionString[] = "libntlm version 0.21";
1218
1219/* Utility routines that handle NTLM auth structures. */
1220
1221/* The [IS]VAL macros are to take care of byte order for non-Intel
1222 * Machines -- I think this file is OK, but it hasn't been tested.
1223 * The other files (the ones stolen from Samba) should be OK.
1224 */
1225
1226
1227/* I am not crazy about these macros -- they seem to have gotten
1228 * a bit complex. A new scheme for handling string/buffer fields
1229 * in the structures probably needs to be designed
1230 */
1231
1232#define spa_bytes_add(ptr, header, buf, count) \
1233{ \
1234if (buf && count) \
1235 { \
1236 SSVAL(&ptr->header.len,0,count); \
1237 SSVAL(&ptr->header.maxlen,0,count); \
1238 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1239 memcpy(ptr->buffer+ptr->bufIndex, buf, count); \
1240 ptr->bufIndex += count; \
1241 } \
1242else \
1243 { \
1244 ptr->header.len = \
1245 ptr->header.maxlen = 0; \
1246 SIVAL(&ptr->header.offset,0,((ptr->buffer - ((uint8x*)ptr)) + ptr->bufIndex)); \
1247 } \
1248}
1249
1250#define spa_string_add(ptr, header, string) \
1251{ \
1252char *p = string; \
1253int len = 0; \
1254if (p) len = strlen(p); \
1255spa_bytes_add(ptr, header, ((unsigned char*)p), len); \
1256}
1257
1258#define spa_unicode_add_string(ptr, header, string) \
1259{ \
1260char *p = string; \
1261unsigned char *b = NULL; \
1262int len = 0; \
1263if (p) \
1264 { \
1265 len = strlen(p); \
1266 b = strToUnicode(p); \
1267 } \
1268spa_bytes_add(ptr, header, b, len*2); \
1269}
1270
1271
1272#define GetUnicodeString(structPtr, header) \
1273unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
1274#define GetString(structPtr, header) \
1275toString((((char *)structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
1276#define DumpBuffer(fp, structPtr, header) \
1277dumpRaw(fp,((unsigned char*)structPtr)+IVAL(&structPtr->header.offset,0),SVAL(&structPtr->header.len,0))
1278
1279
1280static void
1281dumpRaw (FILE * fp, unsigned char *buf, size_t len)
1282{
1283 int i;
1284
1285 for (i = 0; i < len; ++i)
1286 fprintf (fp, "%02x ", buf[i]);
1287
1288 fprintf (fp, "\n");
1289}
1290
1291char *
1292unicodeToString (char *p, size_t len)
1293{
1294 int i;
1295 static char buf[1024];
1296
1297 assert (len + 1 < sizeof buf);
1298
1299 for (i = 0; i < len; ++i)
1300 {
1301 buf[i] = *p & 0x7f;
1302 p += 2;
1303 }
1304
1305 buf[i] = '\0';
1306 return buf;
1307}
1308
1309static unsigned char *
1310strToUnicode (char *p)
1311{
1312 static unsigned char buf[1024];
1313 size_t l = strlen (p);
1314 int i = 0;
1315
1316 assert (l * 2 < sizeof buf);
1317
1318 while (l--)
1319 {
1320 buf[i++] = *p++;
1321 buf[i++] = 0;
1322 }
1323
1324 return buf;
1325}
1326
1327static unsigned char *
1328toString (char *p, size_t len)
1329{
1330 static unsigned char buf[1024];
1331
1332 assert (len + 1 < sizeof buf);
1333
1334 memcpy (buf, p, len);
1335 buf[len] = 0;
1336 return buf;
1337}
1338
1339void
1340dumpSmbNtlmAuthRequest (FILE * fp, SPAAuthRequest * request)
1341{
1342 fprintf (fp, "NTLM Request:\n");
1343 fprintf (fp, " Ident = %s\n", request->ident);
1344 fprintf (fp, " mType = %d\n", IVAL (&request->msgType, 0));
1345 fprintf (fp, " Flags = %08x\n", IVAL (&request->flags, 0));
1346 fprintf (fp, " User = %s\n", GetString (request, user));
1347 fprintf (fp, " Domain = %s\n", GetString (request, domain));
1348}
1349
1350void
1351dumpSmbNtlmAuthChallenge (FILE * fp, SPAAuthChallenge * challenge)
1352{
1353 fprintf (fp, "NTLM Challenge:\n");
1354 fprintf (fp, " Ident = %s\n", challenge->ident);
1355 fprintf (fp, " mType = %d\n", IVAL (&challenge->msgType, 0));
1356 fprintf (fp, " Domain = %s\n", GetUnicodeString (challenge, uDomain));
1357 fprintf (fp, " Flags = %08x\n", IVAL (&challenge->flags, 0));
1358 fprintf (fp, " Challenge = ");
1359 dumpRaw (fp, challenge->challengeData, 8);
1360}
1361
1362void
1363dumpSmbNtlmAuthResponse (FILE * fp, SPAAuthResponse * response)
1364{
1365 fprintf (fp, "NTLM Response:\n");
1366 fprintf (fp, " Ident = %s\n", response->ident);
1367 fprintf (fp, " mType = %d\n", IVAL (&response->msgType, 0));
1368 fprintf (fp, " LmResp = ");
1369 DumpBuffer (fp, response, lmResponse);
1370 fprintf (fp, " NTResp = ");
1371 DumpBuffer (fp, response, ntResponse);
1372 fprintf (fp, " Domain = %s\n", GetUnicodeString (response, uDomain));
1373 fprintf (fp, " User = %s\n", GetUnicodeString (response, uUser));
1374 fprintf (fp, " Wks = %s\n", GetUnicodeString (response, uWks));
1375 fprintf (fp, " sKey = ");
1376 DumpBuffer (fp, response, sessionKey);
1377 fprintf (fp, " Flags = %08x\n", IVAL (&response->flags, 0));
1378}
1379
1380void
1381spa_build_auth_request (SPAAuthRequest * request, char *user, char *domain)
1382{
1383 char *u = strdup (user);
1384 char *p = strchr (u, '@');
1385
1386 if (p)
1387 {
1388 if (!domain)
1389 domain = p + 1;
1390 *p = '\0';
1391 }
1392
1393 request->bufIndex = 0;
1394 memcpy (request->ident, "NTLMSSP\0\0\0", 8);
1395 SIVAL (&request->msgType, 0, 1);
1396 SIVAL (&request->flags, 0, 0x0000b207); /* have to figure out what these mean */
1397 spa_string_add (request, user, u);
1398 spa_string_add (request, domain, domain);
1399 free (u);
1400}
1401
1402
1403
1404void
1405spa_build_auth_challenge (SPAAuthRequest * request, SPAAuthChallenge * challenge)
1406{
1407 char chalstr[8];
1408 int i;
1409 int p = (int)getpid();
1410 int random_seed = (int)time(NULL) ^ ((p << 16) | p);
1411
1412 request = request; /* Added by PH to stop compilers whinging */
1413
1414 /* Ensure challenge data is cleared, in case it isn't all used. This
1415 patch added by PH on suggestion of Russell King */
1416
1417 memset(challenge, 0, sizeof(SPAAuthChallenge));
1418
1419 challenge->bufIndex = 0;
1420 memcpy (challenge->ident, "NTLMSSP\0", 8);
1421 SIVAL (&challenge->msgType, 0, 2);
1422 SIVAL (&challenge->flags, 0, 0x00008201);
1423 SIVAL (&challenge->uDomain.len, 0, 0x0000);
1424 SIVAL (&challenge->uDomain.maxlen, 0, 0x0000);
1425 SIVAL (&challenge->uDomain.offset, 0, 0x00002800);
1426
1427 /* generate eight pseudo random bytes (method ripped from host.c) */
1428
1429 for(i=0;i<8;i++) {
1430 chalstr[i] = (unsigned char)(random_seed >> 16) % 256;
1431 random_seed = (1103515245 - (chalstr[i])) * random_seed + 12345;
1432 };
1433
1434 memcpy(challenge->challengeData,chalstr,8);
1435}
1436
1437
1438
1439
1440/* This is the original source of this function, preserved here for reference.
1441The new version below was re-organized by PH following a patch and some further
1442suggestions from Mark Lyda to fix the problem that is described at the head of
1443this module. At the same time, I removed the untidiness in the code below that
1444involves the "d" and "domain" variables. */
1445
1446#ifdef NEVER
1447void
1448spa_build_auth_response (SPAAuthChallenge * challenge,
1449 SPAAuthResponse * response, char *user,
1450 char *password)
1451{
1452 uint8x lmRespData[24];
1453 uint8x ntRespData[24];
1454 char *d = strdup (GetUnicodeString (challenge, uDomain));
1455 char *domain = d;
1456 char *u = strdup (user);
1457 char *p = strchr (u, '@');
1458
1459 if (p)
1460 {
1461 domain = p + 1;
1462 *p = '\0';
1463 }
1464
1465 spa_smb_encrypt ((uchar *)password, challenge->challengeData, lmRespData);
1466 spa_smb_nt_encrypt ((uchar *)password, challenge->challengeData, ntRespData);
1467
1468 response->bufIndex = 0;
1469 memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1470 SIVAL (&response->msgType, 0, 3);
1471
1472 spa_bytes_add (response, lmResponse, lmRespData, 24);
1473 spa_bytes_add (response, ntResponse, ntRespData, 24);
1474 spa_unicode_add_string (response, uDomain, domain);
1475 spa_unicode_add_string (response, uUser, u);
1476 spa_unicode_add_string (response, uWks, u);
1477 spa_string_add (response, sessionKey, NULL);
1478
1479 response->flags = challenge->flags;
1480
1481 free (d);
1482 free (u);
1483}
1484#endif
1485
1486
1487/* This is the re-organized version (see comments above) */
1488
1489void
1490spa_build_auth_response (SPAAuthChallenge * challenge,
1491 SPAAuthResponse * response, char *user,
1492 char *password)
1493{
1494 uint8x lmRespData[24];
1495 uint8x ntRespData[24];
1496 uint32x cf = IVAL(&challenge->flags, 0);
1497 char *u = strdup (user);
1498 char *p = strchr (u, '@');
1499 char *d = NULL;
1500 char *domain;
1501
1502 if (p)
1503 {
1504 domain = p + 1;
1505 *p = '\0';
1506 }
1507
1508 else domain = d = strdup((cf & 0x1)?
1509 (const char *)GetUnicodeString(challenge, uDomain) :
1510 (const char *)GetString(challenge, uDomain));
1511
1512 spa_smb_encrypt ((uchar *)password, challenge->challengeData, lmRespData);
1513 spa_smb_nt_encrypt ((uchar *)password, challenge->challengeData, ntRespData);
1514
1515 response->bufIndex = 0;
1516 memcpy (response->ident, "NTLMSSP\0\0\0", 8);
1517 SIVAL (&response->msgType, 0, 3);
1518
1519 spa_bytes_add (response, lmResponse, lmRespData, (cf & 0x200) ? 24 : 0);
1520 spa_bytes_add (response, ntResponse, ntRespData, (cf & 0x8000) ? 24 : 0);
1521
1522 if (cf & 0x1) { /* Unicode Text */
1523 spa_unicode_add_string (response, uDomain, domain);
1524 spa_unicode_add_string (response, uUser, u);
1525 spa_unicode_add_string (response, uWks, u);
1526 } else { /* OEM Text */
1527 spa_string_add (response, uDomain, domain);
1528 spa_string_add (response, uUser, u);
1529 spa_string_add (response, uWks, u);
1530 }
1531
1532 spa_string_add (response, sessionKey, NULL);
1533 response->flags = challenge->flags;
1534
1535 if (d != NULL) free (d);
1536 free (u);
1537}