xref: /plan9/sys/src/cmd/auth/warning.c (revision f54edc786b9c49b2c7ab1c0695cdc8c698b11f4d)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <auth.h>
5 #include "authcmdlib.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
usage(void)23 usage(void)
24 {
25 	fprint(2, "usage: %s [-n] [-p]\n", argv0);
26 	exits("usage");
27 }
28 
29 void
main(int argc,char ** argv)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
dodir(Fs * f)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 = dirreadall(fd, &dirbuf);
74 	close(fd);
75 	for(i = 0; i < nfiles; i++)
76 		douser(f, dirbuf[i].name);
77 }
78 
79 /*
80  *  check for expiration
81  */
82 void
douser(Fs * f,char * user)83 douser(Fs *f, char *user)
84 {
85 	int n, nwarn;
86 	char buf[128];
87 	long rcvrs, et, now;
88 	char *l;
89 
90 	snprint(buf, sizeof buf, "%s/expire", user);
91 	et = readnumfile(buf);
92 	now = time(0);
93 
94 	/* start warning 2 weeks ahead of time */
95 	if(et <= now || et > now+14*24*60*60)
96 		return;
97 
98 	snprint(buf, sizeof buf, "%s/warnings", user);
99 	nwarn = readnumfile(buf);
100 	if(et <= now+14*24*60*60 && et > now+7*24*60*60){
101 		/* one warning 2 weeks before expiration */
102 		if(nwarn > 0)
103 			return;
104 		nwarn = 1;
105 	} else {
106 		/* one warning 1 week before expiration */
107 		if(nwarn > 1)
108 			return;
109 		nwarn = 2;
110 	}
111 
112 	/*
113 	 *  if we can't open the who file, just mail to the user and hope
114  	 *  for it makes it.
115 	 */
116 	if(f->b){
117 		if(Bseek(f->b, 0, 0) < 0){
118 			Bterm(f->b);
119 			f->b = 0;
120 		}
121 	}
122 	if(f->b == 0){
123 		f->b = Bopen(f->who, OREAD);
124 		if(f->b == 0){
125 			if(mail(f, user, user, et) > 0)
126 				writenumfile(buf, nwarn);
127 			return;
128 		}
129 	}
130 
131 	/*
132 	 *  look for matches in the who file and mail to every address on
133 	 *  matching lines
134 	 */
135 	rcvrs = 0;
136 	while(l = Brdline(f->b, '\n')){
137 		n = strlen(user);
138 		if(strncmp(l, user, n) == 0 && (l[n] == ' ' || l[n] == '\t'))
139 			rcvrs += mailin(f, user, et, l, l+Blinelen(f->b));
140 	}
141 
142 	/*
143 	 *  if no matches, try the user directly
144 	 */
145 	if(rcvrs == 0)
146 		rcvrs = mail(f, user, user, et);
147 	rcvrs += mail(f, "netkeys", user, et);
148 	if(rcvrs)
149 		writenumfile(buf, nwarn);
150 }
151 
152 /*
153  *  anything in <>'s is an address
154  */
155 int
mailin(Fs * f,char * user,long et,char * l,char * e)156 mailin(Fs *f, char *user, long et, char *l, char *e)
157 {
158 	int n;
159 	int rcvrs;
160 	char *p;
161 	char addr[256];
162 
163 	p = 0;
164 	rcvrs = 0;
165 	while(l < e){
166 		switch(*l){
167 		case '<':
168 			p = l + 1;
169 			break;
170 		case '>':
171 			if(p == 0)
172 				break;
173 			n = l - p;
174 			if(n > 0 && n <= sizeof(addr) - 2){
175 				memmove(addr, p, n);
176 				addr[n] = 0;
177 				rcvrs += mail(f, addr, user, et);
178 			}
179 			p = 0;
180 			break;
181 		}
182 		l++;
183 	}
184 	return rcvrs;
185 }
186 
187 /*
188  *  send mail
189  */
190 int
mail(Fs * f,char * rcvr,char * user,long et)191 mail(Fs *f, char *rcvr, char *user, long et)
192 {
193 	int pid, i, fd;
194 	int pfd[2];
195 	char *ct, *p;
196 	Waitmsg *w;
197 	char buf[128];
198 
199 	if(pipe(pfd) < 0){
200 		complain("out of pipes: %r");
201 		return 0;
202 	}
203 
204 	switch(pid = fork()){
205 	case -1:
206 		complain("can't fork: %r");
207 		return 0;
208 	case 0:
209 		break;
210 	default:
211 		if(debug)
212 			fprint(2, "started %d\n", pid);
213 		close(pfd[0]);
214 		ct = ctime(et);
215 		p = strchr(ct, '\n');
216 		*p = '.';
217 		fprint(pfd[1], "User '%s's %s expires on %s\n", user, f->msg, ct);
218 		if(f != fs)
219 			fprint(pfd[1], "If you wish to renew contact your local administrator.\n");
220 		p = strrchr(f->keys, '/');
221 		if(p)
222 			p++;
223 		else
224 			p = f->keys;
225 		snprint(buf, sizeof buf, "/adm/warn.%s", p);
226 		fd = open(buf, OREAD);
227 		if(fd >= 0){
228 			while((i = read(fd, buf, sizeof(buf))) > 0)
229 				write(pfd[1], buf, i);
230 			close(fd);
231 		}
232 		close(pfd[1]);
233 
234 		/* wait for warning to be mailed */
235 		for(;;){
236 			w = wait();
237 			if(w == nil)
238 				break;
239 			if(w->pid == pid){
240 				if(debug)
241 					fprint(2, "%d terminated: %s\n", pid, w->msg);
242 				if(w->msg[0] == 0){
243 					free(w);
244 					break;
245 				}else{
246 					free(w);
247 					return 0;
248 				}
249 			}else
250 				free(w);
251 		}
252 		return 1;
253 	}
254 
255 	/* get out of the current namespace */
256 	newns("none", 0);
257 
258 	dup(pfd[0], 0);
259 	close(pfd[0]);
260 	close(pfd[1]);
261 	putenv("upasname", "netkeys");
262 	if(debug){
263 		print("\nto %s\n", rcvr);
264 		execl("/bin/cat", "cat", nil);
265 	}
266 	execl("/bin/upas/send", "send", "-r", rcvr, nil);
267 
268 	/* just in case */
269 	sysfatal("can't exec send: %r");
270 
271 	return 0;		/* for compiler */
272 }
273 
274 void
complain(char * fmt,...)275 complain(char *fmt, ...)
276 {
277 	char buf[8192], *s;
278 	va_list arg;
279 
280 	s = buf;
281 	s += snprint(s, sizeof buf, "%s: ", argv0);
282 	va_start(arg, fmt);
283 	s = vseprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, arg);
284 	va_end(arg);
285 	*s++ = '\n';
286 	write(2, buf, s - buf);
287 }
288 
289 long
readnumfile(char * file)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: %r", 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: %r", file);
304 		return 0;
305 	}
306 	buf[n] = 0;
307 	return atol(buf);
308 }
309 
310 void
writenumfile(char * file,long num)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: %r", file);
318 		return;
319 	}
320 	fprint(fd, "%ld", num);
321 	close(fd);
322 }
323