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