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