]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cifs/auth.c
stats: show amount of reclaimable pages (add -r flag)
[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 };
25
26 #ifdef DEBUG_MAC
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 #endif
43
44 static Auth *
45 auth_plain(char *windom, char *keyp, uchar *chal, int len)
46 {
47         UserPasswd *up;
48         static Auth *ap;
49
50         USED(chal, len);
51
52         up = auth_getuserpasswd(auth_getkey, "windom=%s proto=pass service=cifs %s",
53                 windom, keyp);
54         if(! up)
55                 sysfatal("cannot get key - %r");
56
57         ap = emalloc9p(sizeof(Auth));
58         memset(ap, 0, sizeof(ap));
59         ap->user = estrdup9p(up->user);
60         ap->windom = estrdup9p(windom);
61
62         ap->resp[0] = estrdup9p(up->passwd);
63         ap->len[0] = strlen(up->passwd);
64         memset(up->passwd, 0, strlen(up->passwd));
65         free(up);
66
67         return ap;
68 }
69
70 static Auth *
71 auth_proto(char *proto, char *windom, char *keyp, uchar *chal, int len)
72 {
73         MSchapreply *mcr;
74         uchar resp[4096];
75         int nresp;
76         char user[64];
77         Auth *ap;
78
79         mcr = (MSchapreply*)resp;
80         nresp = sizeof(resp);
81         if(strcmp(proto, "mschap") == 0)
82                 nresp = sizeof(*mcr);   /* backwards compatibility with old factotum */
83         nresp = auth_respond(chal, len, user, sizeof user, resp, nresp,
84                 auth_getkey, "proto=%s role=client service=cifs windom=%s %s",
85                 proto, windom, keyp);
86         if(nresp < 0)
87                 sysfatal("cannot get response - %r");
88         if(nresp < sizeof(*mcr))
89                 sysfatal("bad response size");
90
91         ap = emalloc9p(sizeof(Auth));
92         memset(ap, 0, sizeof(ap));
93         ap->user = estrdup9p(user);
94         ap->windom = estrdup9p(windom);
95
96         /* LM response */
97         ap->len[0] = sizeof(mcr->LMresp);
98         ap->resp[0] = emalloc9p(ap->len[0]);
99         memcpy(ap->resp[0], mcr->LMresp, ap->len[0]);
100
101         /* NT response */
102         ap->len[1] = nresp+sizeof(mcr->NTresp)-sizeof(*mcr);
103         ap->resp[1] = emalloc9p(ap->len[1]);
104         memcpy(ap->resp[1], mcr->NTresp, ap->len[1]);
105
106         return ap;
107 }
108
109 static Auth *
110 auth_lm_and_ntlm(char *windom, char *keyp, uchar *chal, int len)
111 {
112         return auth_proto("mschap", windom, keyp, chal, len);
113 }
114
115 /*
116  * NTLM response only, the LM response is a just
117  * copy of the NTLM one. we do this because the lm
118  * response is easily reversed - Google for l0pht
119  * for more info.
120  */
121 static Auth *
122 auth_ntlm(char *windom, char *keyp, uchar *chal, int len)
123 {
124         Auth *ap;
125
126         if((ap = auth_lm_and_ntlm(windom, keyp, chal, len)) == nil)
127                 return nil;
128
129         free(ap->resp[0]);
130         ap->len[0] = ap->len[1];
131         ap->resp[0] = emalloc9p(ap->len[0]);
132         memcpy(ap->resp[0], ap->resp[1], ap->len[0]);
133         return ap;
134 }
135
136 static Auth *
137 auth_ntlmv2(char *windom, char *keyp, uchar *chal, int len)
138 {
139         return auth_proto("mschap2", windom, keyp, chal, len);
140 }
141
142 struct {
143         char    *name;
144         Auth    *(*func)(char *, char *, uchar *, int);
145 } methods[] = {
146         { "plain",      auth_plain },
147         { "lm+ntlm",    auth_lm_and_ntlm },
148         { "ntlm",       auth_ntlm },
149         { "ntlmv2",     auth_ntlmv2 },
150 //      { "kerberos",   auth_kerberos },
151 };
152
153 void
154 autherr(void)
155 {
156         int i;
157
158         fprint(2, "supported auth methods:\t");
159         for(i = 0; i < nelem(methods); i++)
160                 fprint(2, "%s ", methods[i].name);
161         fprint(2, "\n");
162         exits("usage");
163 }
164
165 Auth *
166 getauth(char *name, char *windom, char *keyp, int secmode, uchar *chal, int len)
167 {
168         int i;
169         Auth *ap;
170
171         if(name == nil){
172                 name = DEF_AUTH;
173                 if((secmode & SECMODE_PW_ENCRYPT) == 0)
174                         sysfatal("plaintext authentication required, use '-a plain'");
175         }
176
177         ap = nil;
178         for(i = 0; i < nelem(methods); i++)
179                 if(strcmp(methods[i].name, name) == 0){
180                         ap = methods[i].func(windom, keyp, chal, len);
181                         break;
182                 }
183
184         if(! ap){
185                 fprint(2, "%s: %s - unknown auth method\n", argv0, name);
186                 autherr();      /* never returns */
187         }
188         return ap;
189 }
190
191 static int
192 genmac(uchar *buf, int len, int seq, uchar key[MACkeylen], uchar ours[MAClen])
193 {
194         DigestState *ds;
195         uchar *sig, digest[MD5dlen], theirs[MAClen];
196
197         sig = buf+MACoff;
198         memcpy(theirs, sig, MAClen);
199
200         memset(sig, 0, MAClen);
201         sig[0] = seq;
202         sig[1] = seq >> 8;
203         sig[2] = seq >> 16;
204         sig[3] = seq >> 24;
205
206         ds = md5(key, MACkeylen, nil, nil);
207         md5(buf, len, digest, ds);
208         memcpy(ours, digest, MAClen);
209
210         return memcmp(theirs, ours, MAClen);
211 }
212
213 int
214 macsign(Pkt *p, int seq)
215 {
216         int rc, len;
217         uchar *sig, *buf, mac[MAClen];
218
219         sig = p->buf + NBHDRLEN + MACoff;
220         buf = p->buf + NBHDRLEN;
221         len = (p->pos - p->buf) - NBHDRLEN;
222
223 #ifdef DEBUG_MAC
224         if(seq & 1)
225                 dmp("rx", seq, sig, MAClen);
226 #endif
227         rc = 0;
228         if(! p->s->seqrun)
229                 memcpy(mac, "BSRSPYL ", 8);     /* no idea, ask MS */
230         else
231                 rc = genmac(buf, len, seq, p->s->auth->mackey[0], mac);
232 #ifdef DEBUG_MAC
233         if(!(seq & 1))
234                 dmp("tx", seq, mac, MAClen);
235 #endif
236         memcpy(sig, mac, MAClen);
237         return rc;
238 }