xref: /plan9/sys/src/cmd/cifs/auth-testcase.c (revision 671dfc474d1a5bcbeda8be1356d2abfa05b91489)
1*671dfc47SDavid du Colombier /*
2*671dfc47SDavid du Colombier  * Beware the LM hash is easy to crack (google for l0phtCrack)
3*671dfc47SDavid du Colombier  * and though NTLM is more secure it is still breakable.
4*671dfc47SDavid du Colombier  * Ntlmv2 is better and seen as good enough by the Windows community.
5*671dfc47SDavid du Colombier  * For real security use Kerberos.
6*671dfc47SDavid du Colombier  */
7*671dfc47SDavid du Colombier #include <u.h>
8*671dfc47SDavid du Colombier #include <libc.h>
9*671dfc47SDavid du Colombier #include <mp.h>
10*671dfc47SDavid du Colombier #include <auth.h>
11*671dfc47SDavid du Colombier #include <libsec.h>
12*671dfc47SDavid du Colombier #include <ctype.h>
13*671dfc47SDavid du Colombier #include <fcall.h>
14*671dfc47SDavid du Colombier #include <thread.h>
15*671dfc47SDavid du Colombier #include <9p.h>
16*671dfc47SDavid du Colombier #include "cifs.h"
17*671dfc47SDavid du Colombier 
18*671dfc47SDavid du Colombier #define NTLMV2_TEST	1
19*671dfc47SDavid du Colombier #define DEF_AUTH 	"ntlmv2"
20*671dfc47SDavid du Colombier 
21*671dfc47SDavid du Colombier static enum {
22*671dfc47SDavid du Colombier 	MACkeylen	= 40,	/* MAC key len */
23*671dfc47SDavid du Colombier 	MAClen		= 8,	/* signature length */
24*671dfc47SDavid du Colombier 	MACoff		= 14,	/* sign. offset from start of SMB (not netbios) pkt */
25*671dfc47SDavid du Colombier 	Bliplen		= 8,	/* size of LMv2 client nonce */
26*671dfc47SDavid du Colombier };
27*671dfc47SDavid du Colombier 
28*671dfc47SDavid du Colombier static void
dmp(char * s,int seq,void * buf,int n)29*671dfc47SDavid du Colombier dmp(char *s, int seq, void *buf, int n)
30*671dfc47SDavid du Colombier {
31*671dfc47SDavid du Colombier 	int i;
32*671dfc47SDavid du Colombier 	char *p = buf;
33*671dfc47SDavid du Colombier 
34*671dfc47SDavid du Colombier 	print("%s %3d      ", s, seq);
35*671dfc47SDavid du Colombier 	while(n > 0){
36*671dfc47SDavid du Colombier 		for(i = 0; i < 16 && n > 0; i++, n--)
37*671dfc47SDavid du Colombier 			print("%02x ", *p++ & 0xff);
38*671dfc47SDavid du Colombier 		if(n > 0)
39*671dfc47SDavid du Colombier 			print("\n");
40*671dfc47SDavid du Colombier 	}
41*671dfc47SDavid du Colombier 	print("\n");
42*671dfc47SDavid du Colombier }
43*671dfc47SDavid du Colombier 
44*671dfc47SDavid du Colombier static Auth *
auth_plain(char * windom,char * keyp,uchar * chal,int len)45*671dfc47SDavid du Colombier auth_plain(char *windom, char *keyp, uchar *chal, int len)
46*671dfc47SDavid du Colombier {
47*671dfc47SDavid du Colombier 	UserPasswd *up;
48*671dfc47SDavid du Colombier 	static Auth *ap;
49*671dfc47SDavid du Colombier 
50*671dfc47SDavid du Colombier 	USED(chal, len);
51*671dfc47SDavid du Colombier 
52*671dfc47SDavid du Colombier 	up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs %s",
53*671dfc47SDavid du Colombier 		windom, keyp);
54*671dfc47SDavid du Colombier 	if(! up)
55*671dfc47SDavid du Colombier 		sysfatal("cannot get key - %r");
56*671dfc47SDavid du Colombier 
57*671dfc47SDavid du Colombier 	ap = emalloc9p(sizeof(Auth));
58*671dfc47SDavid du Colombier 	memset(ap, 0, sizeof(ap));
59*671dfc47SDavid du Colombier 	ap->user = estrdup9p(up->user);
60*671dfc47SDavid du Colombier 	ap->windom = estrdup9p(windom);
61*671dfc47SDavid du Colombier 
62*671dfc47SDavid du Colombier 	ap->resp[0] = estrdup9p(up->passwd);
63*671dfc47SDavid du Colombier 	ap->len[0] = strlen(up->passwd);
64*671dfc47SDavid du Colombier 	memset(up->passwd, 0, strlen(up->passwd));
65*671dfc47SDavid du Colombier 	free(up);
66*671dfc47SDavid du Colombier 
67*671dfc47SDavid du Colombier 	return ap;
68*671dfc47SDavid du Colombier }
69*671dfc47SDavid du Colombier 
70*671dfc47SDavid du Colombier static Auth *
auth_lm_and_ntlm(char * windom,char * keyp,uchar * chal,int len)71*671dfc47SDavid du Colombier auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
72*671dfc47SDavid du Colombier {
73*671dfc47SDavid du Colombier 	int err;
74*671dfc47SDavid du Colombier 	Auth *ap;
75*671dfc47SDavid du Colombier 	char user[64];
76*671dfc47SDavid du Colombier 	MSchapreply mcr;
77*671dfc47SDavid du Colombier 
78*671dfc47SDavid du Colombier 	err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr,
79*671dfc47SDavid du Colombier 		auth_getkey, "windom=%s proto=mschap role=client service=cifs %s",
80*671dfc47SDavid du Colombier 		windom, keyp);
81*671dfc47SDavid du Colombier 	if(err == -1)
82*671dfc47SDavid du Colombier 		sysfatal("cannot get key - %r");
83*671dfc47SDavid du Colombier 
84*671dfc47SDavid du Colombier 	ap = emalloc9p(sizeof(Auth));
85*671dfc47SDavid du Colombier 	memset(ap, 0, sizeof(ap));
86*671dfc47SDavid du Colombier 	ap->user = estrdup9p(user);
87*671dfc47SDavid du Colombier 	ap->windom = estrdup9p(windom);
88*671dfc47SDavid du Colombier 
89*671dfc47SDavid du Colombier 	/* LM response */
90*671dfc47SDavid du Colombier 	ap->len[0] = sizeof(mcr.LMresp);
91*671dfc47SDavid du Colombier 	ap->resp[0] = emalloc9p(ap->len[0]);
92*671dfc47SDavid du Colombier 	memcpy(ap->resp[0], mcr.LMresp, ap->len[0]);
93*671dfc47SDavid du Colombier 
94*671dfc47SDavid du Colombier 	/* NTLM response */
95*671dfc47SDavid du Colombier 	ap->len[1] = sizeof(mcr.NTresp);
96*671dfc47SDavid du Colombier 	ap->resp[1] = emalloc9p(ap->len[1]);
97*671dfc47SDavid du Colombier 	memcpy(ap->resp[1], mcr.NTresp, ap->len[1]);
98*671dfc47SDavid du Colombier 
99*671dfc47SDavid du Colombier 	return ap;
100*671dfc47SDavid du Colombier }
101*671dfc47SDavid du Colombier 
102*671dfc47SDavid du Colombier /*
103*671dfc47SDavid du Colombier  * NTLM response only, the LM response is a just
104*671dfc47SDavid du Colombier  * copy of the NTLM one.  We do this because the lm
105*671dfc47SDavid du Colombier  * response is easily reversed - Google for l0pht for more info.
106*671dfc47SDavid du Colombier  */
107*671dfc47SDavid du Colombier static Auth *
auth_ntlm(char * windom,char * keyp,uchar * chal,int len)108*671dfc47SDavid du Colombier auth_ntlm(char *windom, char *keyp, uchar *chal, int len)
109*671dfc47SDavid du Colombier {
110*671dfc47SDavid du Colombier 	Auth *ap;
111*671dfc47SDavid du Colombier 
112*671dfc47SDavid du Colombier 	if((ap = auth_lm_and_ntlm(windom, keyp, chal, len)) == nil)
113*671dfc47SDavid du Colombier 		return nil;
114*671dfc47SDavid du Colombier 
115*671dfc47SDavid du Colombier 	free(ap->resp[0]);
116*671dfc47SDavid du Colombier 	ap->len[0] = ap->len[1];
117*671dfc47SDavid du Colombier 	ap->resp[0] = emalloc9p(ap->len[0]);
118*671dfc47SDavid du Colombier 	memcpy(ap->resp[0], ap->resp[1], ap->len[0]);
119*671dfc47SDavid du Colombier 	return ap;
120*671dfc47SDavid du Colombier }
121*671dfc47SDavid du Colombier 
122*671dfc47SDavid du Colombier /*
123*671dfc47SDavid du Colombier  * This is not really nescessary as all fields hmac_md5'ed
124*671dfc47SDavid du Colombier  * in the ntlmv2 protocol are less than 64 bytes long, however
125*671dfc47SDavid du Colombier  * I still do this for completeness.
126*671dfc47SDavid du Colombier  */
127*671dfc47SDavid du Colombier static DigestState *
hmac_t64(uchar * data,ulong dlen,uchar * key,ulong klen,uchar * digest,DigestState * state)128*671dfc47SDavid du Colombier hmac_t64(uchar *data, ulong dlen, uchar *key, ulong klen, uchar *digest,
129*671dfc47SDavid du Colombier 	DigestState *state)
130*671dfc47SDavid du Colombier {
131*671dfc47SDavid du Colombier 	if(klen > 64)
132*671dfc47SDavid du Colombier 		klen = 64;
133*671dfc47SDavid du Colombier 	return hmac_md5(data, dlen, key, klen, digest, state);
134*671dfc47SDavid du Colombier }
135*671dfc47SDavid du Colombier 
136*671dfc47SDavid du Colombier 
137*671dfc47SDavid du Colombier static int
ntv2_blob(uchar * blob,int len,char * windom)138*671dfc47SDavid du Colombier ntv2_blob(uchar *blob, int len, char *windom)
139*671dfc47SDavid du Colombier {
140*671dfc47SDavid du Colombier 	int n;
141*671dfc47SDavid du Colombier 	uvlong nttime;
142*671dfc47SDavid du Colombier 	Rune r;
143*671dfc47SDavid du Colombier 	char *d;
144*671dfc47SDavid du Colombier 	uchar *p;
145*671dfc47SDavid du Colombier 	enum {			/* name types */
146*671dfc47SDavid du Colombier 		Beof,		/* end of name list */
147*671dfc47SDavid du Colombier 		Bnetbios,	/* Netbios machine name */
148*671dfc47SDavid du Colombier 		Bdomain,	/* Windows Domain name (NT) */
149*671dfc47SDavid du Colombier 		Bdnsfqdn,	/* DNS Fully Qualified Domain Name */
150*671dfc47SDavid du Colombier 		Bdnsname,	/* DNS machine name (win2k) */
151*671dfc47SDavid du Colombier 	};
152*671dfc47SDavid du Colombier 
153*671dfc47SDavid du Colombier 	p = blob;
154*671dfc47SDavid du Colombier 	*p++ = 1;		/* response type */
155*671dfc47SDavid du Colombier 	*p++ = 1;		/* max response type understood by client */
156*671dfc47SDavid du Colombier 
157*671dfc47SDavid du Colombier 	*p++ = 0;
158*671dfc47SDavid du Colombier 	*p++ = 0;		/* 2 bytes reserved */
159*671dfc47SDavid du Colombier 
160*671dfc47SDavid du Colombier 	*p++ = 0;
161*671dfc47SDavid du Colombier 	*p++ = 0;
162*671dfc47SDavid du Colombier 	*p++ = 0;
163*671dfc47SDavid du Colombier 	*p++ = 0;		/* 4 bytes unknown */
164*671dfc47SDavid du Colombier 
165*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
166*671dfc47SDavid du Colombier 	*p++ = 0xf0;
167*671dfc47SDavid du Colombier 	*p++ = 0x20;
168*671dfc47SDavid du Colombier 	*p++ = 0xd0;
169*671dfc47SDavid du Colombier 	*p++ = 0xb6;
170*671dfc47SDavid du Colombier 	*p++ = 0xc2;
171*671dfc47SDavid du Colombier 	*p++ = 0x92;
172*671dfc47SDavid du Colombier 	*p++ = 0xbe;
173*671dfc47SDavid du Colombier 	*p++ = 0x01;
174*671dfc47SDavid du Colombier #else
175*671dfc47SDavid du Colombier 	nttime = time(nil);	/* nt time now */
176*671dfc47SDavid du Colombier 	nttime = nttime + 11644473600LL;
177*671dfc47SDavid du Colombier 	nttime = nttime * 10000000LL;
178*671dfc47SDavid du Colombier 	*p++ = nttime & 0xff;
179*671dfc47SDavid du Colombier 	*p++ = (nttime >> 8) & 0xff;
180*671dfc47SDavid du Colombier 	*p++ = (nttime >> 16) & 0xff;
181*671dfc47SDavid du Colombier 	*p++ = (nttime >> 24) & 0xff;
182*671dfc47SDavid du Colombier 	*p++ = (nttime >> 32) & 0xff;
183*671dfc47SDavid du Colombier 	*p++ = (nttime >> 40) & 0xff;
184*671dfc47SDavid du Colombier 	*p++ = (nttime >> 48) & 0xff;
185*671dfc47SDavid du Colombier 	*p++ = (nttime >> 56) & 0xff;
186*671dfc47SDavid du Colombier #endif
187*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
188*671dfc47SDavid du Colombier 	*p++ = 0x05;
189*671dfc47SDavid du Colombier 	*p++ = 0x83;
190*671dfc47SDavid du Colombier 	*p++ = 0x32;
191*671dfc47SDavid du Colombier 	*p++ = 0xec;
192*671dfc47SDavid du Colombier 	*p++ = 0xfa;
193*671dfc47SDavid du Colombier 	*p++ = 0xe4;
194*671dfc47SDavid du Colombier 	*p++ = 0xf3;
195*671dfc47SDavid du Colombier 	*p++ = 0x6d;
196*671dfc47SDavid du Colombier #else
197*671dfc47SDavid du Colombier 	genrandom(p, 8);
198*671dfc47SDavid du Colombier 	p += 8;			/* client nonce */
199*671dfc47SDavid du Colombier #endif
200*671dfc47SDavid du Colombier 	*p++ = 0x6f;
201*671dfc47SDavid du Colombier 	*p++ = 0;
202*671dfc47SDavid du Colombier 	*p++ = 0x6e;
203*671dfc47SDavid du Colombier 	*p++ = 0;		/* unknown data */
204*671dfc47SDavid du Colombier 
205*671dfc47SDavid du Colombier 	*p++ = Bdomain;
206*671dfc47SDavid du Colombier 	*p++ = 0;		/* name type */
207*671dfc47SDavid du Colombier 
208*671dfc47SDavid du Colombier 	n = utflen(windom) * 2;
209*671dfc47SDavid du Colombier 	*p++ = n;
210*671dfc47SDavid du Colombier 	*p++ = n >> 8;		/* name length */
211*671dfc47SDavid du Colombier 
212*671dfc47SDavid du Colombier 	d = windom;
213*671dfc47SDavid du Colombier 	while(*d && p - blob < len - 8){
214*671dfc47SDavid du Colombier 		d += chartorune(&r, d);
215*671dfc47SDavid du Colombier 		r = toupperrune(r);
216*671dfc47SDavid du Colombier 		*p++ = r;
217*671dfc47SDavid du Colombier 		*p++ = r >> 8;
218*671dfc47SDavid du Colombier 	}
219*671dfc47SDavid du Colombier 
220*671dfc47SDavid du Colombier 	*p++ = 0;
221*671dfc47SDavid du Colombier 	*p++ = Beof;		/* name type */
222*671dfc47SDavid du Colombier 
223*671dfc47SDavid du Colombier 	*p++ = 0;
224*671dfc47SDavid du Colombier 	*p++ = 0;		/* name length */
225*671dfc47SDavid du Colombier 
226*671dfc47SDavid du Colombier 	*p++ = 0x65;
227*671dfc47SDavid du Colombier 	*p++ = 0;
228*671dfc47SDavid du Colombier 	*p++ = 0;
229*671dfc47SDavid du Colombier 	*p++ = 0;		/* unknown data */
230*671dfc47SDavid du Colombier 	return p - blob;
231*671dfc47SDavid du Colombier }
232*671dfc47SDavid du Colombier 
233*671dfc47SDavid du Colombier static Auth *
auth_ntlmv2(char * windom,char * keyp,uchar * chal,int len)234*671dfc47SDavid du Colombier auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len)
235*671dfc47SDavid du Colombier {
236*671dfc47SDavid du Colombier 	int i, n;
237*671dfc47SDavid du Colombier 	Rune r;
238*671dfc47SDavid du Colombier 	char *p, *u;
239*671dfc47SDavid du Colombier 	uchar c, lm_hmac[MD5dlen], nt_hmac[MD5dlen], nt_sesskey[MD5dlen];
240*671dfc47SDavid du Colombier 	uchar lm_sesskey[MD5dlen];
241*671dfc47SDavid du Colombier 	uchar v1hash[MD5dlen], blip[Bliplen], blob[1024], v2hash[MD5dlen];
242*671dfc47SDavid du Colombier 	DigestState *ds;
243*671dfc47SDavid du Colombier 	UserPasswd *up;
244*671dfc47SDavid du Colombier 	static Auth *ap;
245*671dfc47SDavid du Colombier 
246*671dfc47SDavid du Colombier 	up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs-ntlmv2 %s",
247*671dfc47SDavid du Colombier 		windom, keyp);
248*671dfc47SDavid du Colombier 	if(! up)
249*671dfc47SDavid du Colombier 		sysfatal("cannot get key - %r");
250*671dfc47SDavid du Colombier 
251*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
252*671dfc47SDavid du Colombier {
253*671dfc47SDavid du Colombier 	static uchar srvchal[] = { 0x52, 0xaa, 0xc8, 0xe8, 0x2c, 0x06, 0x7f, 0xa1 };
254*671dfc47SDavid du Colombier 	up->user = "ADMINISTRATOR";
255*671dfc47SDavid du Colombier 	windom = "rocknroll";
256*671dfc47SDavid du Colombier 	chal = srvchal;
257*671dfc47SDavid du Colombier }
258*671dfc47SDavid du Colombier #endif
259*671dfc47SDavid du Colombier 	ap = emalloc9p(sizeof(Auth));
260*671dfc47SDavid du Colombier 	memset(ap, 0, sizeof(ap));
261*671dfc47SDavid du Colombier 
262*671dfc47SDavid du Colombier 	/* Standard says unlimited length, experience says 128 max */
263*671dfc47SDavid du Colombier 	if((n = strlen(up->passwd)) > 128)
264*671dfc47SDavid du Colombier 		n = 128;
265*671dfc47SDavid du Colombier 
266*671dfc47SDavid du Colombier 	ds = md4(nil, 0, nil, nil);
267*671dfc47SDavid du Colombier 	for(i = 0, p = up->passwd; i < n; i++) {
268*671dfc47SDavid du Colombier 		p += chartorune(&r, p);
269*671dfc47SDavid du Colombier 		c = r;
270*671dfc47SDavid du Colombier 		md4(&c, 1, nil, ds);
271*671dfc47SDavid du Colombier 		c = r >> 8;
272*671dfc47SDavid du Colombier 		md4(&c, 1, nil, ds);
273*671dfc47SDavid du Colombier 	}
274*671dfc47SDavid du Colombier 	md4(nil, 0, v1hash, ds);
275*671dfc47SDavid du Colombier 
276*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
277*671dfc47SDavid du Colombier {
278*671dfc47SDavid du Colombier 	uchar v1[] = {
279*671dfc47SDavid du Colombier 		0x0c, 0xb6, 0x94, 0x88, 0x05, 0xf7, 0x97, 0xbf,
280*671dfc47SDavid du Colombier 		0x2a, 0x82, 0x80, 0x79, 0x73, 0xb8, 0x95, 0x37
281*671dfc47SDavid du Colombier 	;
282*671dfc47SDavid du Colombier 	memcpy(v1hash, v1, sizeof(v1));
283*671dfc47SDavid du Colombier }
284*671dfc47SDavid du Colombier #endif
285*671dfc47SDavid du Colombier 	/*
286*671dfc47SDavid du Colombier 	 * Some documentation insists that the username must be forced to
287*671dfc47SDavid du Colombier 	 * uppercase, but the domain name should not be. Other shows both
288*671dfc47SDavid du Colombier 	 * being forced to uppercase.  I am pretty sure this is irrevevant as
289*671dfc47SDavid du Colombier 	 * the domain name passed from the remote server always seems to be in
290*671dfc47SDavid du Colombier 	 * uppercase already.
291*671dfc47SDavid du Colombier 	 */
292*671dfc47SDavid du Colombier         ds = hmac_t64(nil, 0, v1hash, MD5dlen, nil, nil);
293*671dfc47SDavid du Colombier 	u = up->user;
294*671dfc47SDavid du Colombier 	while(*u){
295*671dfc47SDavid du Colombier 		u += chartorune(&r, u);
296*671dfc47SDavid du Colombier 		r = toupperrune(r);
297*671dfc47SDavid du Colombier 		c = r & 0xff;
298*671dfc47SDavid du Colombier         	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
299*671dfc47SDavid du Colombier 		c = r >> 8;
300*671dfc47SDavid du Colombier         	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
301*671dfc47SDavid du Colombier 	}
302*671dfc47SDavid du Colombier 	u = windom;
303*671dfc47SDavid du Colombier 
304*671dfc47SDavid du Colombier 	while(*u){
305*671dfc47SDavid du Colombier 		u += chartorune(&r, u);
306*671dfc47SDavid du Colombier 		c = r;
307*671dfc47SDavid du Colombier         	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
308*671dfc47SDavid du Colombier 		c = r >> 8;
309*671dfc47SDavid du Colombier         	hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
310*671dfc47SDavid du Colombier 	}
311*671dfc47SDavid du Colombier         hmac_t64(nil, 0, v1hash, MD5dlen, v2hash, ds);
312*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
313*671dfc47SDavid du Colombier 	print("want:               40 e1 b3 24...\n");
314*671dfc47SDavid du Colombier 	dmp("v2hash==kr", 0, v2hash, MD5dlen);
315*671dfc47SDavid du Colombier #endif
316*671dfc47SDavid du Colombier 	ap->user = estrdup9p(up->user);
317*671dfc47SDavid du Colombier 	ap->windom = estrdup9p(windom);
318*671dfc47SDavid du Colombier 
319*671dfc47SDavid du Colombier 	/* LM v2 */
320*671dfc47SDavid du Colombier 
321*671dfc47SDavid du Colombier 	genrandom(blip, Bliplen);
322*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
323*671dfc47SDavid du Colombier {
324*671dfc47SDavid du Colombier 	uchar t[] = { 0x05, 0x83, 0x32, 0xec, 0xfa, 0xe4, 0xf3, 0x6d };
325*671dfc47SDavid du Colombier 	memcpy(blip, t, 8);
326*671dfc47SDavid du Colombier }
327*671dfc47SDavid du Colombier #endif
328*671dfc47SDavid du Colombier         ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
329*671dfc47SDavid du Colombier 	hmac_t64(blip, Bliplen, v2hash, MD5dlen, lm_hmac, ds);
330*671dfc47SDavid du Colombier 	ap->len[0] = MD5dlen+Bliplen;
331*671dfc47SDavid du Colombier 	ap->resp[0] = emalloc9p(ap->len[0]);
332*671dfc47SDavid du Colombier 	memcpy(ap->resp[0], lm_hmac, MD5dlen);
333*671dfc47SDavid du Colombier 	memcpy(ap->resp[0]+MD5dlen, blip, Bliplen);
334*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
335*671dfc47SDavid du Colombier 	print("want:               38 6b ae...\n");
336*671dfc47SDavid du Colombier 	dmp("lmv2 resp ", 0, lm_hmac, MD5dlen);
337*671dfc47SDavid du Colombier #endif
338*671dfc47SDavid du Colombier 
339*671dfc47SDavid du Colombier 	/* LM v2 session key */
340*671dfc47SDavid du Colombier 	hmac_t64(lm_hmac, MD5dlen, v2hash, MD5dlen, lm_sesskey, nil);
341*671dfc47SDavid du Colombier 
342*671dfc47SDavid du Colombier 	/* LM v2 MAC key */
343*671dfc47SDavid du Colombier 	ap->mackey[0] = emalloc9p(MACkeylen);
344*671dfc47SDavid du Colombier 	memcpy(ap->mackey[0], lm_sesskey, MD5dlen);
345*671dfc47SDavid du Colombier 	memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen);
346*671dfc47SDavid du Colombier 
347*671dfc47SDavid du Colombier 	/* NTLM v2 */
348*671dfc47SDavid du Colombier 	n = ntv2_blob(blob, sizeof(blob), windom);
349*671dfc47SDavid du Colombier         ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
350*671dfc47SDavid du Colombier 	hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds);
351*671dfc47SDavid du Colombier 	ap->len[1] = MD5dlen+n;
352*671dfc47SDavid du Colombier 	ap->resp[1] = emalloc9p(ap->len[1]);
353*671dfc47SDavid du Colombier 	memcpy(ap->resp[1], nt_hmac, MD5dlen);
354*671dfc47SDavid du Colombier 	memcpy(ap->resp[1]+MD5dlen, blob, n);
355*671dfc47SDavid du Colombier #ifdef NTLMV2_TEST
356*671dfc47SDavid du Colombier 	print("want:               1a ad 55...\n");
357*671dfc47SDavid du Colombier 	dmp("ntv2 resp ", 0, nt_hmac, MD5dlen);
358*671dfc47SDavid du Colombier #endif
359*671dfc47SDavid du Colombier 
360*671dfc47SDavid du Colombier 	/* NTLM v2 session key */
361*671dfc47SDavid du Colombier 	hmac_t64(nt_hmac, MD5dlen, v2hash, MD5dlen, nt_sesskey, nil);
362*671dfc47SDavid du Colombier 
363*671dfc47SDavid du Colombier 	/* NTLM v2 MAC key */
364*671dfc47SDavid du Colombier 	ap->mackey[1] = emalloc9p(MACkeylen);
365*671dfc47SDavid du Colombier 	memcpy(ap->mackey[1], nt_sesskey, MD5dlen);
366*671dfc47SDavid du Colombier 	memcpy(ap->mackey[1]+MD5dlen, ap->resp[1], MACkeylen-MD5dlen);
367*671dfc47SDavid du Colombier 	free(up);
368*671dfc47SDavid du Colombier 
369*671dfc47SDavid du Colombier 	return ap;
370*671dfc47SDavid du Colombier }
371*671dfc47SDavid du Colombier 
372*671dfc47SDavid du Colombier struct {
373*671dfc47SDavid du Colombier 	char	*name;
374*671dfc47SDavid du Colombier 	Auth	*(*func)(char *, char *, uchar *, int);
375*671dfc47SDavid du Colombier } methods[] = {
376*671dfc47SDavid du Colombier 	{ "plain",	auth_plain },
377*671dfc47SDavid du Colombier 	{ "lm+ntlm",	auth_lm_and_ntlm },
378*671dfc47SDavid du Colombier 	{ "ntlm",	auth_ntlm },
379*671dfc47SDavid du Colombier 	{ "ntlmv2",	auth_ntlmv2 },
380*671dfc47SDavid du Colombier //	{ "kerberos",	auth_kerberos },
381*671dfc47SDavid du Colombier };
382*671dfc47SDavid du Colombier 
383*671dfc47SDavid du Colombier void
384*671dfc47SDavid du Colombier autherr(void)
385*671dfc47SDavid du Colombier {
386*671dfc47SDavid du Colombier 	int i;
387*671dfc47SDavid du Colombier 
388*671dfc47SDavid du Colombier 	fprint(2, "supported auth methods:\t");
389*671dfc47SDavid du Colombier 	for(i = 0; i < nelem(methods); i++)
390*671dfc47SDavid du Colombier 		fprint(2, "%s ", methods[i].name);
391*671dfc47SDavid du Colombier 	fprint(2, "\n");
392*671dfc47SDavid du Colombier 	exits("usage");
393*671dfc47SDavid du Colombier }
394*671dfc47SDavid du Colombier 
395*671dfc47SDavid du Colombier Auth *
396*671dfc47SDavid du Colombier getauth(char *name, char *windom, char *keyp, int secmode, uchar *chal, int len)
397*671dfc47SDavid du Colombier {
398*671dfc47SDavid du Colombier 	int i;
399*671dfc47SDavid du Colombier 	Auth *ap;
400*671dfc47SDavid du Colombier 
401*671dfc47SDavid du Colombier 	if(name == nil){
402*671dfc47SDavid du Colombier 		name = DEF_AUTH;
403*671dfc47SDavid du Colombier 		if((secmode & SECMODE_PW_ENCRYPT) == 0)
404*671dfc47SDavid du Colombier 			sysfatal("plaintext authentication required, use '-a plain'");
405*671dfc47SDavid du Colombier 	}
406*671dfc47SDavid du Colombier 
407*671dfc47SDavid du Colombier 	ap = nil;
408*671dfc47SDavid du Colombier 	for(i = 0; i < nelem(methods); i++)
409*671dfc47SDavid du Colombier 		if(strcmp(methods[i].name, name) == 0){
410*671dfc47SDavid du Colombier 			ap = methods[i].func(windom, keyp, chal, len);
411*671dfc47SDavid du Colombier 			break;
412*671dfc47SDavid du Colombier 		}
413*671dfc47SDavid du Colombier 
414*671dfc47SDavid du Colombier 	if(! ap){
415*671dfc47SDavid du Colombier 		fprint(2, "%s: %s - unknown auth method\n", argv0, name);
416*671dfc47SDavid du Colombier 		autherr();		/* never returns */
417*671dfc47SDavid du Colombier 	}
418*671dfc47SDavid du Colombier 	return ap;
419*671dfc47SDavid du Colombier }
420*671dfc47SDavid du Colombier 
421*671dfc47SDavid du Colombier static int
422*671dfc47SDavid du Colombier genmac(uchar *buf, int len, int seq, uchar key[MACkeylen], uchar mine[MAClen])
423*671dfc47SDavid du Colombier {
424*671dfc47SDavid du Colombier 	DigestState *ds;
425*671dfc47SDavid du Colombier 	uchar *sig, digest[MD5dlen], their[MAClen];
426*671dfc47SDavid du Colombier 
427*671dfc47SDavid du Colombier 	sig = buf+MACoff;
428*671dfc47SDavid du Colombier 	memcpy(their, sig, MAClen);
429*671dfc47SDavid du Colombier 	memset(sig, 0, MAClen);
430*671dfc47SDavid du Colombier 	sig[0] = seq;
431*671dfc47SDavid du Colombier 	sig[1] = seq >> 8;
432*671dfc47SDavid du Colombier 	sig[2] = seq >> 16;
433*671dfc47SDavid du Colombier 	sig[3] = seq >> 24;
434*671dfc47SDavid du Colombier 
435*671dfc47SDavid du Colombier 	ds = md5(key, MACkeylen, nil, nil);
436*671dfc47SDavid du Colombier 	md5(buf, len, nil, ds);
437*671dfc47SDavid du Colombier 	md5(nil, 0, digest, ds);
438*671dfc47SDavid du Colombier 	memcpy(mine, digest, MAClen);
439*671dfc47SDavid du Colombier 
440*671dfc47SDavid du Colombier 	return memcmp(their, mine, MAClen);
441*671dfc47SDavid du Colombier }
442*671dfc47SDavid du Colombier 
443*671dfc47SDavid du Colombier int
444*671dfc47SDavid du Colombier macsign(Pkt *p)
445*671dfc47SDavid du Colombier {
446*671dfc47SDavid du Colombier 	int i, len;
447*671dfc47SDavid du Colombier 	uchar *sig, *buf, mac[MAClen], zeros[MACkeylen];
448*671dfc47SDavid du Colombier 
449*671dfc47SDavid du Colombier 	sig = p->buf + NBHDRLEN + MACoff;
450*671dfc47SDavid du Colombier 	buf = p->buf + NBHDRLEN;
451*671dfc47SDavid du Colombier 	len = (p->pos - p->buf) - NBHDRLEN;
452*671dfc47SDavid du Colombier 
453*671dfc47SDavid du Colombier 	for(i = -3; i < 4; i++){
454*671dfc47SDavid du Colombier 		memset(zeros, 0, sizeof(zeros));
455*671dfc47SDavid du Colombier 		if(genmac(buf, len, p->seq+i, zeros, mac) == 0){
456*671dfc47SDavid du Colombier 			dmp("got", 0, buf, len);
457*671dfc47SDavid du Colombier 			dmp("Zero OK", p->seq, mac, MAClen);
458*671dfc47SDavid du Colombier 			return 0;
459*671dfc47SDavid du Colombier 		}
460*671dfc47SDavid du Colombier 
461*671dfc47SDavid du Colombier 		if(genmac(buf, len, p->seq+i, p->s->auth->mackey[0], mac) == 0){
462*671dfc47SDavid du Colombier 			dmp("got", 0, buf, len);
463*671dfc47SDavid du Colombier 			dmp("LM-hash OK", p->seq, mac, MAClen);
464*671dfc47SDavid du Colombier 			return 0;
465*671dfc47SDavid du Colombier 		}
466*671dfc47SDavid du Colombier 
467*671dfc47SDavid du Colombier 		if(genmac(buf, len, p->seq+i, p->s->auth->mackey[1], mac) == 0){
468*671dfc47SDavid du Colombier 			dmp("got", 0, buf, len);
469*671dfc47SDavid du Colombier 			dmp("NT-hash OK", p->seq, mac, MAClen);
470*671dfc47SDavid du Colombier 			return 0;
471*671dfc47SDavid du Colombier 		}
472*671dfc47SDavid du Colombier 	}
473*671dfc47SDavid du Colombier 	genmac(buf, len, p->seq, p->s->auth->mackey[0], mac);
474*671dfc47SDavid du Colombier 
475*671dfc47SDavid du Colombier 	memcpy(sig, mac, MAClen);
476*671dfc47SDavid du Colombier 	return -1;
477*671dfc47SDavid du Colombier }
478