#include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include "authsrv.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); voidusage(void){ fprint(2, "usage: %s [-n] [-p]\n"); exits("usage");} voidmain(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]);} voiddodir(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 = readdirect(fd); close(fd); for(i = 0; i < nfiles; i++) douser(f, dirbuf[i].name);} /* * Read a whole directory before doing anything. */longreaddirect(int fd){ enum { N = 32 }; long m, n; m = 1; /* prime the loop */ for(n=0; m>0; n+=m/sizeof(Dir)){ if(n == ndirbuf){ dirbuf = realloc(dirbuf, (ndirbuf+N)*sizeof(Dir)); if(dirbuf == 0) error("memory allocation"); ndirbuf += N; } m = dirread(fd, dirbuf+n, (ndirbuf-n)*sizeof(Dir)); } return n;} /* * check for expiration */voiddouser(Fs *f, char *user){ int n, nwarn; char buf[2*NAMELEN+2]; 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 */intmailin(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 */intmail(Fs *f, char *rcvr, char *user, long et){ int pid, i; int pfd[2]; char *ct, *p; Waitmsg w; if(pipe(pfd) < 0){ complain("out of pipes: %r"); return 0; } switch(pid = rfork(RFPROC|RFNAMEG|RFNOTEG|RFENVG|RFFDG)){ case -1: complain("can't fork: %r"); return 0; case 0: break; default: 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"); close(pfd[1]); for(;;){ i = wait(&w); if(i < 0) break; if(i == pid){ if(w.msg[0] == 0) break; else return 0; } } 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", 0); } execl("/bin/upas/sendmail", "sendmail", rcvr, 0); /* just in case */ error("can't exec /bin/upas/sendmail"); return 0; /* for compiler */} voidcomplain(char *fmt, ...){ char buf[8192], *s; s = buf; s += sprint(s, "%s: ", argv0); s = doprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, &fmt + 1); *s++ = '\n'; write(2, buf, s - buf);} longreadnumfile(char *file){ int fd, n; char buf[64]; fd = open(file, OREAD); if(fd < 0){ complain("can't open %s", file); return 0; } n = read(fd, buf, sizeof(buf)-1); close(fd); if(n < 0){ complain("can't read %s", file); return 0; } buf[n] = 0; return atol(buf);} voidwritenumfile(char *file, long num){ int fd; fd = open(file, OWRITE); if(fd < 0){ complain("can't open %s", file); return; } fprint(fd, "%d", num); close(fd);}
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <auth.h>
#include "authsrv.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");
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 = readdirect(fd);
close(fd);
for(i = 0; i < nfiles; i++)
douser(f, dirbuf[i].name);
}
/*
* Read a whole directory before doing anything.
*/
long
readdirect(int fd)
{
enum
{
N = 32
};
long m, n;
m = 1; /* prime the loop */
for(n=0; m>0; n+=m/sizeof(Dir)){
if(n == ndirbuf){
dirbuf = realloc(dirbuf, (ndirbuf+N)*sizeof(Dir));
if(dirbuf == 0)
error("memory allocation");
ndirbuf += N;
}
m = dirread(fd, dirbuf+n, (ndirbuf-n)*sizeof(Dir));
}
return n;
}
/*
* check for expiration
*/
void
douser(Fs *f, char *user)
{
int n, nwarn;
char buf[2*NAMELEN+2];
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;
int pfd[2];
char *ct, *p;
Waitmsg w;
if(pipe(pfd) < 0){
complain("out of pipes: %r");
return 0;
}
switch(pid = rfork(RFPROC|RFNAMEG|RFNOTEG|RFENVG|RFFDG)){
case -1:
complain("can't fork: %r");
return 0;
case 0:
break;
default:
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");
close(pfd[1]);
for(;;){
i = wait(&w);
if(i < 0)
break;
if(i == pid){
if(w.msg[0] == 0)
break;
else
return 0;
}
}
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", 0);
}
execl("/bin/upas/sendmail", "sendmail", rcvr, 0);
/* just in case */
error("can't exec /bin/upas/sendmail");
return 0; /* for compiler */
}
void
complain(char *fmt, ...)
{
char buf[8192], *s;
s = buf;
s += sprint(s, "%s: ", argv0);
s = doprint(s, buf + sizeof(buf) / sizeof(*buf), fmt, &fmt + 1);
*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", file);
return 0;
}
n = read(fd, buf, sizeof(buf)-1);
close(fd);
if(n < 0){
complain("can't read %s", 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", file);
return;
}
fprint(fd, "%d", num);
close(fd);
}