xref: /plan9/sys/src/cmd/auth/secstore/password.c (revision 7e18f0426d604d0a3448b7b408d9bf716ab433d7)
19a747e4fSDavid du Colombier /* password.c */
29a747e4fSDavid du Colombier #include <u.h>
39a747e4fSDavid du Colombier #include <libc.h>
49a747e4fSDavid du Colombier #include <bio.h>
59a747e4fSDavid du Colombier #include <mp.h>
69a747e4fSDavid du Colombier #include <libsec.h>
79a747e4fSDavid du Colombier #include "SConn.h"
89a747e4fSDavid du Colombier #include "secstore.h"
99a747e4fSDavid du Colombier 
109a747e4fSDavid du Colombier static Biobuf*
openPW(char * id,int mode)119a747e4fSDavid du Colombier openPW(char *id, int mode)
129a747e4fSDavid du Colombier {
139a747e4fSDavid du Colombier 	int nfn = strlen(SECSTORE_DIR)+strlen(id)+20;
1411c9ee8bSDavid du Colombier 	char *fn;
15*7e18f042SDavid du Colombier 	Biobuf *b;
169a747e4fSDavid du Colombier 
1711c9ee8bSDavid du Colombier 	if(validatefile(id) == nil || strcmp(id,".") == 0)
1811c9ee8bSDavid du Colombier 		return nil;
1911c9ee8bSDavid du Colombier 	fn = emalloc(nfn);
209a747e4fSDavid du Colombier 	snprint(fn, nfn, "%s/who/%s", SECSTORE_DIR, id);
219a747e4fSDavid du Colombier 	b = Bopen(fn, mode);
229a747e4fSDavid du Colombier 	free(fn);
239a747e4fSDavid du Colombier 	return b;
249a747e4fSDavid du Colombier }
259a747e4fSDavid du Colombier 
269a747e4fSDavid du Colombier static ulong
mtimePW(char * id)279a747e4fSDavid du Colombier mtimePW(char *id)
289a747e4fSDavid du Colombier {
299a747e4fSDavid du Colombier 	ulong mt;
30*7e18f042SDavid du Colombier 	char *fn;
31*7e18f042SDavid du Colombier 	Dir *d;
329a747e4fSDavid du Colombier 
33*7e18f042SDavid du Colombier 	fn = smprint("%s/who/%s", SECSTORE_DIR, id);
349a747e4fSDavid du Colombier 	d = dirstat(fn);
35*7e18f042SDavid du Colombier 	mt = (d? d->mtime: 0);
369a747e4fSDavid du Colombier 	free(d);
37*7e18f042SDavid du Colombier 	free(fn);
389a747e4fSDavid du Colombier 	return mt;
399a747e4fSDavid du Colombier }
409a747e4fSDavid du Colombier 
419a747e4fSDavid du Colombier PW *
getPW(char * id,int dead_or_alive)42369036d9SDavid du Colombier getPW(char *id, int dead_or_alive)
439a747e4fSDavid du Colombier {
44*7e18f042SDavid du Colombier 	ulong now = time(0);
45*7e18f042SDavid du Colombier 	char *f1, *f2, *oid;		/* fields 1, 2 = attribute, value */
469a747e4fSDavid du Colombier 	Biobuf *bin;
479a747e4fSDavid du Colombier 	PW *pw;
489a747e4fSDavid du Colombier 
49*7e18f042SDavid du Colombier 	oid = id;
509a747e4fSDavid du Colombier 	if((bin = openPW(id, OREAD)) == 0){
51be0c1e85SDavid du Colombier 		id = "FICTITIOUS";
52be0c1e85SDavid du Colombier 		if((bin = openPW(id, OREAD)) == 0){
53*7e18f042SDavid du Colombier 			werrstr("accounts %s and FICTITIOUS do not exist", oid);
549a747e4fSDavid du Colombier 			return nil;
559a747e4fSDavid du Colombier 		}
56be0c1e85SDavid du Colombier 	}
57*7e18f042SDavid du Colombier 	pw = emalloc(sizeof *pw);
589a747e4fSDavid du Colombier 	pw->id = estrdup(id);
599a747e4fSDavid du Colombier 	pw->status |= Enabled;
609a747e4fSDavid du Colombier 	while( (f1 = Brdline(bin, '\n')) != 0){
619a747e4fSDavid du Colombier 		f1[Blinelen(bin)-1] = 0;
62*7e18f042SDavid du Colombier 		for(f2 = f1; *f2 && *f2 != ' ' && *f2 != '\t'; f2++)
63*7e18f042SDavid du Colombier 			;
649a747e4fSDavid du Colombier 		if(*f2)
65*7e18f042SDavid du Colombier 			for(*f2++ = 0; *f2 && (*f2==' ' || *f2=='\t'); f2++)
66*7e18f042SDavid du Colombier 				;
67*7e18f042SDavid du Colombier 		if(strcmp(f1, "exp") == 0)
689a747e4fSDavid du Colombier 			pw->expire = strtoul(f2, 0, 10);
69*7e18f042SDavid du Colombier 		else if(strcmp(f1, "DISABLED") == 0)
709a747e4fSDavid du Colombier 			pw->status &= ~Enabled;
71*7e18f042SDavid du Colombier 		else if(strcmp(f1, "STA") == 0)
729a747e4fSDavid du Colombier 			pw->status |= STA;
73*7e18f042SDavid du Colombier 		else if(strcmp(f1, "failed") == 0)
749a747e4fSDavid du Colombier 			pw->failed = strtoul(f2, 0, 10);
75*7e18f042SDavid du Colombier 		else if(strcmp(f1, "other") == 0)
769a747e4fSDavid du Colombier 			pw->other = estrdup(f2);
77*7e18f042SDavid du Colombier 		else if(strcmp(f1, "PAK-Hi") == 0)
789a747e4fSDavid du Colombier 			pw->Hi = strtomp(f2, nil, 64, nil);
799a747e4fSDavid du Colombier 	}
809a747e4fSDavid du Colombier 	Bterm(bin);
8111c9ee8bSDavid du Colombier 	if(pw->Hi == nil){
82*7e18f042SDavid du Colombier 		werrstr("corrupted account file for %s", pw->id);
8311c9ee8bSDavid du Colombier 		freePW(pw);
8411c9ee8bSDavid du Colombier 		return nil;
8511c9ee8bSDavid du Colombier 	}
86369036d9SDavid du Colombier 	if(dead_or_alive)
87*7e18f042SDavid du Colombier 		return pw;  /* return for editing, whether valid now or not */
88*7e18f042SDavid du Colombier 	if(pw->expire != 0 && pw->expire <= now){
89*7e18f042SDavid du Colombier 		/* %.28s excludes ctime's newline */
90*7e18f042SDavid du Colombier 		werrstr("account %s expired at %.28s", pw->id,
91*7e18f042SDavid du Colombier 			ctime(pw->expire));
929a747e4fSDavid du Colombier 		freePW(pw);
939a747e4fSDavid du Colombier 		return nil;
949a747e4fSDavid du Colombier 	}
95369036d9SDavid du Colombier 	if((pw->status & Enabled) == 0){
96*7e18f042SDavid du Colombier 		werrstr("account %s disabled", pw->id);
979a747e4fSDavid du Colombier 		freePW(pw);
989a747e4fSDavid du Colombier 		return nil;
999a747e4fSDavid du Colombier 	}
1009a747e4fSDavid du Colombier 	if(pw->failed < 10)
101*7e18f042SDavid du Colombier 		return pw;	/* success */
1029a747e4fSDavid du Colombier 	if(now < mtimePW(id)+300){
1035d459b5aSDavid du Colombier 		werrstr("too many failures; try again in five minutes");
1049a747e4fSDavid du Colombier 		freePW(pw);
1059a747e4fSDavid du Colombier 		return nil;
1069a747e4fSDavid du Colombier 	}
1079a747e4fSDavid du Colombier 	pw->failed = 0;
108*7e18f042SDavid du Colombier 	putPW(pw);	/* reset failed-login-counter after five minutes */
1099a747e4fSDavid du Colombier 	return pw;
1109a747e4fSDavid du Colombier }
1119a747e4fSDavid du Colombier 
1129a747e4fSDavid du Colombier int
putPW(PW * pw)1139a747e4fSDavid du Colombier putPW(PW *pw)
1149a747e4fSDavid du Colombier {
1159a747e4fSDavid du Colombier 	Biobuf *bout;
1169a747e4fSDavid du Colombier 	char *hexHi;
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier 	if((bout = openPW(pw->id, OWRITE|OTRUNC)) ==0){
119*7e18f042SDavid du Colombier 		werrstr("can't open PW file for %s", pw->id);
1209a747e4fSDavid du Colombier 		return -1;
1219a747e4fSDavid du Colombier 	}
1229a747e4fSDavid du Colombier 	Bprint(bout, "exp	%lud\n", pw->expire);
1239a747e4fSDavid du Colombier 	if(!(pw->status & Enabled))
1249a747e4fSDavid du Colombier 		Bprint(bout, "DISABLED\n");
1259a747e4fSDavid du Colombier 	if(pw->status & STA)
1269a747e4fSDavid du Colombier 		Bprint(bout, "STA\n");
1279a747e4fSDavid du Colombier 	if(pw->failed)
1289a747e4fSDavid du Colombier 		Bprint(bout, "failed\t%d\n", pw->failed);
1299a747e4fSDavid du Colombier 	if(pw->other)
1309a747e4fSDavid du Colombier 		Bprint(bout,"other\t%s\n", pw->other);
1319a747e4fSDavid du Colombier 	hexHi = mptoa(pw->Hi, 64, nil, 0);
1329a747e4fSDavid du Colombier 	Bprint(bout, "PAK-Hi\t%s\n", hexHi);
1339a747e4fSDavid du Colombier 	free(hexHi);
1349a747e4fSDavid du Colombier 	return 0;
1359a747e4fSDavid du Colombier }
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier void
freePW(PW * pw)1389a747e4fSDavid du Colombier freePW(PW *pw)
1399a747e4fSDavid du Colombier {
1409a747e4fSDavid du Colombier 	if(pw == nil)
1419a747e4fSDavid du Colombier 		return;
1429a747e4fSDavid du Colombier 	free(pw->id);
1439a747e4fSDavid du Colombier 	free(pw->other);
1449a747e4fSDavid du Colombier 	mpfree(pw->Hi);
1459a747e4fSDavid du Colombier 	free(pw);
1469a747e4fSDavid du Colombier }
147