xref: /plan9/sys/src/cmd/auth/warning.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include <u.h>
2*219b2ee8SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <bio.h>
4*219b2ee8SDavid du Colombier #include <auth.h>
5*219b2ee8SDavid du Colombier #include "authsrv.h"
6*219b2ee8SDavid du Colombier 
7*219b2ee8SDavid du Colombier /* working directory */
8*219b2ee8SDavid du Colombier Dir	*dirbuf;
9*219b2ee8SDavid du Colombier long	ndirbuf = 0;
10*219b2ee8SDavid du Colombier 
11*219b2ee8SDavid du Colombier int debug;
12*219b2ee8SDavid du Colombier 
13*219b2ee8SDavid du Colombier long	readdirect(int);
14*219b2ee8SDavid du Colombier void	douser(Fs*, char*);
15*219b2ee8SDavid du Colombier void	dodir(Fs*);
16*219b2ee8SDavid du Colombier int	mail(Fs*, char*, char*, long);
17*219b2ee8SDavid du Colombier int	mailin(Fs*, char*, long, char*, char*);
18*219b2ee8SDavid du Colombier void	complain(char*, ...);
19*219b2ee8SDavid du Colombier long	readnumfile(char*);
20*219b2ee8SDavid du Colombier void	writenumfile(char*, long);
21*219b2ee8SDavid du Colombier 
22*219b2ee8SDavid du Colombier void
23*219b2ee8SDavid du Colombier usage(void)
24*219b2ee8SDavid du Colombier {
25*219b2ee8SDavid du Colombier 	fprint(2, "usage: %s [-n] [-p]\n");
26*219b2ee8SDavid du Colombier 	exits("usage");
27*219b2ee8SDavid du Colombier }
28*219b2ee8SDavid du Colombier 
29*219b2ee8SDavid du Colombier void
30*219b2ee8SDavid du Colombier main(int argc, char **argv)
31*219b2ee8SDavid du Colombier {
32*219b2ee8SDavid du Colombier 	int which;
33*219b2ee8SDavid du Colombier 
34*219b2ee8SDavid du Colombier 	which = 0;
35*219b2ee8SDavid du Colombier 	ARGBEGIN{
36*219b2ee8SDavid du Colombier 	case 'p':
37*219b2ee8SDavid du Colombier 		which |= Plan9;
38*219b2ee8SDavid du Colombier 		break;
39*219b2ee8SDavid du Colombier 	case 'n':
40*219b2ee8SDavid du Colombier 		which |= Securenet;
41*219b2ee8SDavid du Colombier 		break;
42*219b2ee8SDavid du Colombier 	case 'd':
43*219b2ee8SDavid du Colombier 		debug++;
44*219b2ee8SDavid du Colombier 		break;
45*219b2ee8SDavid du Colombier 	default:
46*219b2ee8SDavid du Colombier 		usage();
47*219b2ee8SDavid du Colombier 	}ARGEND
48*219b2ee8SDavid du Colombier 	argv0 = "warning";
49*219b2ee8SDavid du Colombier 
50*219b2ee8SDavid du Colombier 	if(!which)
51*219b2ee8SDavid du Colombier 		which |= Plan9 | Securenet;
52*219b2ee8SDavid du Colombier 	if(which & Plan9)
53*219b2ee8SDavid du Colombier 		dodir(&fs[Plan9]);
54*219b2ee8SDavid du Colombier 	if(which & Securenet)
55*219b2ee8SDavid du Colombier 		dodir(&fs[Securenet]);
56*219b2ee8SDavid du Colombier }
57*219b2ee8SDavid du Colombier 
58*219b2ee8SDavid du Colombier void
59*219b2ee8SDavid du Colombier dodir(Fs *f)
60*219b2ee8SDavid du Colombier {
61*219b2ee8SDavid du Colombier 	int nfiles;
62*219b2ee8SDavid du Colombier 	int i, fd;
63*219b2ee8SDavid du Colombier 
64*219b2ee8SDavid du Colombier 	if(chdir(f->keys) < 0){
65*219b2ee8SDavid du Colombier 		complain("can't chdir to %s: %r", f->keys);
66*219b2ee8SDavid du Colombier 		return;
67*219b2ee8SDavid du Colombier 	}
68*219b2ee8SDavid du Colombier  	fd = open(".", OREAD);
69*219b2ee8SDavid du Colombier 	if(fd < 0){
70*219b2ee8SDavid du Colombier 		complain("can't open %s: %r\n", f->keys);
71*219b2ee8SDavid du Colombier 		return;
72*219b2ee8SDavid du Colombier 	}
73*219b2ee8SDavid du Colombier 	nfiles = readdirect(fd);
74*219b2ee8SDavid du Colombier 	close(fd);
75*219b2ee8SDavid du Colombier 	for(i = 0; i < nfiles; i++)
76*219b2ee8SDavid du Colombier 		douser(f, dirbuf[i].name);
77*219b2ee8SDavid du Colombier }
78*219b2ee8SDavid du Colombier 
79*219b2ee8SDavid du Colombier /*
80*219b2ee8SDavid du Colombier  * Read a whole directory before doing anything.
81*219b2ee8SDavid du Colombier  */
82*219b2ee8SDavid du Colombier long
83*219b2ee8SDavid du Colombier readdirect(int fd)
84*219b2ee8SDavid du Colombier {
85*219b2ee8SDavid du Colombier 	enum
86*219b2ee8SDavid du Colombier 	{
87*219b2ee8SDavid du Colombier 		N = 32
88*219b2ee8SDavid du Colombier 	};
89*219b2ee8SDavid du Colombier 	long m, n;
90*219b2ee8SDavid du Colombier 
91*219b2ee8SDavid du Colombier 	m = 1;	/* prime the loop */
92*219b2ee8SDavid du Colombier 	for(n=0; m>0; n+=m/sizeof(Dir)){
93*219b2ee8SDavid du Colombier 		if(n == ndirbuf){
94*219b2ee8SDavid du Colombier 			dirbuf = realloc(dirbuf, (ndirbuf+N)*sizeof(Dir));
95*219b2ee8SDavid du Colombier 			if(dirbuf == 0)
96*219b2ee8SDavid du Colombier 				error("memory allocation");
97*219b2ee8SDavid du Colombier 			ndirbuf += N;
98*219b2ee8SDavid du Colombier 		}
99*219b2ee8SDavid du Colombier 		m = dirread(fd, dirbuf+n, (ndirbuf-n)*sizeof(Dir));
100*219b2ee8SDavid du Colombier 	}
101*219b2ee8SDavid du Colombier 	return n;
102*219b2ee8SDavid du Colombier }
103*219b2ee8SDavid du Colombier 
104*219b2ee8SDavid du Colombier /*
105*219b2ee8SDavid du Colombier  *  check for expiration
106*219b2ee8SDavid du Colombier  */
107*219b2ee8SDavid du Colombier void
108*219b2ee8SDavid du Colombier douser(Fs *f, char *user)
109*219b2ee8SDavid du Colombier {
110*219b2ee8SDavid du Colombier 	int n, nwarn;
111*219b2ee8SDavid du Colombier 	char buf[2*NAMELEN+2];
112*219b2ee8SDavid du Colombier 	long rcvrs, et, now;
113*219b2ee8SDavid du Colombier 	char *l;
114*219b2ee8SDavid du Colombier 
115*219b2ee8SDavid du Colombier 	sprint(buf, "%s/expire", user);
116*219b2ee8SDavid du Colombier 	et = readnumfile(buf);
117*219b2ee8SDavid du Colombier 	now = time(0);
118*219b2ee8SDavid du Colombier 
119*219b2ee8SDavid du Colombier 	/* start warning 2 weeks ahead of time */
120*219b2ee8SDavid du Colombier 	if(et <= now || et > now+14*24*60*60)
121*219b2ee8SDavid du Colombier 		return;
122*219b2ee8SDavid du Colombier 
123*219b2ee8SDavid du Colombier 	sprint(buf, "%s/warnings", user);
124*219b2ee8SDavid du Colombier 	nwarn = readnumfile(buf);
125*219b2ee8SDavid du Colombier 	if(et <= now+14*24*60*60 && et > now+7*24*60*60){
126*219b2ee8SDavid du Colombier 		/* one warning 2 weeks before expiration */
127*219b2ee8SDavid du Colombier 		if(nwarn > 0)
128*219b2ee8SDavid du Colombier 			return;
129*219b2ee8SDavid du Colombier 		nwarn = 1;
130*219b2ee8SDavid du Colombier 	} else {
131*219b2ee8SDavid du Colombier 		/* one warning 1 week before expiration */
132*219b2ee8SDavid du Colombier 		if(nwarn > 1)
133*219b2ee8SDavid du Colombier 			return;
134*219b2ee8SDavid du Colombier 		nwarn = 2;
135*219b2ee8SDavid du Colombier 	}
136*219b2ee8SDavid du Colombier 
137*219b2ee8SDavid du Colombier 	/*
138*219b2ee8SDavid du Colombier 	 *  if we can't open the who file, just mail to the user and hope
139*219b2ee8SDavid du Colombier  	 *  for it makes it.
140*219b2ee8SDavid du Colombier 	 */
141*219b2ee8SDavid du Colombier 	if(f->b){
142*219b2ee8SDavid du Colombier 		if(Bseek(f->b, 0, 0) < 0){
143*219b2ee8SDavid du Colombier 			Bterm(f->b);
144*219b2ee8SDavid du Colombier 			f->b = 0;
145*219b2ee8SDavid du Colombier 		}
146*219b2ee8SDavid du Colombier 	}
147*219b2ee8SDavid du Colombier 	if(f->b == 0){
148*219b2ee8SDavid du Colombier 		f->b = Bopen(f->who, OREAD);
149*219b2ee8SDavid du Colombier 		if(f->b == 0){
150*219b2ee8SDavid du Colombier 			if(mail(f, user, user, et) > 0)
151*219b2ee8SDavid du Colombier 				writenumfile(buf, nwarn);
152*219b2ee8SDavid du Colombier 			return;
153*219b2ee8SDavid du Colombier 		}
154*219b2ee8SDavid du Colombier 	}
155*219b2ee8SDavid du Colombier 
156*219b2ee8SDavid du Colombier 	/*
157*219b2ee8SDavid du Colombier 	 *  look for matches in the who file and mail to every address on
158*219b2ee8SDavid du Colombier 	 *  matching lines
159*219b2ee8SDavid du Colombier 	 */
160*219b2ee8SDavid du Colombier 	rcvrs = 0;
161*219b2ee8SDavid du Colombier 	while(l = Brdline(f->b, '\n')){
162*219b2ee8SDavid du Colombier 		n = strlen(user);
163*219b2ee8SDavid du Colombier 		if(strncmp(l, user, n) == 0 && (l[n] == ' ' || l[n] == '\t'))
164*219b2ee8SDavid du Colombier 			rcvrs += mailin(f, user, et, l, l+Blinelen(f->b));
165*219b2ee8SDavid du Colombier 	}
166*219b2ee8SDavid du Colombier 
167*219b2ee8SDavid du Colombier 	/*
168*219b2ee8SDavid du Colombier 	 *  if no matches, try the user directly
169*219b2ee8SDavid du Colombier 	 */
170*219b2ee8SDavid du Colombier 	if(rcvrs == 0)
171*219b2ee8SDavid du Colombier 		rcvrs = mail(f, user, user, et);
172*219b2ee8SDavid du Colombier 	rcvrs += mail(f, "netkeys", user, et);
173*219b2ee8SDavid du Colombier 	if(rcvrs)
174*219b2ee8SDavid du Colombier 		writenumfile(buf, nwarn);
175*219b2ee8SDavid du Colombier }
176*219b2ee8SDavid du Colombier 
177*219b2ee8SDavid du Colombier /*
178*219b2ee8SDavid du Colombier  *  anything in <>'s is an address
179*219b2ee8SDavid du Colombier  */
180*219b2ee8SDavid du Colombier int
181*219b2ee8SDavid du Colombier mailin(Fs *f, char *user, long et, char *l, char *e)
182*219b2ee8SDavid du Colombier {
183*219b2ee8SDavid du Colombier 	int n;
184*219b2ee8SDavid du Colombier 	int rcvrs;
185*219b2ee8SDavid du Colombier 	char *p;
186*219b2ee8SDavid du Colombier 	char addr[256];
187*219b2ee8SDavid du Colombier 
188*219b2ee8SDavid du Colombier 	p = 0;
189*219b2ee8SDavid du Colombier 	rcvrs = 0;
190*219b2ee8SDavid du Colombier 	while(l < e){
191*219b2ee8SDavid du Colombier 		switch(*l){
192*219b2ee8SDavid du Colombier 		case '<':
193*219b2ee8SDavid du Colombier 			p = l + 1;
194*219b2ee8SDavid du Colombier 			break;
195*219b2ee8SDavid du Colombier 		case '>':
196*219b2ee8SDavid du Colombier 			if(p == 0)
197*219b2ee8SDavid du Colombier 				break;
198*219b2ee8SDavid du Colombier 			n = l - p;
199*219b2ee8SDavid du Colombier 			if(n > 0 && n <= sizeof(addr) - 2){
200*219b2ee8SDavid du Colombier 				memmove(addr, p, n);
201*219b2ee8SDavid du Colombier 				addr[n] = 0;
202*219b2ee8SDavid du Colombier 				rcvrs += mail(f, addr, user, et);
203*219b2ee8SDavid du Colombier 			}
204*219b2ee8SDavid du Colombier 			p = 0;
205*219b2ee8SDavid du Colombier 			break;
206*219b2ee8SDavid du Colombier 		}
207*219b2ee8SDavid du Colombier 		l++;
208*219b2ee8SDavid du Colombier 	}
209*219b2ee8SDavid du Colombier 	return rcvrs;
210*219b2ee8SDavid du Colombier }
211*219b2ee8SDavid du Colombier 
212*219b2ee8SDavid du Colombier /*
213*219b2ee8SDavid du Colombier  *  send mail
214*219b2ee8SDavid du Colombier  */
215*219b2ee8SDavid du Colombier int
216*219b2ee8SDavid du Colombier mail(Fs *f, char *rcvr, char *user, long et)
217*219b2ee8SDavid du Colombier {
218*219b2ee8SDavid du Colombier 	int pid, i;
219*219b2ee8SDavid du Colombier 	int pfd[2];
220*219b2ee8SDavid du Colombier 	char *ct, *p;
221*219b2ee8SDavid du Colombier 	Waitmsg w;
222*219b2ee8SDavid du Colombier 
223*219b2ee8SDavid du Colombier 	if(pipe(pfd) < 0){
224*219b2ee8SDavid du Colombier 		complain("out of pipes: %r");
225*219b2ee8SDavid du Colombier 		return 0;
226*219b2ee8SDavid du Colombier 	}
227*219b2ee8SDavid du Colombier 
228*219b2ee8SDavid du Colombier 	switch(pid = rfork(RFPROC|RFNAMEG|RFNOTEG|RFENVG|RFFDG)){
229*219b2ee8SDavid du Colombier 	case -1:
230*219b2ee8SDavid du Colombier 		complain("can't fork: %r");
231*219b2ee8SDavid du Colombier 		return 0;
232*219b2ee8SDavid du Colombier 	case 0:
233*219b2ee8SDavid du Colombier 		break;
234*219b2ee8SDavid du Colombier 	default:
235*219b2ee8SDavid du Colombier 		close(pfd[0]);
236*219b2ee8SDavid du Colombier 		ct = ctime(et);
237*219b2ee8SDavid du Colombier 		p = strchr(ct, '\n');
238*219b2ee8SDavid du Colombier 		*p = '.';
239*219b2ee8SDavid du Colombier 		fprint(pfd[1], "User '%s's %s expires on %s\n", user, f->msg, ct);
240*219b2ee8SDavid du Colombier 		if(f != fs)
241*219b2ee8SDavid du Colombier 			fprint(pfd[1], "If you wish to renew contact your local administrator.\n");
242*219b2ee8SDavid du Colombier 		close(pfd[1]);
243*219b2ee8SDavid du Colombier 
244*219b2ee8SDavid du Colombier 		for(;;){
245*219b2ee8SDavid du Colombier 			i = wait(&w);
246*219b2ee8SDavid du Colombier 			if(i < 0)
247*219b2ee8SDavid du Colombier 				break;
248*219b2ee8SDavid du Colombier 			if(i == pid){
249*219b2ee8SDavid du Colombier 				if(w.msg[0] == 0)
250*219b2ee8SDavid du Colombier 					break;
251*219b2ee8SDavid du Colombier 				else
252*219b2ee8SDavid du Colombier 					return 0;
253*219b2ee8SDavid du Colombier 			}
254*219b2ee8SDavid du Colombier 		}
255*219b2ee8SDavid du Colombier 		return 1;
256*219b2ee8SDavid du Colombier 	}
257*219b2ee8SDavid du Colombier 
258*219b2ee8SDavid du Colombier 	/* get out of the current namespace */
259*219b2ee8SDavid du Colombier 	newns("none", 0);
260*219b2ee8SDavid du Colombier 
261*219b2ee8SDavid du Colombier 	dup(pfd[0], 0);
262*219b2ee8SDavid du Colombier 	close(pfd[0]);
263*219b2ee8SDavid du Colombier 	close(pfd[1]);
264*219b2ee8SDavid du Colombier 	putenv("upasname", "netkeys");
265*219b2ee8SDavid du Colombier 	if(debug){
266*219b2ee8SDavid du Colombier 		print("\nto %s\n", rcvr);
267*219b2ee8SDavid du Colombier 		execl("/bin/cat", "cat", 0);
268*219b2ee8SDavid du Colombier 	}
269*219b2ee8SDavid du Colombier 	execl("/bin/upas/sendmail", "sendmail", rcvr, 0);
270*219b2ee8SDavid du Colombier 
271*219b2ee8SDavid du Colombier 	/* just in case */
272*219b2ee8SDavid du Colombier 	error("can't exec /bin/upas/sendmail");
273*219b2ee8SDavid du Colombier 
274*219b2ee8SDavid du Colombier 	return 0;		/* for compiler */
275*219b2ee8SDavid du Colombier }
276*219b2ee8SDavid du Colombier 
277*219b2ee8SDavid du Colombier void
278*219b2ee8SDavid du Colombier complain(char *fmt, ...)
279*219b2ee8SDavid du Colombier {
280*219b2ee8SDavid du Colombier 	char buf[8192], *s;
281*219b2ee8SDavid du Colombier 
282*219b2ee8SDavid du Colombier 	s = buf;
283*219b2ee8SDavid du Colombier 	s += sprint(s, "%s: ", argv0);
284*219b2ee8SDavid du Colombier 	s = doprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, &fmt + 1);
285*219b2ee8SDavid du Colombier 	*s++ = '\n';
286*219b2ee8SDavid du Colombier 	write(2, buf, s - buf);
287*219b2ee8SDavid du Colombier }
288*219b2ee8SDavid du Colombier 
289*219b2ee8SDavid du Colombier long
290*219b2ee8SDavid du Colombier readnumfile(char *file)
291*219b2ee8SDavid du Colombier {
292*219b2ee8SDavid du Colombier 	int fd, n;
293*219b2ee8SDavid du Colombier 	char buf[64];
294*219b2ee8SDavid du Colombier 
295*219b2ee8SDavid du Colombier 	fd = open(file, OREAD);
296*219b2ee8SDavid du Colombier 	if(fd < 0){
297*219b2ee8SDavid du Colombier 		complain("can't open %s", file);
298*219b2ee8SDavid du Colombier 		return 0;
299*219b2ee8SDavid du Colombier 	}
300*219b2ee8SDavid du Colombier 	n = read(fd, buf, sizeof(buf)-1);
301*219b2ee8SDavid du Colombier 	close(fd);
302*219b2ee8SDavid du Colombier 	if(n < 0){
303*219b2ee8SDavid du Colombier 		complain("can't read %s", file);
304*219b2ee8SDavid du Colombier 		return 0;
305*219b2ee8SDavid du Colombier 	}
306*219b2ee8SDavid du Colombier 	buf[n] = 0;
307*219b2ee8SDavid du Colombier 	return atol(buf);
308*219b2ee8SDavid du Colombier }
309*219b2ee8SDavid du Colombier 
310*219b2ee8SDavid du Colombier void
311*219b2ee8SDavid du Colombier writenumfile(char *file, long num)
312*219b2ee8SDavid du Colombier {
313*219b2ee8SDavid du Colombier 	int fd;
314*219b2ee8SDavid du Colombier 
315*219b2ee8SDavid du Colombier 	fd = open(file, OWRITE);
316*219b2ee8SDavid du Colombier 	if(fd < 0){
317*219b2ee8SDavid du Colombier 		complain("can't open %s", file);
318*219b2ee8SDavid du Colombier 		return;
319*219b2ee8SDavid du Colombier 	}
320*219b2ee8SDavid du Colombier 	fprint(fd, "%d", num);
321*219b2ee8SDavid du Colombier 	close(fd);
322*219b2ee8SDavid du Colombier }
323