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