ref: ddd839ff7cfa099f8c363d9c790a9ef10026b52c
dir: /chusr.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <libsec.h> #include <authsrv.h> #define KEYDB "/mnt/keys" #define NETKEYDB "/mnt/netkeys" #define KEYDBBUF (sizeof NETKEYDB) /* enough for any keydb prefix */ #define AUTHLOG "auth" enum{ Nemail = 10, /* from authcmdlib.h */ MAXNETCHAL = 100000, /* max securenet challenge */ Maxpath = 256, }; typedef struct { char *user; char *postid; char *name; char *dept; char *email[Nemail]; } Acctbio; typedef struct { char *keys; char *msg; char *who; Biobuf *b; } Fs; Fs fs = { "/mnt/keys", "plan 9 key", "/adm/keys.who", 0 }; static uchar zeros[16]; void install(char*, char*, Authkey*, long); int exists(char*, char*); void private(void); int setkey(char*, char*, Authkey*); char* setdeskey(char*, char*, char*); uchar* setaeskey(char*, char*, uchar*); char* setsecret(char*, char*, char*); void wrbio(char*, Acctbio*); int writefile(char*, char*, int); int deskeyfmt(Fmt*); void usage(void) { fprint(2, "usage: %s [-d dept] [-e email] [-i postid] [-s sponsor\'s email] -p pass user\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { int debug = 1; char *u, *pass = ""; Authkey key; Acctbio a; Fs *f; fmtinstall('K', deskeyfmt); ARGBEGIN{ case 'D': debug = 1; break; case 'd': a.dept = EARGF(usage()); break; case 'i': a.postid = EARGF(usage()); break; case 'e': a.email[0] = EARGF(usage()); break; case 'p': pass = EARGF(usage()); break; case 's': a.email[1] = EARGF(usage()); break; default: usage(); }ARGEND if(utflen(pass) < 8) usage(); u = argv[0]; if(memchr(u, '\0', ANAMELEN) == 0) sysfatal("bad user name"); if(!debug) private(); a.user = u; memset(&key, 0, sizeof(key)); f = &fs; passtokey(&key, pass); install(f->keys, u, &key, 0); if(setsecret(KEYDB, u, pass) == 0) sysfatal("error writing Inferno/POP secret"); wrbio(f->who, &a); print("user %s installed for Plan 9\n", u); syslog(0, AUTHLOG, "user %s installed for plan 9", u); exits(0); } void install(char *db, char *u, Authkey *key, long t) { char buf[KEYDBBUF+ANAMELEN+20]; int fd; if(!exists(db, u)){ snprint(buf, sizeof(buf), "%s/%s", db, u); fd = create(buf, OREAD, 0777|DMDIR); if(fd < 0) sysfatal("can't create user %s: %r", u); close(fd); } if(!setkey(db, u, key)) sysfatal("can't set key: %r"); if(t == -1) return; snprint(buf, sizeof(buf), "%s/%s/expire", db, u); fd = open(buf, OWRITE); if(fd < 0 || fprint(fd, "%ld", t) < 0) sysfatal("can't write expiration time"); close(fd); } int exists(char *db, char *u) { char buf[KEYDBBUF+ANAMELEN+6]; snprint(buf, sizeof(buf), "%s/%s/expire", db, u); if(access(buf, 0) < 0) return 0; return 1; } /* these functions are from /sys/src/cmd/auth/lib/ */ int deskeyfmt(Fmt *f) { uchar key[8]; char buf[32]; uchar *k; int i; k = va_arg(f->args, uchar*); key[0] = 0; for(i = 0; i < 7; i++){ key[i] |= k[i] >> i; key[i] &= ~1; key[i+1] = k[i] << (7 - i); } key[7] &= ~1; sprint(buf, "%.3uo %.3uo %.3uo %.3uo %.3uo %.3uo %.3uo %.3uo", key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]); fmtstrcpy(f, buf); return 0; } /* don't allow other processes to debug us and steal keys */ void private(void) { int fd; char buf[32]; static char pmsg[] = "Warning! %s can't protect itself from debugging: %r\n"; static char smsg[] = "Warning! %s can't turn off swapping: %r\n"; snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid()); fd = open(buf, OWRITE|OCEXEC); if(fd < 0){ fprint(2, pmsg, argv0); return; } if(fprint(fd, "private") < 0) fprint(2, pmsg, argv0); if(fprint(fd, "noswap") < 0) fprint(2, smsg, argv0); close(fd); } int setkey(char *db, char *user, Authkey *key) { int ret; ret = setdeskey(db, user, key->des) != nil; if(tsmemcmp(key->aes, zeros, AESKEYLEN) != 0) ret |= setaeskey(db, user, key->aes) != nil; return ret; } char* setdeskey(char *db, char *user, char *key) { char filename[Maxpath]; snprint(filename, sizeof filename, "%s/%s/key", db, user); if(writefile(filename, key, DESKEYLEN) != DESKEYLEN) return nil; return key; } uchar* setaeskey(char *db, char *user, uchar *key) { char filename[Maxpath]; snprint(filename, sizeof filename, "%s/%s/aeskey", db, user); if(writefile(filename, (char*)key, AESKEYLEN) != AESKEYLEN) return nil; return key; } char* setsecret(char *db, char *user, char *secret) { char filename[Maxpath]; snprint(filename, sizeof filename, "%s/%s/secret", db, user); if(writefile(filename, secret, strlen(secret)) != strlen(secret)) return nil; return secret; } void wrbio(char *file, Acctbio *a) { char buf[1024]; int i, fd, n; fd = open(file, OWRITE); if(fd < 0){ fd = create(file, OWRITE, 0660); if(fd < 0) sysfatal("can't create %s", file); } if(seek(fd, 0, 2) < 0) sysfatal("can't seek %s", file); if(a->postid == 0) a->postid = ""; if(a->name == 0) a->name = ""; if(a->dept == 0) a->dept = ""; if(a->email[0] == 0) a->email[0] = strdup(a->user); n = 0; n += snprint(buf+n, sizeof(buf)-n, "%s|%s|%s|%s", a->user, a->postid, a->name, a->dept); for(i = 0; i < Nemail; i++){ if(a->email[i] == 0) break; n += snprint(buf+n, sizeof(buf)-n, "|%s", a->email[i]); } n += snprint(buf+n, sizeof(buf)-n, "\n"); write(fd, buf, n); close(fd); } int writefile(char *file, char *buf, int n) { int fd; fd = open(file, OWRITE); if(fd < 0) return -1; n = write(fd, buf, n); close(fd); return n; }