|
|
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.