|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "io.h"
7: #include "../port/error.h"
8:
9: typedef struct Crypt Crypt;
10: struct Crypt
11: {
12: Crypt *next;
13: Ticket t;
14: Authenticator a;
15: char tbuf[TICKETLEN]; /* remote ticket */
16: };
17:
18: typedef struct Session Session;
19: struct Session
20: {
21: Lock;
22: QLock send;
23: Crypt *cache; /* cache of tickets */
24: char cchal[CHALLEN]; /* client challenge */
25: char schal[CHALLEN]; /* server challenge */
26: char authid[NAMELEN]; /* server encryption uid */
27: char authdom[DOMLEN]; /* server encryption domain */
28: ulong cid; /* challenge id */
29: int valid;
30: };
31:
32: struct
33: {
34: Lock;
35: Crypt *free;
36: } cryptalloc;
37:
38: char eve[NAMELEN] = "bootes";
39: char evekey[DESKEYLEN];
40: char hostdomain[DOMLEN];
41:
42: /*
43: * return true if current user is eve
44: */
45: int
46: iseve(void)
47: {
48: return strcmp(eve, u->p->user) == 0;
49: }
50:
51: /*
52: * crypt entries are allocated from a pool rather than allocated using malloc so
53: * the memory can be protected from reading by devproc. The base and top of the
54: * crypt arena is stored in palloc for devproc.
55: */
56: Crypt*
57: newcrypt(void)
58: {
59: Crypt *c;
60:
61: lock(&cryptalloc);
62: if(cryptalloc.free) {
63: c = cryptalloc.free;
64: cryptalloc.free = c->next;
65: unlock(&cryptalloc);
66: memset(c, 0, sizeof(Crypt));
67: return c;
68: }
69:
70: cryptalloc.free = xalloc(sizeof(Crypt)*conf.nproc);
71: if(cryptalloc.free == 0)
72: panic("newcrypt");
73:
74: for(c = cryptalloc.free; c < cryptalloc.free+conf.nproc-1; c++)
75: c->next = c+1;
76:
77: palloc.cmembase = (ulong)cryptalloc.free;
78: palloc.cmemtop = palloc.cmembase+(sizeof(Crypt)*conf.nproc);
79: unlock(&cryptalloc);
80: return newcrypt();
81: }
82:
83: void
84: freecrypt(Crypt *c)
85: {
86: lock(&cryptalloc);
87: c->next = cryptalloc.free;
88: cryptalloc.free = c;
89: unlock(&cryptalloc);
90: }
91:
92: /*
93: * return the info received in the session message on this channel.
94: * if no session message has been exchanged, do it.
95: */
96: long
97: sysfsession(ulong *arg)
98: {
99: int i, n;
100: Chan *c;
101: Crypt *cp;
102: Session *s;
103: Ticketreq tr;
104: Fcall f;
105: char buf[MAXMSG];
106:
107: validaddr(arg[1], TICKREQLEN, 1);
108: c = fdtochan(arg[0], OWRITE, 0, 1);
109: if(waserror()){
110: close(c);
111: nexterror();
112: }
113:
114: /* add a session structure to the channel if it has none */
115: lock(c);
116: s = c->session;
117: if(s == 0){
118: s = malloc(sizeof(Session));
119: if(s == 0){
120: unlock(c);
121: error(Enomem);
122: }
123: c->session = s;
124: }
125: unlock(c);
126:
127: qlock(&s->send);
128: if(s->valid == 0){
129: /*
130: * Exchange a session message with the server.
131: */
132: for(i = 0; i < CHALLEN; i++)
133: s->cchal[i] = nrand(256);
134:
135: f.tag = NOTAG;
136: f.type = Tsession;
137: memmove(f.chal, s->cchal, CHALLEN);
138: n = convS2M(&f, buf);
139:
140: /*
141: * If an error occurs reading or writing,
142: * this probably is a mount of a mount so turn off
143: * authentication.
144: */
145: if(waserror())
146: goto noauth;
147:
148: if((*devtab[c->type].write)(c, buf, n, 0) != n)
149: error(Esession);
150: n = (*devtab[c->type].read)(c, buf, sizeof buf, 0);
151: /* OK is sometimes sent as a Datakit sign-on */
152: if(n == 2 && buf[0] == 'O' && buf[1] == 'K')
153: n = (*devtab[c->type].read)(c, buf, sizeof buf, 0);
154:
155: poperror();
156:
157: if(convM2S(buf, &f, n) == 0){
158: qunlock(&s->send);
159: error(Esession);
160: }
161: switch(f.type){
162: case Rsession:
163: memmove(s->schal, f.chal, CHALLEN);
164: memmove(s->authid, f.authid, NAMELEN);
165: memmove(s->authdom, f.authdom, DOMLEN);
166: break;
167: case Rerror:
168: qunlock(&s->send);
169: error(f.ename);
170: default:
171: qunlock(&s->send);
172: error(Esession);
173: }
174: noauth:
175: s->valid = 1;
176: }
177: qunlock(&s->send);
178:
179: /*
180: * If server requires no ticket, or user is "none", or a ticket
181: * is already cached, zero the request type
182: */
183: tr.type = AuthTreq;
184: if(strcmp(u->p->user, "none") == 0 || s->authid[0] == 0)
185: tr.type = 0;
186: else{
187: lock(s);
188: for(cp = s->cache; cp; cp = cp->next)
189: if(strcmp(cp->t.cuid, u->p->user) == 0){
190: tr.type = 0;
191: break;
192: }
193: unlock(s);
194: }
195:
196: /* create ticket request */
197: memmove(tr.chal, s->schal, CHALLEN);
198: memmove(tr.authid, s->authid, NAMELEN);
199: memmove(tr.authdom, s->authdom, DOMLEN);
200: memmove(tr.uid, u->p->user, NAMELEN);
201: memmove(tr.hostid, eve, NAMELEN);
202: convTR2M(&tr, (char*)arg[1]);
203:
204: close(c);
205: poperror();
206: return 0;
207: }
208:
209: /*
210: * attach tickets to a session
211: */
212: long
213: sysfauth(ulong *arg)
214: {
215: Chan *c;
216: char *ta;
217: Session *s;
218: Crypt *cp, *ncp, **l;
219: char tbuf[2*TICKETLEN];
220:
221: validaddr(arg[1], 2*TICKETLEN, 0);
222: c = fdtochan(arg[0], OWRITE, 0, 1);
223: s = c->session;
224: if(s == 0)
225: error("fauth must follow fsession");
226: cp = newcrypt();
227: if(waserror()){
228: freecrypt(cp);
229: nexterror();
230: }
231:
232: /* ticket supplied, use it */
233: ta = (char*)arg[1];
234: memmove(tbuf, ta, 2*TICKETLEN);
235: convM2T(tbuf, &cp->t, evekey);
236: if(cp->t.num != AuthTc)
237: error("bad AuthTc in ticket");
238: if(strncmp(u->p->user, cp->t.cuid, NAMELEN) != 0)
239: error("bad uid in ticket");
240: if(memcmp(cp->t.chal, s->schal, CHALLEN) != 0)
241: error("bad chal in ticket");
242: memmove(cp->tbuf, tbuf+TICKETLEN, TICKETLEN);
243:
244: /* string onto local list, replace old version */
245: lock(s);
246: l = &s->cache;
247: for(ncp = s->cache; ncp; ncp = *l){
248: if(strcmp(ncp->t.cuid, u->p->user) == 0){
249: *l = ncp->next;
250: freecrypt(ncp);
251: break;
252: }
253: l = &ncp->next;
254: }
255: cp->next = s->cache;
256: s->cache = cp;
257: unlock(s);
258: poperror();
259: return 0;
260: }
261:
262: /*
263: * free a session created by fsession
264: */
265: void
266: freesession(Session *s)
267: {
268: Crypt *cp, *next;
269:
270: for(cp = s->cache; cp; cp = next) {
271: next = cp->next;
272: freecrypt(cp);
273: }
274: free(s);
275: }
276:
277: /*
278: * called by mattach() to fill in the Tattach message
279: */
280: ulong
281: authrequest(Session *s, Fcall *f)
282: {
283: Crypt *cp;
284: ulong id, dofree;
285:
286: /* no authentication if user is "none" or if no ticket required by remote */
287: if(s == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0){
288: memset(f->ticket, 0, TICKETLEN);
289: memset(f->auth, 0, AUTHENTLEN);
290: return 0;
291: }
292:
293: /* look for ticket in cache */
294: dofree = 0;
295: lock(s);
296: for(cp = s->cache; cp; cp = cp->next)
297: if(strcmp(cp->t.cuid, u->p->user) == 0)
298: break;
299:
300: id = s->cid++;
301: unlock(s);
302:
303: if(cp == 0){
304: /*
305: * create a ticket using hostkey, this solves the
306: * chicken and egg problem
307: */
308: cp = newcrypt();
309: cp->t.num = AuthTs;
310: memmove(cp->t.chal, s->schal, CHALLEN);
311: memmove(cp->t.cuid, u->p->user, NAMELEN);
312: memmove(cp->t.suid, u->p->user, NAMELEN);
313: memmove(cp->t.key, evekey, DESKEYLEN);
314: convT2M(&cp->t, f->ticket, evekey);
315: dofree = 1;
316: } else
317: memmove(f->ticket, cp->tbuf, TICKETLEN);
318:
319: /* create an authenticator */
320: memmove(cp->a.chal, s->schal, CHALLEN);
321: cp->a.num = AuthAc;
322: cp->a.id = id;
323: convA2M(&cp->a, f->auth, cp->t.key);
324: if(dofree)
325: freecrypt(cp);
326: return id;
327: }
328:
329: /*
330: * called by mattach() to check the Rattach message
331: */
332: void
333: authreply(Session *s, ulong id, Fcall *f)
334: {
335: Crypt *cp;
336:
337: if(s == 0)
338: return;
339:
340: lock(s);
341: for(cp = s->cache; cp; cp = cp->next)
342: if(strcmp(cp->t.cuid, u->p->user) == 0)
343: break;
344: unlock(s);
345:
346: /* we're getting around authentication */
347: if(s == 0 || cp == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0)
348: return;
349:
350: convM2A(f->rauth, &cp->a, cp->t.key);
351: if(cp->a.num != AuthAs){
352: print("bad encryption type\n");
353: error("server lies");
354: }
355: if(memcmp(cp->a.chal, s->cchal, sizeof(cp->a.chal))){
356: print("bad returned challenge\n");
357: error("server lies");
358: }
359: if(cp->a.id != id){
360: print("bad returned id\n");
361: error("server lies");
362: }
363: }
364:
365: /*
366: * called by devcons() for #c/authenticate
367: *
368: * The protocol is
369: * 1) read ticket request from #c/authenticate
370: * 2) write ticket+authenticator to #c/authenticate. if it matches
371: * the challenge the user is changed to the suid field of the ticket
372: * 3) read authenticator (to confirm this is the server advertised)
373: */
374: long
375: authread(Chan *c, char *a, int n)
376: {
377: Crypt *cp;
378: int i;
379: Ticketreq tr;
380:
381: if(c->aux == 0){
382: /*
383: * first read returns a ticket request
384: */
385: if(n != TICKREQLEN)
386: error(Ebadarg);
387: c->aux = newcrypt();
388: cp = c->aux;
389:
390: memset(&tr, 0, sizeof(tr));
391: tr.type = AuthTreq;
392: strcpy(tr.hostid, eve);
393: strcpy(tr.authid, eve);
394: strcpy(tr.authdom, hostdomain);
395: strcpy(tr.uid, u->p->user);
396: for(i = 0; i < CHALLEN; i++)
397: tr.chal[i] = nrand(256);
398: memmove(cp->a.chal, tr.chal, CHALLEN);
399: convTR2M(&tr, a);
400: } else {
401: /*
402: * subsequent read returns an authenticator
403: */
404: if(n != AUTHENTLEN)
405: error(Ebadarg);
406: cp = c->aux;
407:
408: cp->a.num = AuthAs;
409: memmove(cp->a.chal, cp->t.chal, CHALLEN);
410: cp->a.id = 0;
411: convA2M(&cp->a, cp->tbuf, cp->t.key);
412: memmove(a, cp->tbuf, AUTHENTLEN);
413:
414: freecrypt(cp);
415: c->aux = 0;
416: }
417: return n;
418: }
419:
420: long
421: authwrite(Chan *c, char *a, int n)
422: {
423: Crypt *cp;
424:
425: if(n != TICKETLEN+AUTHENTLEN)
426: error(Ebadarg);
427: if(c->aux == 0)
428: error(Ebadarg);
429: cp = c->aux;
430:
431: memmove(cp->tbuf, a, TICKETLEN);
432: convM2T(cp->tbuf, &cp->t, evekey);
433: if(cp->t.num != AuthTs || memcmp(cp->a.chal, cp->t.chal, CHALLEN))
434: error(Eperm);
435:
436: memmove(cp->tbuf, a+TICKETLEN, AUTHENTLEN);
437: convM2A(cp->tbuf, &cp->a, cp->t.key);
438: if(cp->a.num != AuthAc || memcmp(cp->a.chal, cp->t.chal, CHALLEN))
439: error(Eperm);
440:
441: memmove(u->p->user, cp->t.suid, NAMELEN);
442: return n;
443: }
444:
445: /*
446: * called by devcons() for #c/authcheck
447: *
448: * a write of a ticket+authenticator [+challenge+id] succeeds if they match
449: */
450: long
451: authcheck(Chan *c, char *a, int n)
452: {
453: Crypt *cp;
454: char *chal;
455: ulong id;
456:
457: if(n != TICKETLEN+AUTHENTLEN && n != TICKETLEN+AUTHENTLEN+CHALLEN+4)
458: error(Ebadarg);
459: if(c->aux == 0)
460: c->aux = newcrypt();
461: cp = c->aux;
462:
463: memmove(cp->tbuf, a, TICKETLEN);
464: convM2T(cp->tbuf, &cp->t, evekey);
465: if(cp->t.num != AuthTc)
466: error(Ebadarg);
467: if(strcmp(u->p->user, cp->t.cuid))
468: error(cp->t.cuid);
469:
470: memmove(cp->tbuf, a+TICKETLEN, AUTHENTLEN);
471: convM2A(cp->tbuf, &cp->a, cp->t.key);
472: if(n == TICKETLEN+AUTHENTLEN+CHALLEN+4){
473: uchar *p = (uchar *)&a[TICKETLEN+AUTHENTLEN+CHALLEN];
474: id = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
475: chal = &a[TICKETLEN+AUTHENTLEN];
476: }else{
477: id = 0;
478: chal = cp->t.chal;
479: }
480: if(cp->a.num != AuthAs || memcmp(chal, cp->a.chal, CHALLEN) || cp->a.id != id)
481: error(Eperm);
482:
483: return n;
484: }
485:
486: /*
487: * called by devcons() for #c/authenticator
488: *
489: * a read after a write of a ticket (or ticket+id) returns an authenticator
490: * for that ticket.
491: */
492: long
493: authentwrite(Chan *c, char *a, int n)
494: {
495: Crypt *cp;
496:
497: if(n != TICKETLEN && n != TICKETLEN+4)
498: error(Ebadarg);
499: if(c->aux == 0)
500: c->aux = newcrypt();
501: cp = c->aux;
502:
503: memmove(cp->tbuf, a, TICKETLEN);
504: convM2T(cp->tbuf, &cp->t, evekey);
505: if(cp->t.num != AuthTc || strcmp(cp->t.cuid, u->p->user)){
506: freecrypt(cp);
507: c->aux = 0;
508: error(Ebadarg);
509: }
510: if(n == TICKETLEN+4){
511: uchar *p = (uchar *)&a[TICKETLEN];
512: cp->a.id = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
513: }else
514: cp->a.id = 0;
515:
516: return n;
517: }
518: long
519: authentread(Chan *c, char *a, int n)
520: {
521: Crypt *cp;
522:
523: cp = c->aux;
524: if(cp == 0)
525: error("authenticator read must follow a write");
526:
527: cp->a.num = AuthAc;
528: memmove(cp->a.chal, cp->t.chal, CHALLEN);
529: convA2M(&cp->a, cp->tbuf, cp->t.key);
530: memmove(a, cp->tbuf, AUTHENTLEN);
531:
532: return n;
533: }
534:
535: void
536: authclose(Chan *c)
537: {
538: if(c->aux)
539: freecrypt(c->aux);
540: c->aux = 0;
541: }
542:
543: /*
544: * called by devcons() for key device
545: */
546: long
547: keyread(char *a, int n, long offset)
548: {
549: if(n<DESKEYLEN || offset != 0)
550: error(Ebadarg);
551: if(!cpuserver || !iseve())
552: error(Eperm);
553: memmove(a, evekey, DESKEYLEN);
554: return DESKEYLEN;
555: }
556:
557: long
558: keywrite(char *a, int n)
559: {
560: if(n != DESKEYLEN)
561: error(Ebadarg);
562: if(!iseve())
563: error(Eperm);
564: memmove(evekey, a, DESKEYLEN);
565: return DESKEYLEN;
566: }
567:
568: /*
569: * called by devcons() for user device
570: *
571: * anyone can become none
572: */
573: long
574: userwrite(char *a, int n)
575: {
576: if(n >= NAMELEN)
577: error(Ebadarg);
578: if(strcmp(a, "none") != 0)
579: error(Eperm);
580: memset(u->p->user, 0, NAMELEN);
581: strcpy(u->p->user, "none");
582: return n;
583: }
584:
585: /*
586: * called by devcons() for host owner/domain
587: *
588: * writing hostowner also sets user
589: */
590: long
591: hostownerwrite(char *a, int n)
592: {
593: char buf[NAMELEN];
594:
595: if(!iseve())
596: error(Eperm);
597: if(n >= NAMELEN)
598: error(Ebadarg);
599: memset(buf, 0, NAMELEN);
600: strncpy(buf, a, n);
601: if(buf[0] == 0)
602: error(Ebadarg);
603: memmove(eve, buf, NAMELEN);
604: memmove(u->p->user, buf, NAMELEN);
605: return n;
606: }
607:
608: long
609: hostdomainwrite(char *a, int n)
610: {
611: char buf[DOMLEN];
612:
613: if(!iseve())
614: error(Eperm);
615: if(n >= DOMLEN)
616: error(Ebadarg);
617: memset(buf, 0, DOMLEN);
618: strncpy(buf, a, n);
619: if(buf[0] == 0)
620: error(Ebadarg);
621: memmove(hostdomain, buf, DOMLEN);
622: return n;
623: }
624:
625: void
626: wipekeys(void)
627: {
628: memset(evekey, 0, sizeof(evekey));
629: memset((void*)palloc.cmembase, 0, palloc.cmemtop - palloc.cmembase);
630: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.