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