xref: /plan9/sys/src/cmd/cwfs/auth.c (revision 223a035810d484657ee1a815f68faa8211009d6d)
1 #include "all.h"
2 #include "io.h"
3 #include <authsrv.h>
4 
5 Nvrsafe	nvr;
6 
7 static int gotnvr;	/* flag: nvr contains nvram; it could be bad */
8 
9 char*
nvrgetconfig(void)10 nvrgetconfig(void)
11 {
12 	return conf.confdev;
13 }
14 
15 /*
16  * we shouldn't be writing nvram any more.
17  * the secstore/config field is now just secstore key.
18  * we still use authid, authdom and machkey for authentication.
19  */
20 
21 int
nvrcheck(void)22 nvrcheck(void)
23 {
24 	uchar csum;
25 
26 	if (readnvram(&nvr, NVread) < 0) {
27 		print("nvrcheck: can't read nvram\n");
28 		return 1;
29 	} else
30 		gotnvr = 1;
31 	print("nvr read\n");
32 
33 	csum = nvcsum(nvr.machkey, sizeof nvr.machkey);
34 	if(csum != nvr.machsum) {
35 		print("\n\n ** NVR key checksum is incorrect  **\n");
36 		print(" ** set password to allow attaches **\n\n");
37 		memset(nvr.machkey, 0, sizeof nvr.machkey);
38 		return 1;
39 	}
40 
41 	return 0;
42 }
43 
44 int
nvrsetconfig(char * word)45 nvrsetconfig(char* word)
46 {
47 	/* config block is on device `word' */
48 	USED(word);
49 	return 0;
50 }
51 
52 int
conslock(void)53 conslock(void)
54 {
55 	char *ln;
56 	char nkey1[DESKEYLEN];
57 	static char zeroes[DESKEYLEN];
58 
59 	if(memcmp(nvr.machkey, zeroes, DESKEYLEN) == 0) {
60 		print("no password set\n");
61 		return 0;
62 	}
63 
64 	for(;;) {
65 		print("%s password:", service);
66 		/* could turn off echo here */
67 
68 		if ((ln = Brdline(&bin, '\n')) == nil)
69 			return 0;
70 		ln[Blinelen(&bin)-1] = '\0';
71 
72 		/* could turn on echo here */
73 		memset(nkey1, 0, DESKEYLEN);
74 		passtokey(nkey1, ln);
75 		if(memcmp(nkey1, nvr.machkey, DESKEYLEN) == 0) {
76 			prdate();
77 			break;
78 		}
79 
80 		print("Bad password\n");
81 		delay(1000);
82 	}
83 	return 1;
84 }
85 
86 /*
87  *  authentication specific to 9P2000
88  */
89 
90 /* authentication states */
91 enum
92 {
93 	HaveProtos=1,
94 	NeedProto,
95 	HaveOK,
96 	NeedCchal,
97 	HaveSinfo,
98 	NeedTicket,
99 	HaveSauthenticator,
100 	SSuccess,
101 };
102 
103 char *phasename[] =
104 {
105 [HaveProtos]	"HaveProtos",
106 [NeedProto]	"NeedProto",
107 [HaveOK]	"HaveOK",
108 [NeedCchal]	"NeedCchal",
109 [HaveSinfo]	"HaveSinfo",
110 [NeedTicket]	"NeedTicket",
111 [HaveSauthenticator]	"HaveSauthenticator",
112 [SSuccess]	"SSuccess",
113 };
114 
115 /* authentication structure */
116 struct	Auth
117 {
118 	int	inuse;
119 	char	uname[NAMELEN];	/* requestor's remote user name */
120 	char	aname[NAMELEN];	/* requested aname */
121 	Userid	uid;		/* uid decided on */
122 	int	phase;
123 	char	cchal[CHALLEN];
124 	char	tbuf[TICKETLEN+AUTHENTLEN];	/* server ticket */
125 	Ticket	t;
126 	Ticketreq tr;
127 };
128 
129 Auth*	auths;
130 Lock	authlock;
131 
132 void
authinit(void)133 authinit(void)
134 {
135 	auths = malloc(conf.nauth * sizeof(*auths));
136 }
137 
138 static int
failure(Auth * s,char * why)139 failure(Auth *s, char *why)
140 {
141 	int i;
142 
143 if(*why)print("authentication failed: %s: %s\n", phasename[s->phase], why);
144 	srand((uintptr)s + time(nil));
145 	for(i = 0; i < CHALLEN; i++)
146 		s->tr.chal[i] = nrand(256);
147 	s->uid = -1;
148 	strncpy(s->tr.authid, nvr.authid, NAMELEN);
149 	strncpy(s->tr.authdom, nvr.authdom, DOMLEN);
150 	memmove(s->cchal, s->tr.chal, sizeof(s->cchal));
151 	s->phase = HaveProtos;
152 	return -1;
153 }
154 
155 Auth*
authnew(char * uname,char * aname)156 authnew(char *uname, char *aname)
157 {
158 	static int si = 0;
159 	int i, nwrap;
160 	Auth *s;
161 
162 	i = si;
163 	nwrap = 0;
164 	for(;;){
165 		if(i < 0 || i >= conf.nauth){
166 			if(++nwrap > 1)
167 				return nil;
168 			i = 0;
169 		}
170 		s = &auths[i++];
171 		if(s->inuse)
172 			continue;
173 		lock(&authlock);
174 		if(s->inuse == 0){
175 			s->inuse = 1;
176 			strncpy(s->uname, uname, NAMELEN-1);
177 			strncpy(s->aname, aname, NAMELEN-1);
178 			failure(s, "");
179 			si = i;
180 			unlock(&authlock);
181 			break;
182 		}
183 		unlock(&authlock);
184 	}
185 	return s;
186 }
187 
188 void
authfree(Auth * s)189 authfree(Auth *s)
190 {
191 	if(s != nil)
192 		s->inuse = 0;
193 }
194 
195 int
authread(File * file,uchar * data,int n)196 authread(File* file, uchar* data, int n)
197 {
198 	Auth *s;
199 	int m;
200 
201 	s = file->auth;
202 	if(s == nil)
203 		return -1;
204 
205 	switch(s->phase){
206 	default:
207 		return failure(s, "unexpected phase");
208 	case HaveProtos:
209 		m = snprint((char*)data, n, "v.2 p9sk1@%s", nvr.authdom) + 1;
210 		s->phase = NeedProto;
211 		break;
212 	case HaveOK:
213 		m = 3;
214 		if(n < m)
215 			return failure(s, "read too short");
216 		strcpy((char*)data, "OK");
217 		s->phase = NeedCchal;
218 		break;
219 	case HaveSinfo:
220 		m = TICKREQLEN;
221 		if(n < m)
222 			return failure(s, "read too short");
223 		convTR2M(&s->tr, (char*)data);
224 		s->phase = NeedTicket;
225 		break;
226 	case HaveSauthenticator:
227 		m = AUTHENTLEN;
228 		if(n < m)
229 			return failure(s, "read too short");
230 		memmove(data, s->tbuf+TICKETLEN, m);
231 		s->phase = SSuccess;
232 		break;
233 	}
234 	return m;
235 }
236 
237 int
authwrite(File * file,uchar * data,int n)238 authwrite(File* file, uchar *data, int n)
239 {
240 	Auth *s;
241 	int m;
242 	char *p, *d;
243 	Authenticator a;
244 
245 	s = file->auth;
246 	if(s == nil)
247 		return -1;
248 
249 	switch(s->phase){
250 	default:
251 		return failure(s, "unknown phase");
252 	case NeedProto:
253 		p = (char*)data;
254 		if(p[n-1] != 0)
255 			return failure(s, "proto missing terminator");
256 		d = strchr(p, ' ');
257 		if(d == nil)
258 			return failure(s, "proto missing separator");
259 		*d++ = 0;
260 		if(strcmp(p, "p9sk1") != 0)
261 			return failure(s, "unknown proto");
262 		if(strcmp(d, nvr.authdom) != 0)
263 			return failure(s, "unknown domain");
264 		s->phase = HaveOK;
265 		m = n;
266 		break;
267 	case NeedCchal:
268 		m = CHALLEN;
269 		if(n < m)
270 			return failure(s, "client challenge too short");
271 		memmove(s->cchal, data, sizeof(s->cchal));
272 		s->phase = HaveSinfo;
273 		break;
274 	case NeedTicket:
275 		m = TICKETLEN+AUTHENTLEN;
276 		if(n < m)
277 			return failure(s, "ticket+auth too short");
278 
279 		convM2T((char*)data, &s->t, nvr.machkey);
280 		if(s->t.num != AuthTs
281 		|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0)
282 			return failure(s, "bad ticket");
283 
284 		convM2A((char*)data+TICKETLEN, &a, s->t.key);
285 		if(a.num != AuthAc
286 		|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
287 		|| a.id != 0)
288 			return failure(s, "bad authenticator");
289 
290 		/* at this point, we're convinced */
291 		s->uid = strtouid(s->t.suid);
292 		if(s->uid < 0)
293 			return failure(s, "unknown user");
294 		if(cons.flags & authdebugflag)
295 			print("user %s = %d authenticated\n",
296 				s->t.suid, s->uid);
297 
298 		/* create an authenticator to send back */
299 		a.num = AuthAs;
300 		memmove(a.chal, s->cchal, sizeof(a.chal));
301 		a.id = 0;
302 		convA2M(&a, s->tbuf+TICKETLEN, s->t.key);
303 
304 		s->phase = HaveSauthenticator;
305 		break;
306 	}
307 	return m;
308 }
309 
310 int
authuid(Auth * s)311 authuid(Auth* s)
312 {
313 	return s->uid;
314 }
315 
316 char*
authaname(Auth * s)317 authaname(Auth* s)
318 {
319 	return s->aname;
320 }
321 
322 char*
authuname(Auth * s)323 authuname(Auth* s)
324 {
325 	return s->uname;
326 }
327