ref: 04c4a9ca8b06e34a203f7ddacc2263cf2077e1aa
dir: /sys/src/cmd/auth/warning.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <auth.h> #include <authsrv.h> #include "authcmdlib.h" /* working directory */ Dir *dirbuf; long ndirbuf = 0; int debug; long readdirect(int); void douser(Fs*, char*); void dodir(Fs*); int mail(Fs*, char*, char*, long); int mailin(Fs*, char*, long, char*, char*); void complain(char*, ...); long readnumfile(char*); void writenumfile(char*, long); void usage(void) { fprint(2, "usage: %s [-n] [-p]\n", argv0); exits("usage"); } void main(int argc, char **argv) { int which; which = 0; ARGBEGIN{ case 'p': which |= Plan9; break; case 'n': which |= Securenet; break; case 'd': debug++; break; default: usage(); }ARGEND argv0 = "warning"; if(!which) which |= Plan9 | Securenet; if(which & Plan9) dodir(&fs[Plan9]); if(which & Securenet) dodir(&fs[Securenet]); } void dodir(Fs *f) { int nfiles; int i, fd; if(chdir(f->keys) < 0){ complain("can't chdir to %s: %r", f->keys); return; } fd = open(".", OREAD); if(fd < 0){ complain("can't open %s: %r\n", f->keys); return; } nfiles = dirreadall(fd, &dirbuf); close(fd); for(i = 0; i < nfiles; i++) douser(f, dirbuf[i].name); } /* * check for expiration */ void douser(Fs *f, char *user) { int n, nwarn; char buf[128]; long rcvrs, et, now; char *l; sprint(buf, "%s/expire", user); et = readnumfile(buf); now = time(0); /* start warning 2 weeks ahead of time */ if(et <= now || et > now+14*24*60*60) return; sprint(buf, "%s/warnings", user); nwarn = readnumfile(buf); if(et <= now+14*24*60*60 && et > now+7*24*60*60){ /* one warning 2 weeks before expiration */ if(nwarn > 0) return; nwarn = 1; } else { /* one warning 1 week before expiration */ if(nwarn > 1) return; nwarn = 2; } /* * if we can't open the who file, just mail to the user and hope * for it makes it. */ if(f->b){ if(Bseek(f->b, 0, 0) < 0){ Bterm(f->b); f->b = 0; } } if(f->b == 0){ f->b = Bopen(f->who, OREAD); if(f->b == 0){ if(mail(f, user, user, et) > 0) writenumfile(buf, nwarn); return; } } /* * look for matches in the who file and mail to every address on * matching lines */ rcvrs = 0; while(l = Brdline(f->b, '\n')){ n = strlen(user); if(strncmp(l, user, n) == 0 && (l[n] == ' ' || l[n] == '\t')) rcvrs += mailin(f, user, et, l, l+Blinelen(f->b)); } /* * if no matches, try the user directly */ if(rcvrs == 0) rcvrs = mail(f, user, user, et); rcvrs += mail(f, "netkeys", user, et); if(rcvrs) writenumfile(buf, nwarn); } /* * anything in <>'s is an address */ int mailin(Fs *f, char *user, long et, char *l, char *e) { int n; int rcvrs; char *p; char addr[256]; p = 0; rcvrs = 0; while(l < e){ switch(*l){ case '<': p = l + 1; break; case '>': if(p == 0) break; n = l - p; if(n > 0 && n <= sizeof(addr) - 2){ memmove(addr, p, n); addr[n] = 0; rcvrs += mail(f, addr, user, et); } p = 0; break; } l++; } return rcvrs; } /* * send mail */ int mail(Fs *f, char *rcvr, char *user, long et) { int pid, i, fd; int pfd[2]; char *ct, *p; Waitmsg *w; char buf[128]; if(pipe(pfd) < 0){ complain("out of pipes: %r"); return 0; } switch(pid = fork()){ case -1: complain("can't fork: %r"); return 0; case 0: break; default: if(debug) fprint(2, "started %d\n", pid); close(pfd[0]); ct = ctime(et); p = strchr(ct, '\n'); *p = '.'; fprint(pfd[1], "User '%s's %s expires on %s\n", user, f->msg, ct); if(f != fs) fprint(pfd[1], "If you wish to renew contact your local administrator.\n"); p = strrchr(f->keys, '/'); if(p) p++; else p = f->keys; sprint(buf, "/adm/warn.%s", p); fd = open(buf, OREAD); if(fd >= 0){ while((i = read(fd, buf, sizeof(buf))) > 0) write(pfd[1], buf, i); close(fd); } close(pfd[1]); /* wait for warning to be mailed */ for(;;){ w = wait(); if(w == nil) break; if(w->pid == pid){ if(debug) fprint(2, "%d terminated: %s\n", pid, w->msg); if(w->msg[0] == 0){ free(w); break; }else{ free(w); return 0; } }else free(w); } return 1; } /* get out of the current namespace */ newns("none", 0); dup(pfd[0], 0); close(pfd[0]); close(pfd[1]); putenv("upasname", "netkeys"); if(debug){ print("\nto %s\n", rcvr); execl("/bin/cat", "cat", nil); } execl("/bin/upas/send", "send", "-r", rcvr, nil); /* just in case */ sysfatal("can't exec send: %r"); return 0; /* for compiler */ } void complain(char *fmt, ...) { char buf[8192], *s; va_list arg; s = buf; s += sprint(s, "%s: ", argv0); va_start(arg, fmt); s = vseprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, arg); va_end(arg); *s++ = '\n'; write(2, buf, s - buf); } long readnumfile(char *file) { int fd, n; char buf[64]; fd = open(file, OREAD); if(fd < 0){ complain("can't open %s: %r", file); return 0; } n = read(fd, buf, sizeof(buf)-1); close(fd); if(n < 0){ complain("can't read %s: %r", file); return 0; } buf[n] = 0; return atol(buf); } void writenumfile(char *file, long num) { int fd; fd = open(file, OWRITE); if(fd < 0){ complain("can't open %s: %r", file); return; } fprint(fd, "%ld", num); close(fd); }