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