xref: /plan9/sys/src/cmd/cwfs/auth.c (revision 223a035810d484657ee1a815f68faa8211009d6d)
101a344a2SDavid du Colombier #include "all.h"
201a344a2SDavid du Colombier #include "io.h"
301a344a2SDavid du Colombier #include <authsrv.h>
401a344a2SDavid du Colombier 
501a344a2SDavid du Colombier Nvrsafe	nvr;
601a344a2SDavid du Colombier 
701a344a2SDavid du Colombier static int gotnvr;	/* flag: nvr contains nvram; it could be bad */
801a344a2SDavid du Colombier 
901a344a2SDavid du Colombier char*
nvrgetconfig(void)1001a344a2SDavid du Colombier nvrgetconfig(void)
1101a344a2SDavid du Colombier {
1201a344a2SDavid du Colombier 	return conf.confdev;
1301a344a2SDavid du Colombier }
1401a344a2SDavid du Colombier 
1501a344a2SDavid du Colombier /*
1601a344a2SDavid du Colombier  * we shouldn't be writing nvram any more.
1701a344a2SDavid du Colombier  * the secstore/config field is now just secstore key.
1801a344a2SDavid du Colombier  * we still use authid, authdom and machkey for authentication.
1901a344a2SDavid du Colombier  */
2001a344a2SDavid du Colombier 
2101a344a2SDavid du Colombier int
nvrcheck(void)2201a344a2SDavid du Colombier nvrcheck(void)
2301a344a2SDavid du Colombier {
2401a344a2SDavid du Colombier 	uchar csum;
2501a344a2SDavid du Colombier 
2601a344a2SDavid du Colombier 	if (readnvram(&nvr, NVread) < 0) {
2701a344a2SDavid du Colombier 		print("nvrcheck: can't read nvram\n");
2801a344a2SDavid du Colombier 		return 1;
2901a344a2SDavid du Colombier 	} else
3001a344a2SDavid du Colombier 		gotnvr = 1;
3101a344a2SDavid du Colombier 	print("nvr read\n");
3201a344a2SDavid du Colombier 
3301a344a2SDavid du Colombier 	csum = nvcsum(nvr.machkey, sizeof nvr.machkey);
3401a344a2SDavid du Colombier 	if(csum != nvr.machsum) {
3501a344a2SDavid du Colombier 		print("\n\n ** NVR key checksum is incorrect  **\n");
3601a344a2SDavid du Colombier 		print(" ** set password to allow attaches **\n\n");
3701a344a2SDavid du Colombier 		memset(nvr.machkey, 0, sizeof nvr.machkey);
3801a344a2SDavid du Colombier 		return 1;
3901a344a2SDavid du Colombier 	}
4001a344a2SDavid du Colombier 
4101a344a2SDavid du Colombier 	return 0;
4201a344a2SDavid du Colombier }
4301a344a2SDavid du Colombier 
4401a344a2SDavid du Colombier int
nvrsetconfig(char * word)4501a344a2SDavid du Colombier nvrsetconfig(char* word)
4601a344a2SDavid du Colombier {
4701a344a2SDavid du Colombier 	/* config block is on device `word' */
4801a344a2SDavid du Colombier 	USED(word);
4901a344a2SDavid du Colombier 	return 0;
5001a344a2SDavid du Colombier }
5101a344a2SDavid du Colombier 
5201a344a2SDavid du Colombier int
conslock(void)5301a344a2SDavid du Colombier conslock(void)
5401a344a2SDavid du Colombier {
5501a344a2SDavid du Colombier 	char *ln;
5601a344a2SDavid du Colombier 	char nkey1[DESKEYLEN];
5701a344a2SDavid du Colombier 	static char zeroes[DESKEYLEN];
5801a344a2SDavid du Colombier 
5901a344a2SDavid du Colombier 	if(memcmp(nvr.machkey, zeroes, DESKEYLEN) == 0) {
6001a344a2SDavid du Colombier 		print("no password set\n");
6101a344a2SDavid du Colombier 		return 0;
6201a344a2SDavid du Colombier 	}
6301a344a2SDavid du Colombier 
6401a344a2SDavid du Colombier 	for(;;) {
6501a344a2SDavid du Colombier 		print("%s password:", service);
6601a344a2SDavid du Colombier 		/* could turn off echo here */
6701a344a2SDavid du Colombier 
6801a344a2SDavid du Colombier 		if ((ln = Brdline(&bin, '\n')) == nil)
6901a344a2SDavid du Colombier 			return 0;
7001a344a2SDavid du Colombier 		ln[Blinelen(&bin)-1] = '\0';
7101a344a2SDavid du Colombier 
7201a344a2SDavid du Colombier 		/* could turn on echo here */
7301a344a2SDavid du Colombier 		memset(nkey1, 0, DESKEYLEN);
7401a344a2SDavid du Colombier 		passtokey(nkey1, ln);
7501a344a2SDavid du Colombier 		if(memcmp(nkey1, nvr.machkey, DESKEYLEN) == 0) {
7601a344a2SDavid du Colombier 			prdate();
7701a344a2SDavid du Colombier 			break;
7801a344a2SDavid du Colombier 		}
7901a344a2SDavid du Colombier 
8001a344a2SDavid du Colombier 		print("Bad password\n");
8101a344a2SDavid du Colombier 		delay(1000);
8201a344a2SDavid du Colombier 	}
8301a344a2SDavid du Colombier 	return 1;
8401a344a2SDavid du Colombier }
8501a344a2SDavid du Colombier 
8601a344a2SDavid du Colombier /*
8701a344a2SDavid du Colombier  *  authentication specific to 9P2000
8801a344a2SDavid du Colombier  */
8901a344a2SDavid du Colombier 
9001a344a2SDavid du Colombier /* authentication states */
9101a344a2SDavid du Colombier enum
9201a344a2SDavid du Colombier {
9301a344a2SDavid du Colombier 	HaveProtos=1,
9401a344a2SDavid du Colombier 	NeedProto,
9501a344a2SDavid du Colombier 	HaveOK,
9601a344a2SDavid du Colombier 	NeedCchal,
9701a344a2SDavid du Colombier 	HaveSinfo,
9801a344a2SDavid du Colombier 	NeedTicket,
9901a344a2SDavid du Colombier 	HaveSauthenticator,
10001a344a2SDavid du Colombier 	SSuccess,
10101a344a2SDavid du Colombier };
10201a344a2SDavid du Colombier 
10301a344a2SDavid du Colombier char *phasename[] =
10401a344a2SDavid du Colombier {
10501a344a2SDavid du Colombier [HaveProtos]	"HaveProtos",
10601a344a2SDavid du Colombier [NeedProto]	"NeedProto",
10701a344a2SDavid du Colombier [HaveOK]	"HaveOK",
10801a344a2SDavid du Colombier [NeedCchal]	"NeedCchal",
10901a344a2SDavid du Colombier [HaveSinfo]	"HaveSinfo",
11001a344a2SDavid du Colombier [NeedTicket]	"NeedTicket",
11101a344a2SDavid du Colombier [HaveSauthenticator]	"HaveSauthenticator",
11201a344a2SDavid du Colombier [SSuccess]	"SSuccess",
11301a344a2SDavid du Colombier };
11401a344a2SDavid du Colombier 
11501a344a2SDavid du Colombier /* authentication structure */
11601a344a2SDavid du Colombier struct	Auth
11701a344a2SDavid du Colombier {
11801a344a2SDavid du Colombier 	int	inuse;
11901a344a2SDavid du Colombier 	char	uname[NAMELEN];	/* requestor's remote user name */
12001a344a2SDavid du Colombier 	char	aname[NAMELEN];	/* requested aname */
12101a344a2SDavid du Colombier 	Userid	uid;		/* uid decided on */
12201a344a2SDavid du Colombier 	int	phase;
12301a344a2SDavid du Colombier 	char	cchal[CHALLEN];
12401a344a2SDavid du Colombier 	char	tbuf[TICKETLEN+AUTHENTLEN];	/* server ticket */
12501a344a2SDavid du Colombier 	Ticket	t;
12601a344a2SDavid du Colombier 	Ticketreq tr;
12701a344a2SDavid du Colombier };
12801a344a2SDavid du Colombier 
12901a344a2SDavid du Colombier Auth*	auths;
13001a344a2SDavid du Colombier Lock	authlock;
13101a344a2SDavid du Colombier 
13201a344a2SDavid du Colombier void
authinit(void)13301a344a2SDavid du Colombier authinit(void)
13401a344a2SDavid du Colombier {
13501a344a2SDavid du Colombier 	auths = malloc(conf.nauth * sizeof(*auths));
13601a344a2SDavid du Colombier }
13701a344a2SDavid du Colombier 
13801a344a2SDavid du Colombier static int
failure(Auth * s,char * why)13901a344a2SDavid du Colombier failure(Auth *s, char *why)
14001a344a2SDavid du Colombier {
14101a344a2SDavid du Colombier 	int i;
14201a344a2SDavid du Colombier 
14301a344a2SDavid du Colombier if(*why)print("authentication failed: %s: %s\n", phasename[s->phase], why);
144*223a0358SDavid du Colombier 	srand((uintptr)s + time(nil));
14501a344a2SDavid du Colombier 	for(i = 0; i < CHALLEN; i++)
14601a344a2SDavid du Colombier 		s->tr.chal[i] = nrand(256);
14701a344a2SDavid du Colombier 	s->uid = -1;
14801a344a2SDavid du Colombier 	strncpy(s->tr.authid, nvr.authid, NAMELEN);
14901a344a2SDavid du Colombier 	strncpy(s->tr.authdom, nvr.authdom, DOMLEN);
15001a344a2SDavid du Colombier 	memmove(s->cchal, s->tr.chal, sizeof(s->cchal));
15101a344a2SDavid du Colombier 	s->phase = HaveProtos;
15201a344a2SDavid du Colombier 	return -1;
15301a344a2SDavid du Colombier }
15401a344a2SDavid du Colombier 
15501a344a2SDavid du Colombier Auth*
authnew(char * uname,char * aname)15601a344a2SDavid du Colombier authnew(char *uname, char *aname)
15701a344a2SDavid du Colombier {
15801a344a2SDavid du Colombier 	static int si = 0;
15901a344a2SDavid du Colombier 	int i, nwrap;
16001a344a2SDavid du Colombier 	Auth *s;
16101a344a2SDavid du Colombier 
16201a344a2SDavid du Colombier 	i = si;
16301a344a2SDavid du Colombier 	nwrap = 0;
16401a344a2SDavid du Colombier 	for(;;){
16501a344a2SDavid du Colombier 		if(i < 0 || i >= conf.nauth){
16601a344a2SDavid du Colombier 			if(++nwrap > 1)
16701a344a2SDavid du Colombier 				return nil;
16801a344a2SDavid du Colombier 			i = 0;
16901a344a2SDavid du Colombier 		}
17001a344a2SDavid du Colombier 		s = &auths[i++];
17101a344a2SDavid du Colombier 		if(s->inuse)
17201a344a2SDavid du Colombier 			continue;
17301a344a2SDavid du Colombier 		lock(&authlock);
17401a344a2SDavid du Colombier 		if(s->inuse == 0){
17501a344a2SDavid du Colombier 			s->inuse = 1;
17601a344a2SDavid du Colombier 			strncpy(s->uname, uname, NAMELEN-1);
17701a344a2SDavid du Colombier 			strncpy(s->aname, aname, NAMELEN-1);
17801a344a2SDavid du Colombier 			failure(s, "");
17901a344a2SDavid du Colombier 			si = i;
18001a344a2SDavid du Colombier 			unlock(&authlock);
18101a344a2SDavid du Colombier 			break;
18201a344a2SDavid du Colombier 		}
18301a344a2SDavid du Colombier 		unlock(&authlock);
18401a344a2SDavid du Colombier 	}
18501a344a2SDavid du Colombier 	return s;
18601a344a2SDavid du Colombier }
18701a344a2SDavid du Colombier 
18801a344a2SDavid du Colombier void
authfree(Auth * s)18901a344a2SDavid du Colombier authfree(Auth *s)
19001a344a2SDavid du Colombier {
19101a344a2SDavid du Colombier 	if(s != nil)
19201a344a2SDavid du Colombier 		s->inuse = 0;
19301a344a2SDavid du Colombier }
19401a344a2SDavid du Colombier 
19501a344a2SDavid du Colombier int
authread(File * file,uchar * data,int n)19601a344a2SDavid du Colombier authread(File* file, uchar* data, int n)
19701a344a2SDavid du Colombier {
19801a344a2SDavid du Colombier 	Auth *s;
19901a344a2SDavid du Colombier 	int m;
20001a344a2SDavid du Colombier 
20101a344a2SDavid du Colombier 	s = file->auth;
20201a344a2SDavid du Colombier 	if(s == nil)
20301a344a2SDavid du Colombier 		return -1;
20401a344a2SDavid du Colombier 
20501a344a2SDavid du Colombier 	switch(s->phase){
20601a344a2SDavid du Colombier 	default:
20701a344a2SDavid du Colombier 		return failure(s, "unexpected phase");
20801a344a2SDavid du Colombier 	case HaveProtos:
20901a344a2SDavid du Colombier 		m = snprint((char*)data, n, "v.2 p9sk1@%s", nvr.authdom) + 1;
21001a344a2SDavid du Colombier 		s->phase = NeedProto;
21101a344a2SDavid du Colombier 		break;
21201a344a2SDavid du Colombier 	case HaveOK:
21301a344a2SDavid du Colombier 		m = 3;
21401a344a2SDavid du Colombier 		if(n < m)
21501a344a2SDavid du Colombier 			return failure(s, "read too short");
21601a344a2SDavid du Colombier 		strcpy((char*)data, "OK");
21701a344a2SDavid du Colombier 		s->phase = NeedCchal;
21801a344a2SDavid du Colombier 		break;
21901a344a2SDavid du Colombier 	case HaveSinfo:
22001a344a2SDavid du Colombier 		m = TICKREQLEN;
22101a344a2SDavid du Colombier 		if(n < m)
22201a344a2SDavid du Colombier 			return failure(s, "read too short");
22301a344a2SDavid du Colombier 		convTR2M(&s->tr, (char*)data);
22401a344a2SDavid du Colombier 		s->phase = NeedTicket;
22501a344a2SDavid du Colombier 		break;
22601a344a2SDavid du Colombier 	case HaveSauthenticator:
22701a344a2SDavid du Colombier 		m = AUTHENTLEN;
22801a344a2SDavid du Colombier 		if(n < m)
22901a344a2SDavid du Colombier 			return failure(s, "read too short");
23001a344a2SDavid du Colombier 		memmove(data, s->tbuf+TICKETLEN, m);
23101a344a2SDavid du Colombier 		s->phase = SSuccess;
23201a344a2SDavid du Colombier 		break;
23301a344a2SDavid du Colombier 	}
23401a344a2SDavid du Colombier 	return m;
23501a344a2SDavid du Colombier }
23601a344a2SDavid du Colombier 
23701a344a2SDavid du Colombier int
authwrite(File * file,uchar * data,int n)23801a344a2SDavid du Colombier authwrite(File* file, uchar *data, int n)
23901a344a2SDavid du Colombier {
24001a344a2SDavid du Colombier 	Auth *s;
24101a344a2SDavid du Colombier 	int m;
24201a344a2SDavid du Colombier 	char *p, *d;
24301a344a2SDavid du Colombier 	Authenticator a;
24401a344a2SDavid du Colombier 
24501a344a2SDavid du Colombier 	s = file->auth;
24601a344a2SDavid du Colombier 	if(s == nil)
24701a344a2SDavid du Colombier 		return -1;
24801a344a2SDavid du Colombier 
24901a344a2SDavid du Colombier 	switch(s->phase){
25001a344a2SDavid du Colombier 	default:
25101a344a2SDavid du Colombier 		return failure(s, "unknown phase");
25201a344a2SDavid du Colombier 	case NeedProto:
25301a344a2SDavid du Colombier 		p = (char*)data;
25401a344a2SDavid du Colombier 		if(p[n-1] != 0)
25501a344a2SDavid du Colombier 			return failure(s, "proto missing terminator");
25601a344a2SDavid du Colombier 		d = strchr(p, ' ');
25701a344a2SDavid du Colombier 		if(d == nil)
25801a344a2SDavid du Colombier 			return failure(s, "proto missing separator");
25901a344a2SDavid du Colombier 		*d++ = 0;
26001a344a2SDavid du Colombier 		if(strcmp(p, "p9sk1") != 0)
26101a344a2SDavid du Colombier 			return failure(s, "unknown proto");
26201a344a2SDavid du Colombier 		if(strcmp(d, nvr.authdom) != 0)
26301a344a2SDavid du Colombier 			return failure(s, "unknown domain");
26401a344a2SDavid du Colombier 		s->phase = HaveOK;
26501a344a2SDavid du Colombier 		m = n;
26601a344a2SDavid du Colombier 		break;
26701a344a2SDavid du Colombier 	case NeedCchal:
26801a344a2SDavid du Colombier 		m = CHALLEN;
26901a344a2SDavid du Colombier 		if(n < m)
27001a344a2SDavid du Colombier 			return failure(s, "client challenge too short");
27101a344a2SDavid du Colombier 		memmove(s->cchal, data, sizeof(s->cchal));
27201a344a2SDavid du Colombier 		s->phase = HaveSinfo;
27301a344a2SDavid du Colombier 		break;
27401a344a2SDavid du Colombier 	case NeedTicket:
27501a344a2SDavid du Colombier 		m = TICKETLEN+AUTHENTLEN;
27601a344a2SDavid du Colombier 		if(n < m)
27701a344a2SDavid du Colombier 			return failure(s, "ticket+auth too short");
27801a344a2SDavid du Colombier 
27901a344a2SDavid du Colombier 		convM2T((char*)data, &s->t, nvr.machkey);
28001a344a2SDavid du Colombier 		if(s->t.num != AuthTs
28101a344a2SDavid du Colombier 		|| memcmp(s->t.chal, s->tr.chal, sizeof(s->t.chal)) != 0)
28201a344a2SDavid du Colombier 			return failure(s, "bad ticket");
28301a344a2SDavid du Colombier 
28401a344a2SDavid du Colombier 		convM2A((char*)data+TICKETLEN, &a, s->t.key);
28501a344a2SDavid du Colombier 		if(a.num != AuthAc
28601a344a2SDavid du Colombier 		|| memcmp(a.chal, s->tr.chal, sizeof(a.chal)) != 0
28701a344a2SDavid du Colombier 		|| a.id != 0)
28801a344a2SDavid du Colombier 			return failure(s, "bad authenticator");
28901a344a2SDavid du Colombier 
29001a344a2SDavid du Colombier 		/* at this point, we're convinced */
29101a344a2SDavid du Colombier 		s->uid = strtouid(s->t.suid);
29201a344a2SDavid du Colombier 		if(s->uid < 0)
29301a344a2SDavid du Colombier 			return failure(s, "unknown user");
29401a344a2SDavid du Colombier 		if(cons.flags & authdebugflag)
29501a344a2SDavid du Colombier 			print("user %s = %d authenticated\n",
29601a344a2SDavid du Colombier 				s->t.suid, s->uid);
29701a344a2SDavid du Colombier 
29801a344a2SDavid du Colombier 		/* create an authenticator to send back */
29901a344a2SDavid du Colombier 		a.num = AuthAs;
30001a344a2SDavid du Colombier 		memmove(a.chal, s->cchal, sizeof(a.chal));
30101a344a2SDavid du Colombier 		a.id = 0;
30201a344a2SDavid du Colombier 		convA2M(&a, s->tbuf+TICKETLEN, s->t.key);
30301a344a2SDavid du Colombier 
30401a344a2SDavid du Colombier 		s->phase = HaveSauthenticator;
30501a344a2SDavid du Colombier 		break;
30601a344a2SDavid du Colombier 	}
30701a344a2SDavid du Colombier 	return m;
30801a344a2SDavid du Colombier }
30901a344a2SDavid du Colombier 
31001a344a2SDavid du Colombier int
authuid(Auth * s)31101a344a2SDavid du Colombier authuid(Auth* s)
31201a344a2SDavid du Colombier {
31301a344a2SDavid du Colombier 	return s->uid;
31401a344a2SDavid du Colombier }
31501a344a2SDavid du Colombier 
31601a344a2SDavid du Colombier char*
authaname(Auth * s)31701a344a2SDavid du Colombier authaname(Auth* s)
31801a344a2SDavid du Colombier {
31901a344a2SDavid du Colombier 	return s->aname;
32001a344a2SDavid du Colombier }
32101a344a2SDavid du Colombier 
32201a344a2SDavid du Colombier char*
authuname(Auth * s)32301a344a2SDavid du Colombier authuname(Auth* s)
32401a344a2SDavid du Colombier {
32501a344a2SDavid du Colombier 	return s->uname;
32601a344a2SDavid du Colombier }
327