/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h"#include "io.h"#include <authsrv.h> 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. */ intnvrcheck(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;} intnvrsetconfig(char* word){ /* config block is on device `word' */ USED(word); return 0;} intconslock(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; voidauthinit(void){ auths = malloc(conf.nauth * sizeof(*auths));} static intfailure(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;} voidauthfree(Auth *s){ if(s != nil) s->inuse = 0;} intauthread(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;} intauthwrite(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;} intauthuid(Auth* s){ return s->uid;} char*authaname(Auth* s){ return s->aname;} char*authuname(Auth* s){ return s->uname;}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include "all.h"
#include "io.h"
#include <authsrv.h>
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;
}