335 lines · 6.1 KB · C
RawDownload
/*  * 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;}