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