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 DEF_AUTH "ntlmv2"
19*671dfc47SDavid du Colombier
20*671dfc47SDavid du Colombier static enum {
21*671dfc47SDavid du Colombier MACkeylen = 40, /* MAC key len */
22*671dfc47SDavid du Colombier MAClen = 8, /* signature length */
23*671dfc47SDavid du Colombier MACoff = 14, /* sign. offset from start of SMB (not netbios) pkt */
24*671dfc47SDavid du Colombier Bliplen = 8, /* size of LMv2 client nonce */
25*671dfc47SDavid du Colombier };
26*671dfc47SDavid du Colombier
27*671dfc47SDavid du Colombier static void
dmp(char * s,int seq,void * buf,int n)28*671dfc47SDavid du Colombier dmp(char *s, int seq, void *buf, int n)
29*671dfc47SDavid du Colombier {
30*671dfc47SDavid du Colombier int i;
31*671dfc47SDavid du Colombier char *p = buf;
32*671dfc47SDavid du Colombier
33*671dfc47SDavid du Colombier print("%s %3d ", s, seq);
34*671dfc47SDavid du Colombier while(n > 0){
35*671dfc47SDavid du Colombier for(i = 0; i < 16 && n > 0; i++, n--)
36*671dfc47SDavid du Colombier print("%02x ", *p++ & 0xff);
37*671dfc47SDavid du Colombier if(n > 0)
38*671dfc47SDavid du Colombier print("\n");
39*671dfc47SDavid du Colombier }
40*671dfc47SDavid du Colombier print("\n");
41*671dfc47SDavid du Colombier }
42*671dfc47SDavid du Colombier
43*671dfc47SDavid du Colombier static Auth *
auth_plain(char * windom,char * keyp,uchar * chal,int len)44*671dfc47SDavid du Colombier auth_plain(char *windom, char *keyp, uchar *chal, int len)
45*671dfc47SDavid du Colombier {
46*671dfc47SDavid du Colombier UserPasswd *up;
47*671dfc47SDavid du Colombier static Auth *ap;
48*671dfc47SDavid du Colombier
49*671dfc47SDavid du Colombier USED(chal, len);
50*671dfc47SDavid du Colombier
51*671dfc47SDavid du Colombier up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs %s",
52*671dfc47SDavid du Colombier windom, keyp);
53*671dfc47SDavid du Colombier if(! up)
54*671dfc47SDavid du Colombier sysfatal("cannot get key - %r");
55*671dfc47SDavid du Colombier
56*671dfc47SDavid du Colombier ap = emalloc9p(sizeof(Auth));
57*671dfc47SDavid du Colombier memset(ap, 0, sizeof(ap));
58*671dfc47SDavid du Colombier ap->user = estrdup9p(up->user);
59*671dfc47SDavid du Colombier ap->windom = estrdup9p(windom);
60*671dfc47SDavid du Colombier
61*671dfc47SDavid du Colombier ap->resp[0] = estrdup9p(up->passwd);
62*671dfc47SDavid du Colombier ap->len[0] = strlen(up->passwd);
63*671dfc47SDavid du Colombier memset(up->passwd, 0, strlen(up->passwd));
64*671dfc47SDavid du Colombier free(up);
65*671dfc47SDavid du Colombier
66*671dfc47SDavid du Colombier return ap;
67*671dfc47SDavid du Colombier }
68*671dfc47SDavid du Colombier
69*671dfc47SDavid du Colombier static Auth *
auth_lm_and_ntlm(char * windom,char * keyp,uchar * chal,int len)70*671dfc47SDavid du Colombier auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
71*671dfc47SDavid du Colombier {
72*671dfc47SDavid du Colombier int err;
73*671dfc47SDavid du Colombier char user[64];
74*671dfc47SDavid du Colombier Auth *ap;
75*671dfc47SDavid du Colombier MSchapreply mcr;
76*671dfc47SDavid du Colombier
77*671dfc47SDavid du Colombier err = auth_respond(chal, len, user, sizeof user, &mcr, sizeof mcr,
78*671dfc47SDavid du Colombier auth_getkey, "windom=%s proto=mschap role=client service=cifs %s",
79*671dfc47SDavid du Colombier windom, keyp);
80*671dfc47SDavid du Colombier if(err == -1)
81*671dfc47SDavid du Colombier sysfatal("cannot get key - %r");
82*671dfc47SDavid du Colombier
83*671dfc47SDavid du Colombier ap = emalloc9p(sizeof(Auth));
84*671dfc47SDavid du Colombier memset(ap, 0, sizeof(ap));
85*671dfc47SDavid du Colombier ap->user = estrdup9p(user);
86*671dfc47SDavid du Colombier ap->windom = estrdup9p(windom);
87*671dfc47SDavid du Colombier
88*671dfc47SDavid du Colombier /* LM response */
89*671dfc47SDavid du Colombier ap->len[0] = sizeof(mcr.LMresp);
90*671dfc47SDavid du Colombier ap->resp[0] = emalloc9p(ap->len[0]);
91*671dfc47SDavid du Colombier memcpy(ap->resp[0], mcr.LMresp, ap->len[0]);
92*671dfc47SDavid du Colombier
93*671dfc47SDavid du Colombier /* NTLM response */
94*671dfc47SDavid du Colombier ap->len[1] = sizeof(mcr.NTresp);
95*671dfc47SDavid du Colombier ap->resp[1] = emalloc9p(ap->len[1]);
96*671dfc47SDavid du Colombier memcpy(ap->resp[1], mcr.NTresp, ap->len[1]);
97*671dfc47SDavid du Colombier
98*671dfc47SDavid du Colombier return ap;
99*671dfc47SDavid du Colombier }
100*671dfc47SDavid du Colombier
101*671dfc47SDavid du Colombier /*
102*671dfc47SDavid du Colombier * NTLM response only, the LM response is a just
103*671dfc47SDavid du Colombier * copy of the NTLM one. we do this because the lm
104*671dfc47SDavid du Colombier * response is easily reversed - Google for l0pht
105*671dfc47SDavid du Colombier * 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 nttime = time(nil); /* nt time now */
166*671dfc47SDavid du Colombier nttime += 11644473600LL;
167*671dfc47SDavid du Colombier nttime *= 10000000LL;
168*671dfc47SDavid du Colombier *p++ = nttime;
169*671dfc47SDavid du Colombier *p++ = nttime >> 8;
170*671dfc47SDavid du Colombier *p++ = nttime >> 16;
171*671dfc47SDavid du Colombier *p++ = nttime >> 24;
172*671dfc47SDavid du Colombier *p++ = nttime >> 32;
173*671dfc47SDavid du Colombier *p++ = nttime >> 40;
174*671dfc47SDavid du Colombier *p++ = nttime >> 48;
175*671dfc47SDavid du Colombier *p++ = nttime >> 56;
176*671dfc47SDavid du Colombier
177*671dfc47SDavid du Colombier genrandom(p, 8);
178*671dfc47SDavid du Colombier p += 8; /* client nonce */
179*671dfc47SDavid du Colombier *p++ = 0x6f;
180*671dfc47SDavid du Colombier *p++ = 0;
181*671dfc47SDavid du Colombier *p++ = 0x6e;
182*671dfc47SDavid du Colombier *p++ = 0; /* unknown data */
183*671dfc47SDavid du Colombier
184*671dfc47SDavid du Colombier *p++ = Bdomain;
185*671dfc47SDavid du Colombier *p++ = 0; /* name type */
186*671dfc47SDavid du Colombier
187*671dfc47SDavid du Colombier n = utflen(windom) * 2;
188*671dfc47SDavid du Colombier *p++ = n;
189*671dfc47SDavid du Colombier *p++ = n >> 8; /* name length */
190*671dfc47SDavid du Colombier
191*671dfc47SDavid du Colombier d = windom;
192*671dfc47SDavid du Colombier while(*d && p-blob < (len-8)){
193*671dfc47SDavid du Colombier d += chartorune(&r, d);
194*671dfc47SDavid du Colombier r = toupperrune(r);
195*671dfc47SDavid du Colombier *p++ = r;
196*671dfc47SDavid du Colombier *p++ = r >> 8;
197*671dfc47SDavid du Colombier }
198*671dfc47SDavid du Colombier
199*671dfc47SDavid du Colombier *p++ = 0;
200*671dfc47SDavid du Colombier *p++ = Beof; /* name type */
201*671dfc47SDavid du Colombier
202*671dfc47SDavid du Colombier *p++ = 0;
203*671dfc47SDavid du Colombier *p++ = 0; /* name length */
204*671dfc47SDavid du Colombier
205*671dfc47SDavid du Colombier *p++ = 0x65;
206*671dfc47SDavid du Colombier *p++ = 0;
207*671dfc47SDavid du Colombier *p++ = 0;
208*671dfc47SDavid du Colombier *p++ = 0; /* unknown data */
209*671dfc47SDavid du Colombier return p - blob;
210*671dfc47SDavid du Colombier }
211*671dfc47SDavid du Colombier
212*671dfc47SDavid du Colombier static Auth *
auth_ntlmv2(char * windom,char * keyp,uchar * chal,int len)213*671dfc47SDavid du Colombier auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len)
214*671dfc47SDavid du Colombier {
215*671dfc47SDavid du Colombier int i, n;
216*671dfc47SDavid du Colombier Rune r;
217*671dfc47SDavid du Colombier char *p, *u;
218*671dfc47SDavid du Colombier uchar v1hash[MD5dlen], blip[Bliplen], blob[1024], v2hash[MD5dlen];
219*671dfc47SDavid du Colombier uchar c, lm_hmac[MD5dlen], nt_hmac[MD5dlen], nt_sesskey[MD5dlen],
220*671dfc47SDavid du Colombier lm_sesskey[MD5dlen];
221*671dfc47SDavid du Colombier DigestState *ds;
222*671dfc47SDavid du Colombier UserPasswd *up;
223*671dfc47SDavid du Colombier static Auth *ap;
224*671dfc47SDavid du Colombier
225*671dfc47SDavid du Colombier up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs-ntlmv2 %s",
226*671dfc47SDavid du Colombier windom, keyp);
227*671dfc47SDavid du Colombier if(!up)
228*671dfc47SDavid du Colombier sysfatal("cannot get key - %r");
229*671dfc47SDavid du Colombier
230*671dfc47SDavid du Colombier ap = emalloc9p(sizeof(Auth));
231*671dfc47SDavid du Colombier memset(ap, 0, sizeof(ap));
232*671dfc47SDavid du Colombier
233*671dfc47SDavid du Colombier /* Standard says unlimited length, experience says 128 max */
234*671dfc47SDavid du Colombier if((n = strlen(up->passwd)) > 128)
235*671dfc47SDavid du Colombier n = 128;
236*671dfc47SDavid du Colombier
237*671dfc47SDavid du Colombier ds = md4(nil, 0, nil, nil);
238*671dfc47SDavid du Colombier for(i=0, p=up->passwd; i < n; i++) {
239*671dfc47SDavid du Colombier p += chartorune(&r, p);
240*671dfc47SDavid du Colombier c = r;
241*671dfc47SDavid du Colombier md4(&c, 1, nil, ds);
242*671dfc47SDavid du Colombier c = r >> 8;
243*671dfc47SDavid du Colombier md4(&c, 1, nil, ds);
244*671dfc47SDavid du Colombier }
245*671dfc47SDavid du Colombier md4(nil, 0, v1hash, ds);
246*671dfc47SDavid du Colombier
247*671dfc47SDavid du Colombier /*
248*671dfc47SDavid du Colombier * Some documentation insists that the username must be forced to
249*671dfc47SDavid du Colombier * uppercase, but the domain name should not be. Other shows both
250*671dfc47SDavid du Colombier * being forced to uppercase. I am pretty sure this is irrevevant as the
251*671dfc47SDavid du Colombier * domain name passed from the remote server always seems to be in
252*671dfc47SDavid du Colombier * uppercase already.
253*671dfc47SDavid du Colombier */
254*671dfc47SDavid du Colombier ds = hmac_t64(nil, 0, v1hash, MD5dlen, nil, nil);
255*671dfc47SDavid du Colombier u = up->user;
256*671dfc47SDavid du Colombier while(*u){
257*671dfc47SDavid du Colombier u += chartorune(&r, u);
258*671dfc47SDavid du Colombier r = toupperrune(r);
259*671dfc47SDavid du Colombier c = r;
260*671dfc47SDavid du Colombier hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
261*671dfc47SDavid du Colombier c = r >> 8;
262*671dfc47SDavid du Colombier hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
263*671dfc47SDavid du Colombier }
264*671dfc47SDavid du Colombier u = windom;
265*671dfc47SDavid du Colombier
266*671dfc47SDavid du Colombier while(*u){
267*671dfc47SDavid du Colombier u += chartorune(&r, u);
268*671dfc47SDavid du Colombier c = r;
269*671dfc47SDavid du Colombier hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
270*671dfc47SDavid du Colombier c = r >> 8;
271*671dfc47SDavid du Colombier hmac_t64(&c, 1, v1hash, MD5dlen, nil, ds);
272*671dfc47SDavid du Colombier }
273*671dfc47SDavid du Colombier hmac_t64(nil, 0, v1hash, MD5dlen, v2hash, ds);
274*671dfc47SDavid du Colombier ap->user = estrdup9p(up->user);
275*671dfc47SDavid du Colombier ap->windom = estrdup9p(windom);
276*671dfc47SDavid du Colombier
277*671dfc47SDavid du Colombier /* LM v2 */
278*671dfc47SDavid du Colombier
279*671dfc47SDavid du Colombier genrandom(blip, Bliplen);
280*671dfc47SDavid du Colombier ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
281*671dfc47SDavid du Colombier hmac_t64(blip, Bliplen, v2hash, MD5dlen, lm_hmac, ds);
282*671dfc47SDavid du Colombier ap->len[0] = MD5dlen+Bliplen;
283*671dfc47SDavid du Colombier ap->resp[0] = emalloc9p(ap->len[0]);
284*671dfc47SDavid du Colombier memcpy(ap->resp[0], lm_hmac, MD5dlen);
285*671dfc47SDavid du Colombier memcpy(ap->resp[0]+MD5dlen, blip, Bliplen);
286*671dfc47SDavid du Colombier
287*671dfc47SDavid du Colombier /* LM v2 session key */
288*671dfc47SDavid du Colombier hmac_t64(lm_hmac, MD5dlen, v2hash, MD5dlen, lm_sesskey, nil);
289*671dfc47SDavid du Colombier
290*671dfc47SDavid du Colombier /* LM v2 MAC key */
291*671dfc47SDavid du Colombier ap->mackey[0] = emalloc9p(MACkeylen);
292*671dfc47SDavid du Colombier memcpy(ap->mackey[0], lm_sesskey, MD5dlen);
293*671dfc47SDavid du Colombier memcpy(ap->mackey[0]+MD5dlen, ap->resp[0], MACkeylen-MD5dlen);
294*671dfc47SDavid du Colombier
295*671dfc47SDavid du Colombier /* NTLM v2 */
296*671dfc47SDavid du Colombier n = ntv2_blob(blob, sizeof(blob), windom);
297*671dfc47SDavid du Colombier ds = hmac_t64(chal, len, v2hash, MD5dlen, nil, nil);
298*671dfc47SDavid du Colombier hmac_t64(blob, n, v2hash, MD5dlen, nt_hmac, ds);
299*671dfc47SDavid du Colombier ap->len[1] = MD5dlen+n;
300*671dfc47SDavid du Colombier ap->resp[1] = emalloc9p(ap->len[1]);
301*671dfc47SDavid du Colombier memcpy(ap->resp[1], nt_hmac, MD5dlen);
302*671dfc47SDavid du Colombier memcpy(ap->resp[1]+MD5dlen, blob, n);
303*671dfc47SDavid du Colombier
304*671dfc47SDavid du Colombier /*
305*671dfc47SDavid du Colombier * v2hash definitely OK by
306*671dfc47SDavid du Colombier * the time we get here.
307*671dfc47SDavid du Colombier */
308*671dfc47SDavid du Colombier /* NTLM v2 session key */
309*671dfc47SDavid du Colombier hmac_t64(nt_hmac, MD5dlen, v2hash, MD5dlen, nt_sesskey, nil);
310*671dfc47SDavid du Colombier
311*671dfc47SDavid du Colombier /* NTLM v2 MAC key */
312*671dfc47SDavid du Colombier ap->mackey[1] = emalloc9p(MACkeylen);
313*671dfc47SDavid du Colombier memcpy(ap->mackey[1], nt_sesskey, MD5dlen);
314*671dfc47SDavid du Colombier memcpy(ap->mackey[1]+MD5dlen, ap->resp[1], MACkeylen-MD5dlen);
315*671dfc47SDavid du Colombier free(up);
316*671dfc47SDavid du Colombier
317*671dfc47SDavid du Colombier return ap;
318*671dfc47SDavid du Colombier }
319*671dfc47SDavid du Colombier
320*671dfc47SDavid du Colombier struct {
321*671dfc47SDavid du Colombier char *name;
322*671dfc47SDavid du Colombier Auth *(*func)(char *, char *, uchar *, int);
323*671dfc47SDavid du Colombier } methods[] = {
324*671dfc47SDavid du Colombier { "plain", auth_plain },
325*671dfc47SDavid du Colombier { "lm+ntlm", auth_lm_and_ntlm },
326*671dfc47SDavid du Colombier { "ntlm", auth_ntlm },
327*671dfc47SDavid du Colombier { "ntlmv2", auth_ntlmv2 },
328*671dfc47SDavid du Colombier // { "kerberos", auth_kerberos },
329*671dfc47SDavid du Colombier };
330*671dfc47SDavid du Colombier
331*671dfc47SDavid du Colombier void
autherr(void)332*671dfc47SDavid du Colombier autherr(void)
333*671dfc47SDavid du Colombier {
334*671dfc47SDavid du Colombier int i;
335*671dfc47SDavid du Colombier
336*671dfc47SDavid du Colombier fprint(2, "supported auth methods:\t");
337*671dfc47SDavid du Colombier for(i = 0; i < nelem(methods); i++)
338*671dfc47SDavid du Colombier fprint(2, "%s ", methods[i].name);
339*671dfc47SDavid du Colombier fprint(2, "\n");
340*671dfc47SDavid du Colombier exits("usage");
341*671dfc47SDavid du Colombier }
342*671dfc47SDavid du Colombier
343*671dfc47SDavid du Colombier Auth *
getauth(char * name,char * windom,char * keyp,int secmode,uchar * chal,int len)344*671dfc47SDavid du Colombier getauth(char *name, char *windom, char *keyp, int secmode, uchar *chal, int len)
345*671dfc47SDavid du Colombier {
346*671dfc47SDavid du Colombier int i;
347*671dfc47SDavid du Colombier Auth *ap;
348*671dfc47SDavid du Colombier
349*671dfc47SDavid du Colombier if(name == nil){
350*671dfc47SDavid du Colombier name = DEF_AUTH;
351*671dfc47SDavid du Colombier if((secmode & SECMODE_PW_ENCRYPT) == 0)
352*671dfc47SDavid du Colombier sysfatal("plaintext authentication required, use '-a plain'");
353*671dfc47SDavid du Colombier }
354*671dfc47SDavid du Colombier
355*671dfc47SDavid du Colombier ap = nil;
356*671dfc47SDavid du Colombier for(i = 0; i < nelem(methods); i++)
357*671dfc47SDavid du Colombier if(strcmp(methods[i].name, name) == 0){
358*671dfc47SDavid du Colombier ap = methods[i].func(windom, keyp, chal, len);
359*671dfc47SDavid du Colombier break;
360*671dfc47SDavid du Colombier }
361*671dfc47SDavid du Colombier
362*671dfc47SDavid du Colombier if(! ap){
363*671dfc47SDavid du Colombier fprint(2, "%s: %s - unknown auth method\n", argv0, name);
364*671dfc47SDavid du Colombier autherr(); /* never returns */
365*671dfc47SDavid du Colombier }
366*671dfc47SDavid du Colombier return ap;
367*671dfc47SDavid du Colombier }
368*671dfc47SDavid du Colombier
369*671dfc47SDavid du Colombier static int
genmac(uchar * buf,int len,int seq,uchar key[MACkeylen],uchar ours[MAClen])370*671dfc47SDavid du Colombier genmac(uchar *buf, int len, int seq, uchar key[MACkeylen], uchar ours[MAClen])
371*671dfc47SDavid du Colombier {
372*671dfc47SDavid du Colombier DigestState *ds;
373*671dfc47SDavid du Colombier uchar *sig, digest[MD5dlen], theirs[MAClen];
374*671dfc47SDavid du Colombier
375*671dfc47SDavid du Colombier sig = buf+MACoff;
376*671dfc47SDavid du Colombier memcpy(theirs, sig, MAClen);
377*671dfc47SDavid du Colombier
378*671dfc47SDavid du Colombier memset(sig, 0, MAClen);
379*671dfc47SDavid du Colombier sig[0] = seq;
380*671dfc47SDavid du Colombier sig[1] = seq >> 8;
381*671dfc47SDavid du Colombier sig[2] = seq >> 16;
382*671dfc47SDavid du Colombier sig[3] = seq >> 24;
383*671dfc47SDavid du Colombier
384*671dfc47SDavid du Colombier ds = md5(key, MACkeylen, nil, nil);
385*671dfc47SDavid du Colombier md5(buf, len, digest, ds);
386*671dfc47SDavid du Colombier memcpy(ours, digest, MAClen);
387*671dfc47SDavid du Colombier
388*671dfc47SDavid du Colombier return memcmp(theirs, ours, MAClen);
389*671dfc47SDavid du Colombier }
390*671dfc47SDavid du Colombier
391*671dfc47SDavid du Colombier int
macsign(Pkt * p,int seq)392*671dfc47SDavid du Colombier macsign(Pkt *p, int seq)
393*671dfc47SDavid du Colombier {
394*671dfc47SDavid du Colombier int rc, len;
395*671dfc47SDavid du Colombier uchar *sig, *buf, mac[MAClen];
396*671dfc47SDavid du Colombier
397*671dfc47SDavid du Colombier sig = p->buf + NBHDRLEN + MACoff;
398*671dfc47SDavid du Colombier buf = p->buf + NBHDRLEN;
399*671dfc47SDavid du Colombier len = (p->pos - p->buf) - NBHDRLEN;
400*671dfc47SDavid du Colombier
401*671dfc47SDavid du Colombier #ifdef DEBUG_MAC
402*671dfc47SDavid du Colombier if(seq & 1)
403*671dfc47SDavid du Colombier dmp("rx", seq, sig, MAClen);
404*671dfc47SDavid du Colombier #endif
405*671dfc47SDavid du Colombier rc = 0;
406*671dfc47SDavid du Colombier if(! p->s->seqrun)
407*671dfc47SDavid du Colombier memcpy(mac, "BSRSPYL ", 8); /* no idea, ask MS */
408*671dfc47SDavid du Colombier else
409*671dfc47SDavid du Colombier rc = genmac(buf, len, seq, p->s->auth->mackey[0], mac);
410*671dfc47SDavid du Colombier #ifdef DEBUG_MAC
411*671dfc47SDavid du Colombier if(!(seq & 1))
412*671dfc47SDavid du Colombier dmp("tx", seq, mac, MAClen);
413*671dfc47SDavid du Colombier #endif
414*671dfc47SDavid du Colombier memcpy(sig, mac, MAClen);
415*671dfc47SDavid du Colombier return rc;
416*671dfc47SDavid du Colombier }
417