xref: /plan9/sys/src/cmd/auth/changeuser.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include <u.h>
2*219b2ee8SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <auth.h>
4*219b2ee8SDavid du Colombier #include <ctype.h>
5*219b2ee8SDavid du Colombier #include "authsrv.h"
6*219b2ee8SDavid du Colombier 
7*219b2ee8SDavid du Colombier 
8*219b2ee8SDavid du Colombier void	install(char*, char*, char*, long, int);
9*219b2ee8SDavid du Colombier int	exists (char*, char*);
10*219b2ee8SDavid du Colombier long	getexpiration(char *db, char *u);
11*219b2ee8SDavid du Colombier Tm	getdate(char*);
12*219b2ee8SDavid du Colombier 
13*219b2ee8SDavid du Colombier void
14*219b2ee8SDavid du Colombier usage(void)
15*219b2ee8SDavid du Colombier {
16*219b2ee8SDavid du Colombier 	fprint(2, "usage: changeuser [-hpn] user\n");
17*219b2ee8SDavid du Colombier 	exits("usage");
18*219b2ee8SDavid du Colombier }
19*219b2ee8SDavid du Colombier 
20*219b2ee8SDavid du Colombier void
21*219b2ee8SDavid du Colombier main(int argc, char *argv[])
22*219b2ee8SDavid du Colombier {
23*219b2ee8SDavid du Colombier 	char *u, key[DESKEYLEN], answer[32];
24*219b2ee8SDavid du Colombier 	int which, i, newkey, newbio;
25*219b2ee8SDavid du Colombier 	long t;
26*219b2ee8SDavid du Colombier 	Acctbio a;
27*219b2ee8SDavid du Colombier 	Fs *f;
28*219b2ee8SDavid du Colombier 
29*219b2ee8SDavid du Colombier 	srand(getpid()*time(0));
30*219b2ee8SDavid du Colombier 	fmtinstall('K', keyconv);
31*219b2ee8SDavid du Colombier 
32*219b2ee8SDavid du Colombier 	which = 0;
33*219b2ee8SDavid du Colombier 	ARGBEGIN{
34*219b2ee8SDavid du Colombier 	case 'p':
35*219b2ee8SDavid du Colombier 		which |= Plan9;
36*219b2ee8SDavid du Colombier 		break;
37*219b2ee8SDavid du Colombier 	case 'n':
38*219b2ee8SDavid du Colombier 		which |= Securenet;
39*219b2ee8SDavid du Colombier 		break;
40*219b2ee8SDavid du Colombier 	default:
41*219b2ee8SDavid du Colombier 		usage();
42*219b2ee8SDavid du Colombier 	}ARGEND
43*219b2ee8SDavid du Colombier 	argv0 = "changeuser";
44*219b2ee8SDavid du Colombier 
45*219b2ee8SDavid du Colombier 	if(argc != 1)
46*219b2ee8SDavid du Colombier 		usage();
47*219b2ee8SDavid du Colombier 	u = *argv;
48*219b2ee8SDavid du Colombier 	if(memchr(u, '\0', NAMELEN) == 0)
49*219b2ee8SDavid du Colombier 		error("bad user name");
50*219b2ee8SDavid du Colombier 
51*219b2ee8SDavid du Colombier 	if(!which)
52*219b2ee8SDavid du Colombier 		which = Plan9;
53*219b2ee8SDavid du Colombier 
54*219b2ee8SDavid du Colombier 	newbio = 0;
55*219b2ee8SDavid du Colombier 	t = 0;
56*219b2ee8SDavid du Colombier 	a.user = 0;
57*219b2ee8SDavid du Colombier 	if(which & Plan9){
58*219b2ee8SDavid du Colombier 		f = &fs[Plan9];
59*219b2ee8SDavid du Colombier 		newkey = 1;
60*219b2ee8SDavid du Colombier 		if(exists(f->keys, u)){
61*219b2ee8SDavid du Colombier 			readln("assign new password? [y/n]: ", answer, sizeof answer, 0);
62*219b2ee8SDavid du Colombier 			if(answer[0] != 'y' && answer[0] != 'Y')
63*219b2ee8SDavid du Colombier 				newkey = 0;
64*219b2ee8SDavid du Colombier 		}
65*219b2ee8SDavid du Colombier 		if(newkey)
66*219b2ee8SDavid du Colombier 			getpass(key, 1);
67*219b2ee8SDavid du Colombier 		t = getexpiration(f->keys, u);
68*219b2ee8SDavid du Colombier 		install(f->keys, u, key, t, newkey);
69*219b2ee8SDavid du Colombier 		newbio = querybio(f->who, u, &a);
70*219b2ee8SDavid du Colombier 		if(newbio)
71*219b2ee8SDavid du Colombier 			wrbio(f->who, &a);
72*219b2ee8SDavid du Colombier 		print("user %s installed for Plan 9\n", u);
73*219b2ee8SDavid du Colombier 		syslog(0, AUTHLOG, "user %s installed for plan 9", u);
74*219b2ee8SDavid du Colombier 	}
75*219b2ee8SDavid du Colombier 	if(which & Securenet){
76*219b2ee8SDavid du Colombier 		f = &fs[Securenet];
77*219b2ee8SDavid du Colombier 		newkey = 1;
78*219b2ee8SDavid du Colombier 		if(exists(f->keys, u)){
79*219b2ee8SDavid du Colombier 			readln("assign new key? [y/n]: ", answer, sizeof answer, 0);
80*219b2ee8SDavid du Colombier 			if(answer[0] != 'y' && answer[0] != 'Y')
81*219b2ee8SDavid du Colombier 				newkey = 0;
82*219b2ee8SDavid du Colombier 		}
83*219b2ee8SDavid du Colombier 		if(newkey)
84*219b2ee8SDavid du Colombier 			for(i=0; i<DESKEYLEN; i++)
85*219b2ee8SDavid du Colombier 				key[i] = nrand(256);
86*219b2ee8SDavid du Colombier 		if(a.user == 0){
87*219b2ee8SDavid du Colombier 			t = getexpiration(f->keys, u);
88*219b2ee8SDavid du Colombier 			newbio = querybio(f->who, u, &a);
89*219b2ee8SDavid du Colombier 		}
90*219b2ee8SDavid du Colombier 		install(f->keys, u, key, t, newkey);
91*219b2ee8SDavid du Colombier 		if(newbio)
92*219b2ee8SDavid du Colombier 			wrbio(f->who, &a);
93*219b2ee8SDavid du Colombier 		findkey(f->keys, u, key);
94*219b2ee8SDavid du Colombier 		print("user %s: SecureNet key: %K\n", u, key);
95*219b2ee8SDavid du Colombier 		checksum(key, answer);
96*219b2ee8SDavid du Colombier 		print("verify with checksum %s\n", answer);
97*219b2ee8SDavid du Colombier 		print("user %s installed for SecureNet\n", u);
98*219b2ee8SDavid du Colombier 		syslog(0, AUTHLOG, "user %s installed for securenet", u);
99*219b2ee8SDavid du Colombier 	}
100*219b2ee8SDavid du Colombier 	exits(0);
101*219b2ee8SDavid du Colombier }
102*219b2ee8SDavid du Colombier 
103*219b2ee8SDavid du Colombier void
104*219b2ee8SDavid du Colombier install(char *db, char *u, char *key, long t, int newkey)
105*219b2ee8SDavid du Colombier {
106*219b2ee8SDavid du Colombier 	char buf[KEYDBBUF+NAMELEN+6];
107*219b2ee8SDavid du Colombier 	int fd;
108*219b2ee8SDavid du Colombier 
109*219b2ee8SDavid du Colombier 	if(!exists(db, u)){
110*219b2ee8SDavid du Colombier 		sprint(buf, "%s/%s", db, u);
111*219b2ee8SDavid du Colombier 		fd = create(buf, OREAD, 0777|CHDIR);
112*219b2ee8SDavid du Colombier 		if(fd < 0)
113*219b2ee8SDavid du Colombier 			error("can't create user %s: %r", u);
114*219b2ee8SDavid du Colombier 		close(fd);
115*219b2ee8SDavid du Colombier 	}
116*219b2ee8SDavid du Colombier 
117*219b2ee8SDavid du Colombier 	if(newkey){
118*219b2ee8SDavid du Colombier 		sprint(buf, "%s/%s/key", db, u);
119*219b2ee8SDavid du Colombier 		fd = open(buf, OWRITE);
120*219b2ee8SDavid du Colombier 		if(fd < 0 || write(fd, key, DESKEYLEN) != DESKEYLEN)
121*219b2ee8SDavid du Colombier 			error("can't set key: %r");
122*219b2ee8SDavid du Colombier 		close(fd);
123*219b2ee8SDavid du Colombier 	}
124*219b2ee8SDavid du Colombier 
125*219b2ee8SDavid du Colombier 	if(t == 0)
126*219b2ee8SDavid du Colombier 		return;
127*219b2ee8SDavid du Colombier 	sprint(buf, "%s/%s/expire", db, u);
128*219b2ee8SDavid du Colombier 	fd = open(buf, OWRITE);
129*219b2ee8SDavid du Colombier 	if(fd < 0 || fprint(fd, "%d", t) < 0)
130*219b2ee8SDavid du Colombier 		error("can't write expiration time");
131*219b2ee8SDavid du Colombier 	close(fd);
132*219b2ee8SDavid du Colombier }
133*219b2ee8SDavid du Colombier 
134*219b2ee8SDavid du Colombier int
135*219b2ee8SDavid du Colombier exists(char *db, char *u)
136*219b2ee8SDavid du Colombier {
137*219b2ee8SDavid du Colombier 	char buf[KEYDBBUF+NAMELEN+6];
138*219b2ee8SDavid du Colombier 
139*219b2ee8SDavid du Colombier 	sprint(buf, "%s/%s/expire", db, u);
140*219b2ee8SDavid du Colombier 	if(access(buf, OREAD) < 0)
141*219b2ee8SDavid du Colombier 		return 0;
142*219b2ee8SDavid du Colombier 	return 1;
143*219b2ee8SDavid du Colombier }
144*219b2ee8SDavid du Colombier 
145*219b2ee8SDavid du Colombier /*
146*219b2ee8SDavid du Colombier  * get the date in the format yyyymmdd
147*219b2ee8SDavid du Colombier  */
148*219b2ee8SDavid du Colombier Tm
149*219b2ee8SDavid du Colombier getdate(char *d)
150*219b2ee8SDavid du Colombier {
151*219b2ee8SDavid du Colombier 	Tm date;
152*219b2ee8SDavid du Colombier 	int i;
153*219b2ee8SDavid du Colombier 
154*219b2ee8SDavid du Colombier 	date.year = date.mon = date.mday = 0;
155*219b2ee8SDavid du Colombier 	date.hour = date.min = date.sec = 0;
156*219b2ee8SDavid du Colombier 	for(i = 0; i < 8; i++)
157*219b2ee8SDavid du Colombier 		if(!isdigit(d[i]))
158*219b2ee8SDavid du Colombier 			return date;
159*219b2ee8SDavid du Colombier 	date.year = (d[0]-'0')*1000 + (d[1]-'0')*100 + (d[2]-'0')*10 + d[3]-'0';
160*219b2ee8SDavid du Colombier 	date.year -= 1900;
161*219b2ee8SDavid du Colombier 	d += 4;
162*219b2ee8SDavid du Colombier 	date.mon = (d[0]-'0')*10 + d[1]-'0';
163*219b2ee8SDavid du Colombier 	d += 2;
164*219b2ee8SDavid du Colombier 	date.mday = (d[0]-'0')*10 + d[1]-'0';
165*219b2ee8SDavid du Colombier 	return date;
166*219b2ee8SDavid du Colombier }
167*219b2ee8SDavid du Colombier 
168*219b2ee8SDavid du Colombier long
169*219b2ee8SDavid du Colombier getexpiration(char *db, char *u)
170*219b2ee8SDavid du Colombier {
171*219b2ee8SDavid du Colombier 	char buf[32];
172*219b2ee8SDavid du Colombier 	char prompt[128];
173*219b2ee8SDavid du Colombier 	char cdate[32];
174*219b2ee8SDavid du Colombier 	Tm date;
175*219b2ee8SDavid du Colombier 	ulong secs, now, fd;
176*219b2ee8SDavid du Colombier 	int n;
177*219b2ee8SDavid du Colombier 
178*219b2ee8SDavid du Colombier 	/* read current expiration (if any) */
179*219b2ee8SDavid du Colombier 	sprint(buf, "%s/%s/expire", db, u);
180*219b2ee8SDavid du Colombier 	fd = open(buf, OREAD);
181*219b2ee8SDavid du Colombier 	buf[0] = 0;
182*219b2ee8SDavid du Colombier 	if(fd >= 0){
183*219b2ee8SDavid du Colombier 		n = read(fd, buf, sizeof(buf)-1);
184*219b2ee8SDavid du Colombier 		if(n > 0)
185*219b2ee8SDavid du Colombier 			buf[n-1] = 0;
186*219b2ee8SDavid du Colombier 		close(fd);
187*219b2ee8SDavid du Colombier 	}
188*219b2ee8SDavid du Colombier 	secs = 0;
189*219b2ee8SDavid du Colombier 	if(buf[0]){
190*219b2ee8SDavid du Colombier 		if(strncmp(buf, "never", 5)){
191*219b2ee8SDavid du Colombier 			secs = atoi(buf);
192*219b2ee8SDavid du Colombier 			memmove(&date, localtime(secs), sizeof(date));
193*219b2ee8SDavid du Colombier 			sprint(buf, "%4.4d%2.2d%2.2d", date.year+1900, date.mon, date.mday);
194*219b2ee8SDavid du Colombier 		} else
195*219b2ee8SDavid du Colombier 			buf[5] = 0;
196*219b2ee8SDavid du Colombier 	} else
197*219b2ee8SDavid du Colombier 		strcpy(buf, "never");
198*219b2ee8SDavid du Colombier 	sprint(prompt, "Expiration date (YYYYMMDD or never)[return = %s]: ", buf);
199*219b2ee8SDavid du Colombier 
200*219b2ee8SDavid du Colombier 	now = time(0);
201*219b2ee8SDavid du Colombier 	for(;;){
202*219b2ee8SDavid du Colombier 		readln(prompt, cdate, sizeof cdate, 0);
203*219b2ee8SDavid du Colombier 		if(*cdate == 0)
204*219b2ee8SDavid du Colombier 			return secs;
205*219b2ee8SDavid du Colombier 		if(strcmp(cdate, "never") == 0)
206*219b2ee8SDavid du Colombier 			return 0;
207*219b2ee8SDavid du Colombier 		date = getdate(cdate);
208*219b2ee8SDavid du Colombier 		secs = tm2sec(date);
209*219b2ee8SDavid du Colombier 		if(secs > now && secs < now + 2*365*24*60*60)
210*219b2ee8SDavid du Colombier 			break;
211*219b2ee8SDavid du Colombier 		print("expiration time must fall between now and 2 years from now\n");
212*219b2ee8SDavid du Colombier 	}
213*219b2ee8SDavid du Colombier 	return secs;
214*219b2ee8SDavid du Colombier }
215