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", 0); 265 } 266 execl("/bin/upas/send", "send", "-r", rcvr, 0); 267 268 /* just in case */ 269 fprint(2, "warning can't exec send\n"); 270 exits("exec send"); 271 272 return 0; /* for compiler */ 273 } 274 275 void 276 complain(char *fmt, ...) 277 { 278 char buf[8192], *s; 279 va_list arg; 280 281 s = buf; 282 s += sprint(s, "%s: ", argv0); 283 va_start(arg, fmt); 284 s = vseprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, arg); 285 va_end(arg); 286 *s++ = '\n'; 287 write(2, buf, s - buf); 288 } 289 290 long 291 readnumfile(char *file) 292 { 293 int fd, n; 294 char buf[64]; 295 296 fd = open(file, OREAD); 297 if(fd < 0){ 298 complain("can't open %s:r", file); 299 return 0; 300 } 301 n = read(fd, buf, sizeof(buf)-1); 302 close(fd); 303 if(n < 0){ 304 complain("can't read %s:r", file); 305 return 0; 306 } 307 buf[n] = 0; 308 return atol(buf); 309 } 310 311 void 312 writenumfile(char *file, long num) 313 { 314 int fd; 315 316 fd = open(file, OWRITE); 317 if(fd < 0){ 318 complain("can't open %s", file); 319 return; 320 } 321 fprint(fd, "%ld", num); 322 close(fd); 323 } 324