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 23 usage(void) 24 { 25 fprint(2, "usage: %s [-n] [-p]\n", argv0); 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 = 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 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 sprint(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 sprint(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 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 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 sprint(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 275 complain(char *fmt, ...) 276 { 277 char buf[8192], *s; 278 va_list arg; 279 280 s = buf; 281 s += sprint(s, "%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 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 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