#include "all.h" #include "io.h" #include Nvrsafe nvr; static int gotnvr; /* flag: nvr contains nvram; it could be bad */ char* nvrgetconfig(void) { return conf.confdev; } /* * we shouldn't be writing nvram any more. * the secstore/config field is now just secstore key. * we still use authid, authdom and machkey for authentication. */ int nvrcheck(void) { uchar csum; if (readnvram(&nvr, NVread) < 0) { print("nvrcheck: can't read nvram\n"); return 1; } else gotnvr = 1; print("nvr read\n"); csum = nvcsum(nvr.machkey, sizeof nvr.machkey); if(csum != nvr.machsum) { print("\n\n ** NVR key checksum is incorrect **\n"); print(" ** set password to allow attaches **\n\n"); memset(nvr.machkey, 0, sizeof nvr.machkey); return 1; } return 0; } int nvrsetconfig(char* word) { /* config block is on device `word' */ USED(word); return 0; } int conslock(void) { char *ln; char nkey1[DESKEYLEN]; static char zeroes[DESKEYLEN]; if(memcmp(nvr.machkey, zeroes, DESKEYLEN) == 0) { print("no password set\n"); return 0; } for(;;) { print("%s password:", service); /* could turn off echo here */ if ((ln = Brdline(&bin, '\n')) == nil) return 0; ln[Blinelen(&bin)-1] = '\0'; /* could turn on echo here */ memset(nkey1, 0, DESKEYLEN); passtokey(nkey1, ln); if(memcmp(nkey1, nvr.machkey, DESKEYLEN) == 0) { prdate(); break; } print("Bad password\n"); delay(1000); } return 1; } /* * authentication specific to 9P2000 */ /* authentication states */ enum { HaveProtos=1, NeedProto, HaveOK, NeedCchal, HaveSinfo, NeedTicket, HaveSauthenticator, SSuccess, }; char *phasename[] = { [HaveProtos] "HaveProtos", [NeedProto] "NeedProto", [HaveOK] "HaveOK", [NeedCchal] "NeedCchal", [HaveSinfo] "HaveSinfo", [NeedTicket] "NeedTicket", [HaveSauthenticator] "HaveSauthenticator", [SSuccess] "SSuccess", }; /* authentication structure */ struct Auth { int inuse; char uname[NAMELEN]; /* requestor's remote user name */ char aname[NAMELEN]; /* requested aname */ Userid uid; /* uid decided on */ int phase; char cchal[CHALLEN]; char tbuf[TICKETLEN+AUTHENTLEN]; /* server ticket */ Ticket t; Ticketreq tr; }; Auth* auths; Lock authlock; void authinit(void) { auths = malloc(conf.nauth * sizeof(*auths)); } static int failure(Auth *s, char *why) { int i; if(*why)print("authentication failed: %s: %s\n", phasename[s->phase], why); srand((uintptr)s + time(nil)); for(i = 0; i < CHALLEN; i++) s->tr.chal[i] = nrand(256); s->uid = -1; strncpy(s->tr.authid, nvr.authid, NAMELEN); strncpy(s->tr.authdom, nvr.authdom, DOMLEN); memmove(s->cchal, s->tr.chal, sizeof(s->cchal)); s->phase = HaveProtos; return -1; } Auth* authnew(char *uname, char *aname) { static int si = 0; int i, nwrap; Auth *s; i = si; nwrap = 0; for(;;){ if(i < 0 || i >= conf.nauth){ if(++nwrap > 1) return nil; i = 0; } s = &auths[i++]; if(s->inuse) continue; lock(&authlock); if(s->inuse == 0){ s->inuse = 1; strncpy(s->uname, uname, NAMELEN-1); strncpy(s->aname, aname, NAMELEN-1); failure(s, ""); si = i; unlock(&authlock); break; } unlock(&authlock); } return s; } void authfree(Auth *s) { if(s != nil) s->inuse = 0; } int authread(File* file, uchar* data, int n) { Auth *s; int m; s = file->auth; if(s == nil) return -1; switch(s->phase){ default: return failure(s, "unexpected phase"); case HaveProtos: m = snprint((char*)data, n, "v.2 p9sk1@%s", nvr.authdom) + 1; s->phase = NeedProto; break; case HaveOK: m = 3; if(n < m) return failure(s, "read too short"); strcpy((char*)data, "OK"); s->phase = NeedCchal; break; case HaveSinfo: m = TICKREQLEN; if(n < m) return failure(s, "read too short"); convTR2M(&s->tr, (char*)data); s->phase = NeedTicket; break; case HaveSauthenticator: m = AUTHENTLEN; if(n < m) return failure(s, "read too short"); memmove(data, s->tbuf+TICKETLEN, m); s->phase = SSuccess; break; } return m; } int authwrite(File* file, uchar *data, int n) { Auth *s; int m; char *p, *d; Authenticator a; s = file->auth; if(s == nil) return -1; switch(s->phase){ default: return failure(s, "unknown phase"); case NeedProto: p = (char*)data; if(p[n-1] != 0) return failure(s, "proto missing terminator"); d = strchr(p, ' '); if(d == nil) return failure(s, "proto missing separator"); *d++ = 0; if(strcmp(p, "p9sk1") != 0) return failure(s, "unknown proto"); if(strcmp(d, nvr.authdom) != 0) return failure(s, "unknown domain"); s->phase = HaveOK; m = n; break; case NeedCchal: m = CHALLEN; if(n < m) return failure(s, "client challenge too short"); memmove(s->cchal, data, sizeof(s->cchal)); s->phase = HaveSinfo; break; case NeedTicket: m = TICKETLEN+AUTHENTLEN; if(n < m) return failure(s, "ticket+auth too short"); convM2T((char*)data, &s->t, nvr.machkey); if(s->t.num != AuthTs || memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0) return failure(s, "bad ticket"); convM2A((char*)data+TICKETLEN, &a, s->t.key); if(a.num != AuthAc || memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0 || a.id != 0) return failure(s, "bad authenticator"); /* at this point, we're convinced */ s->uid = strtouid(s->t.suid); if(s->uid < 0) return failure(s, "unknown user"); if(cons.flags & authdebugflag) print("user %s = %d authenticated\n", s->t.suid, s->uid); /* create an authenticator to send back */ a.num = AuthAs; memmove(a.chal, s->cchal, sizeof(a.chal)); a.id = 0; convA2M(&a, s->tbuf+TICKETLEN, s->t.key); s->phase = HaveSauthenticator; break; } return m; } int authuid(Auth* s) { return s->uid; } char* authaname(Auth* s) { return s->aname; } char* authuname(Auth* s) { return s->uname; }