xref: /plan9/sys/src/cmd/auth/secstore/password.c (revision 7e18f0426d604d0a3448b7b408d9bf716ab433d7)
1 /* password.c */
2 #include <u.h>
3 #include <libc.h>
4 #include <bio.h>
5 #include <mp.h>
6 #include <libsec.h>
7 #include "SConn.h"
8 #include "secstore.h"
9 
10 static Biobuf*
openPW(char * id,int mode)11 openPW(char *id, int mode)
12 {
13 	int nfn = strlen(SECSTORE_DIR)+strlen(id)+20;
14 	char *fn;
15 	Biobuf *b;
16 
17 	if(validatefile(id) == nil || strcmp(id,".") == 0)
18 		return nil;
19 	fn = emalloc(nfn);
20 	snprint(fn, nfn, "%s/who/%s", SECSTORE_DIR, id);
21 	b = Bopen(fn, mode);
22 	free(fn);
23 	return b;
24 }
25 
26 static ulong
mtimePW(char * id)27 mtimePW(char *id)
28 {
29 	ulong mt;
30 	char *fn;
31 	Dir *d;
32 
33 	fn = smprint("%s/who/%s", SECSTORE_DIR, id);
34 	d = dirstat(fn);
35 	mt = (d? d->mtime: 0);
36 	free(d);
37 	free(fn);
38 	return mt;
39 }
40 
41 PW *
getPW(char * id,int dead_or_alive)42 getPW(char *id, int dead_or_alive)
43 {
44 	ulong now = time(0);
45 	char *f1, *f2, *oid;		/* fields 1, 2 = attribute, value */
46 	Biobuf *bin;
47 	PW *pw;
48 
49 	oid = id;
50 	if((bin = openPW(id, OREAD)) == 0){
51 		id = "FICTITIOUS";
52 		if((bin = openPW(id, OREAD)) == 0){
53 			werrstr("accounts %s and FICTITIOUS do not exist", oid);
54 			return nil;
55 		}
56 	}
57 	pw = emalloc(sizeof *pw);
58 	pw->id = estrdup(id);
59 	pw->status |= Enabled;
60 	while( (f1 = Brdline(bin, '\n')) != 0){
61 		f1[Blinelen(bin)-1] = 0;
62 		for(f2 = f1; *f2 && *f2 != ' ' && *f2 != '\t'; f2++)
63 			;
64 		if(*f2)
65 			for(*f2++ = 0; *f2 && (*f2==' ' || *f2=='\t'); f2++)
66 				;
67 		if(strcmp(f1, "exp") == 0)
68 			pw->expire = strtoul(f2, 0, 10);
69 		else if(strcmp(f1, "DISABLED") == 0)
70 			pw->status &= ~Enabled;
71 		else if(strcmp(f1, "STA") == 0)
72 			pw->status |= STA;
73 		else if(strcmp(f1, "failed") == 0)
74 			pw->failed = strtoul(f2, 0, 10);
75 		else if(strcmp(f1, "other") == 0)
76 			pw->other = estrdup(f2);
77 		else if(strcmp(f1, "PAK-Hi") == 0)
78 			pw->Hi = strtomp(f2, nil, 64, nil);
79 	}
80 	Bterm(bin);
81 	if(pw->Hi == nil){
82 		werrstr("corrupted account file for %s", pw->id);
83 		freePW(pw);
84 		return nil;
85 	}
86 	if(dead_or_alive)
87 		return pw;  /* return for editing, whether valid now or not */
88 	if(pw->expire != 0 && pw->expire <= now){
89 		/* %.28s excludes ctime's newline */
90 		werrstr("account %s expired at %.28s", pw->id,
91 			ctime(pw->expire));
92 		freePW(pw);
93 		return nil;
94 	}
95 	if((pw->status & Enabled) == 0){
96 		werrstr("account %s disabled", pw->id);
97 		freePW(pw);
98 		return nil;
99 	}
100 	if(pw->failed < 10)
101 		return pw;	/* success */
102 	if(now < mtimePW(id)+300){
103 		werrstr("too many failures; try again in five minutes");
104 		freePW(pw);
105 		return nil;
106 	}
107 	pw->failed = 0;
108 	putPW(pw);	/* reset failed-login-counter after five minutes */
109 	return pw;
110 }
111 
112 int
putPW(PW * pw)113 putPW(PW *pw)
114 {
115 	Biobuf *bout;
116 	char *hexHi;
117 
118 	if((bout = openPW(pw->id, OWRITE|OTRUNC)) ==0){
119 		werrstr("can't open PW file for %s", pw->id);
120 		return -1;
121 	}
122 	Bprint(bout, "exp	%lud\n", pw->expire);
123 	if(!(pw->status & Enabled))
124 		Bprint(bout, "DISABLED\n");
125 	if(pw->status & STA)
126 		Bprint(bout, "STA\n");
127 	if(pw->failed)
128 		Bprint(bout, "failed\t%d\n", pw->failed);
129 	if(pw->other)
130 		Bprint(bout,"other\t%s\n", pw->other);
131 	hexHi = mptoa(pw->Hi, 64, nil, 0);
132 	Bprint(bout, "PAK-Hi\t%s\n", hexHi);
133 	free(hexHi);
134 	return 0;
135 }
136 
137 void
freePW(PW * pw)138 freePW(PW *pw)
139 {
140 	if(pw == nil)
141 		return;
142 	free(pw->id);
143 	free(pw->other);
144 	mpfree(pw->Hi);
145 	free(pw);
146 }
147