/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * keyfs */#include <u.h>#include <libc.h>#include <ctype.h>#include <authsrv.h>#include <fcall.h>#include <bio.h>#include <mp.h>#include <libsec.h>#include "authcmdlib.h" #pragma varargck type "W" char* char authkey[8]; typedef struct Fid Fid;typedef struct User User; enum { Qroot, Quser, Qkey, Qsecret, Qlog, Qstatus, Qexpire, Qwarnings, Qmax, Nuser = 512, MAXBAD = 10, /* max # of bad attempts before disabling the account */ /* file must be randomly addressible, so names have fixed length */ Namelen = ANAMELEN,}; enum { Sok, Sdisabled, Smax,}; struct Fid { int fid; ulong qtype; User *user; int busy; Fid *next;}; struct User { char *name; char key[DESKEYLEN]; char secret[SECRETLEN]; ulong expire; /* 0 == never */ uchar status; ulong bad; /* # of consecutive bad authentication attempts */ int ref; char removed; uchar warnings; long purgatory; /* time purgatory ends */ ulong uniq; User *link;}; char *qinfo[Qmax] = { [Qroot] "keys", [Quser] ".", [Qkey] "key", [Qsecret] "secret", [Qlog] "log", [Qexpire] "expire", [Qstatus] "status", [Qwarnings] "warnings",}; char *status[Smax] = { [Sok] "ok", [Sdisabled] "disabled",}; Fid *fids;User *users[Nuser];char *userkeys;int nuser;ulong uniq = 1;Fcall rhdr, thdr;int usepass;char *warnarg;uchar mdata[8192 + IOHDRSZ];int messagesize = sizeof mdata; int readusers(void);ulong hash(char*);Fid *findfid(int);User *finduser(char*);User *installuser(char*);int removeuser(User*);void insertuser(User*);void writeusers(void);void io(int, int);void *emalloc(ulong);Qid mkqid(User*, ulong);int dostat(User*, ulong, void*, int);int newkeys(void);void warning(void);int weirdfmt(Fmt *f); char *Auth(Fid*), *Attach(Fid*), *Version(Fid*), *Flush(Fid*), *Walk(Fid*), *Open(Fid*), *Create(Fid*), *Read(Fid *), *Write(Fid*), *Clunk(Fid*), *Remove(Fid *), *Stat(Fid*), *Wstat(Fid*);char *(*fcalls[])(Fid*) = { [Tattach] Attach, [Tauth] Auth, [Tclunk] Clunk, [Tcreate] Create, [Tflush] Flush, [Topen] Open, [Tread] Read, [Tremove] Remove, [Tstat] Stat, [Tversion] Version, [Twalk] Walk, [Twrite] Write, [Twstat] Wstat,}; static voidusage(void){ fprint(2, "usage: %s [-p] [-m mtpt] [-w warn] [keyfile]\n", argv0); exits("usage");} voidmain(int argc, char *argv[]){ char *mntpt; int p[2]; fmtinstall('W', weirdfmt); mntpt = "/mnt/keys"; ARGBEGIN{ case 'm': mntpt = EARGF(usage()); break; case 'p': usepass = 1; break; case 'w': warnarg = EARGF(usage()); break; default: usage(); break; }ARGEND argv0 = "keyfs"; userkeys = "/adm/keys"; if(argc > 1) usage(); if(argc == 1) userkeys = argv[0]; if(pipe(p) < 0) error("can't make pipe: %r"); if(usepass) { getpass(authkey, nil, 0, 0); } else { if(!getauthkey(authkey)) print("keyfs: warning: can't read NVRAM\n"); } switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){ case 0: close(p[0]); io(p[1], p[1]); exits(0); case -1: error("fork"); default: close(p[1]); if(mount(p[0], -1, mntpt, MREPL|MCREATE, "") < 0) error("can't mount: %r"); exits(0); }} char *Flush(Fid *f){ USED(f); return 0;} char *Auth(Fid *){ return "keyfs: authentication not required";} char *Attach(Fid *f){ if(f->busy) Clunk(f); f->user = 0; f->qtype = Qroot; f->busy = 1; thdr.qid = mkqid(f->user, f->qtype); return 0;} char*Version(Fid*){ Fid *f; for(f = fids; f; f = f->next) if(f->busy) Clunk(f); if(rhdr.msize > sizeof mdata) thdr.msize = sizeof mdata; else thdr.msize = rhdr.msize; messagesize = thdr.msize; if(strncmp(rhdr.version, "9P2000", 6) != 0) return "bad 9P version"; thdr.version = "9P2000"; return 0;} char *Walk(Fid *f){ char *name, *err; int i, j, max; Fid *nf; ulong qtype; User *user; if(!f->busy) return "walk of unused fid"; nf = nil; qtype = f->qtype; user = f->user; if(rhdr.fid != rhdr.newfid){ nf = findfid(rhdr.newfid); if(nf->busy) return "fid in use"; f = nf; /* walk f */ } err = nil; i = 0; if(rhdr.nwname > 0){ for(; i<rhdr.nwname; i++){ if(i >= MAXWELEM){ err = "too many path name elements"; break; } name = rhdr.wname[i]; switch(qtype){ case Qroot: if(strcmp(name, "..") == 0) goto Accept; user = finduser(name); if(!user) goto Out; qtype = Quser; Accept: thdr.wqid[i] = mkqid(user, qtype); break; case Quser: if(strcmp(name, "..") == 0) { qtype = Qroot; user = 0; goto Accept; } max = Qmax; for(j = Quser + 1; j < Qmax; j++) if(strcmp(name, qinfo[j]) == 0){ qtype = j; break; } if(j < max) goto Accept; goto Out; default: err = "file is not a directory"; goto Out; } } Out: if(i < rhdr.nwname && err == nil) err = "file not found"; } if(err != nil){ return err; } /* if we cloned and then completed the walk, update new fid */ if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){ nf->busy = 1; nf->qtype = qtype; if(nf->user = user) nf->user->ref++; }else if(nf == nil && rhdr.nwname > 0){ /* walk without clone (rare) */ Clunk(f); f->busy = 1; f->qtype = qtype; if(f->user = user) f->user->ref++; } thdr.nwqid = i; return 0;} char *Clunk(Fid *f){ f->busy = 0; if(f->user && --f->user->ref == 0 && f->user->removed) { free(f->user->name); free(f->user); } f->user = 0; return 0;} char *Open(Fid *f){ int mode; if(!f->busy) return "open of unused fid"; mode = rhdr.mode; if(f->qtype == Quser && (mode & (OWRITE|OTRUNC))) return "user already exists"; thdr.qid = mkqid(f->user, f->qtype); thdr.iounit = messagesize - IOHDRSZ; return 0;} char *Create(Fid *f){ char *name; long perm; if(!f->busy) return "create of unused fid"; name = rhdr.name; if(f->user){ return "permission denied"; }else{ perm = rhdr.perm; if(!(perm & DMDIR)) return "permission denied"; if(strcmp(name, "") == 0) return "empty file name"; if(strlen(name) >= Namelen) return "file name too long"; if(finduser(name)) return "user already exists"; f->user = installuser(name); f->user->ref++; f->qtype = Quser; } thdr.qid = mkqid(f->user, f->qtype); thdr.iounit = messagesize - IOHDRSZ; writeusers(); return 0;} char *Read(Fid *f){ User *u; char *data; ulong off, n, m; int i, j, max; if(!f->busy) return "read of unused fid"; n = rhdr.count; off = rhdr.offset; thdr.count = 0; data = thdr.data; switch(f->qtype){ case Qroot: j = 0; for(i = 0; i < Nuser; i++) for(u = users[i]; u; j += m, u = u->link){ m = dostat(u, Quser, data, n); if(m <= BIT16SZ) break; if(j < off) continue; data += m; n -= m; } thdr.count = data - thdr.data; return 0; case Quser: max = Qmax; max -= Quser + 1; j = 0; for(i = 0; i < max; j += m, i++){ m = dostat(f->user, i + Quser + 1, data, n); if(m <= BIT16SZ) break; if(j < off) continue; data += m; n -= m; } thdr.count = data - thdr.data; return 0; case Qkey: if(f->user->status != Sok) return "user disabled"; if(f->user->purgatory > time(0)) return "user in purgatory"; if(f->user->expire != 0 && f->user->expire < time(0)) return "user expired"; if(off != 0) return 0; if(n > DESKEYLEN) n = DESKEYLEN; memmove(thdr.data, f->user->key, n); thdr.count = n; return 0; case Qsecret: if(f->user->status != Sok) return "user disabled"; if(f->user->purgatory > time(0)) return "user in purgatory"; if(f->user->expire != 0 && f->user->expire < time(0)) return "user expired"; if(off != 0) return 0; if(n > strlen(f->user->secret)) n = strlen(f->user->secret); memmove(thdr.data, f->user->secret, n); thdr.count = n; return 0; case Qstatus: if(off != 0){ thdr.count = 0; return 0; } if(f->user->status == Sok && f->user->expire && f->user->expire < time(0)) sprint(thdr.data, "expired\n"); else sprint(thdr.data, "%s\n", status[f->user->status]); thdr.count = strlen(thdr.data); return 0; case Qexpire: if(off != 0){ thdr.count = 0; return 0; } if(!f->user->expire) strcpy(data, "never\n"); else sprint(data, "%lud\n", f->user->expire); if(n > strlen(data)) n = strlen(data); thdr.count = n; return 0; case Qlog: if(off != 0){ thdr.count = 0; return 0; } sprint(data, "%lud\n", f->user->bad); if(n > strlen(data)) n = strlen(data); thdr.count = n;Lines 1–500 of 1123. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * keyfs */ #include <u.h> #include <libc.h> #include <ctype.h> #include <authsrv.h> #include <fcall.h> #include <bio.h> #include <mp.h> #include <libsec.h> #include "authcmdlib.h" #pragma varargck type "W" char* char authkey[8]; typedef struct Fid Fid; typedef struct User User; enum { Qroot, Quser, Qkey, Qsecret, Qlog, Qstatus, Qexpire, Qwarnings, Qmax, Nuser = 512, MAXBAD = 10, /* max # of bad attempts before disabling the account */ /* file must be randomly addressible, so names have fixed length */ Namelen = ANAMELEN, }; enum { Sok, Sdisabled, Smax, }; struct Fid { int fid; ulong qtype; User *user; int busy; Fid *next; }; struct User { char *name; char key[DESKEYLEN]; char secret[SECRETLEN]; ulong expire; /* 0 == never */ uchar status; ulong bad; /* # of consecutive bad authentication attempts */ int ref; char removed; uchar warnings; long purgatory; /* time purgatory ends */ ulong uniq; User *link; }; char *qinfo[Qmax] = { [Qroot] "keys", [Quser] ".", [Qkey] "key", [Qsecret] "secret", [Qlog] "log", [Qexpire] "expire", [Qstatus] "status", [Qwarnings] "warnings", }; char *status[Smax] = { [Sok] "ok", [Sdisabled] "disabled", }; Fid *fids; User *users[Nuser]; char *userkeys; int nuser; ulong uniq = 1; Fcall rhdr, thdr; int usepass; char *warnarg; uchar mdata[8192 + IOHDRSZ]; int messagesize = sizeof mdata; int readusers(void); ulong hash(char*); Fid *findfid(int); User *finduser(char*); User *installuser(char*); int removeuser(User*); void insertuser(User*); void writeusers(void); void io(int, int); void *emalloc(ulong); Qid mkqid(User*, ulong); int dostat(User*, ulong, void*, int); int newkeys(void); void warning(void); int weirdfmt(Fmt *f); char *Auth(Fid*), *Attach(Fid*), *Version(Fid*), *Flush(Fid*), *Walk(Fid*), *Open(Fid*), *Create(Fid*), *Read(Fid *), *Write(Fid*), *Clunk(Fid*), *Remove(Fid *), *Stat(Fid*), *Wstat(Fid*); char *(*fcalls[])(Fid*) = { [Tattach] Attach, [Tauth] Auth, [Tclunk] Clunk, [Tcreate] Create, [Tflush] Flush, [Topen] Open, [Tread] Read, [Tremove] Remove, [Tstat] Stat, [Tversion] Version, [Twalk] Walk, [Twrite] Write, [Twstat] Wstat, }; static void usage(void) { fprint(2, "usage: %s [-p] [-m mtpt] [-w warn] [keyfile]\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { char *mntpt; int p[2]; fmtinstall('W', weirdfmt); mntpt = "/mnt/keys"; ARGBEGIN{ case 'm': mntpt = EARGF(usage()); break; case 'p': usepass = 1; break; case 'w': warnarg = EARGF(usage()); break; default: usage(); break; }ARGEND argv0 = "keyfs"; userkeys = "/adm/keys"; if(argc > 1) usage(); if(argc == 1) userkeys = argv[0]; if(pipe(p) < 0) error("can't make pipe: %r"); if(usepass) { getpass(authkey, nil, 0, 0); } else { if(!getauthkey(authkey)) print("keyfs: warning: can't read NVRAM\n"); } switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){ case 0: close(p[0]); io(p[1], p[1]); exits(0); case -1: error("fork"); default: close(p[1]); if(mount(p[0], -1, mntpt, MREPL|MCREATE, "") < 0) error("can't mount: %r"); exits(0); } } char * Flush(Fid *f) { USED(f); return 0; } char * Auth(Fid *) { return "keyfs: authentication not required"; } char * Attach(Fid *f) { if(f->busy) Clunk(f); f->user = 0; f->qtype = Qroot; f->busy = 1; thdr.qid = mkqid(f->user, f->qtype); return 0; } char* Version(Fid*) { Fid *f; for(f = fids; f; f = f->next) if(f->busy) Clunk(f); if(rhdr.msize > sizeof mdata) thdr.msize = sizeof mdata; else thdr.msize = rhdr.msize; messagesize = thdr.msize; if(strncmp(rhdr.version, "9P2000", 6) != 0) return "bad 9P version"; thdr.version = "9P2000"; return 0; } char * Walk(Fid *f) { char *name, *err; int i, j, max; Fid *nf; ulong qtype; User *user; if(!f->busy) return "walk of unused fid"; nf = nil; qtype = f->qtype; user = f->user; if(rhdr.fid != rhdr.newfid){ nf = findfid(rhdr.newfid); if(nf->busy) return "fid in use"; f = nf; /* walk f */ } err = nil; i = 0; if(rhdr.nwname > 0){ for(; i<rhdr.nwname; i++){ if(i >= MAXWELEM){ err = "too many path name elements"; break; } name = rhdr.wname[i]; switch(qtype){ case Qroot: if(strcmp(name, "..") == 0) goto Accept; user = finduser(name); if(!user) goto Out; qtype = Quser; Accept: thdr.wqid[i] = mkqid(user, qtype); break; case Quser: if(strcmp(name, "..") == 0) { qtype = Qroot; user = 0; goto Accept; } max = Qmax; for(j = Quser + 1; j < Qmax; j++) if(strcmp(name, qinfo[j]) == 0){ qtype = j; break; } if(j < max) goto Accept; goto Out; default: err = "file is not a directory"; goto Out; } } Out: if(i < rhdr.nwname && err == nil) err = "file not found"; } if(err != nil){ return err; } /* if we cloned and then completed the walk, update new fid */ if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){ nf->busy = 1; nf->qtype = qtype; if(nf->user = user) nf->user->ref++; }else if(nf == nil && rhdr.nwname > 0){ /* walk without clone (rare) */ Clunk(f); f->busy = 1; f->qtype = qtype; if(f->user = user) f->user->ref++; } thdr.nwqid = i; return 0; } char * Clunk(Fid *f) { f->busy = 0; if(f->user && --f->user->ref == 0 && f->user->removed) { free(f->user->name); free(f->user); } f->user = 0; return 0; } char * Open(Fid *f) { int mode; if(!f->busy) return "open of unused fid"; mode = rhdr.mode; if(f->qtype == Quser && (mode & (OWRITE|OTRUNC))) return "user already exists"; thdr.qid = mkqid(f->user, f->qtype); thdr.iounit = messagesize - IOHDRSZ; return 0; } char * Create(Fid *f) { char *name; long perm; if(!f->busy) return "create of unused fid"; name = rhdr.name; if(f->user){ return "permission denied"; }else{ perm = rhdr.perm; if(!(perm & DMDIR)) return "permission denied"; if(strcmp(name, "") == 0) return "empty file name"; if(strlen(name) >= Namelen) return "file name too long"; if(finduser(name)) return "user already exists"; f->user = installuser(name); f->user->ref++; f->qtype = Quser; } thdr.qid = mkqid(f->user, f->qtype); thdr.iounit = messagesize - IOHDRSZ; writeusers(); return 0; } char * Read(Fid *f) { User *u; char *data; ulong off, n, m; int i, j, max; if(!f->busy) return "read of unused fid"; n = rhdr.count; off = rhdr.offset; thdr.count = 0; data = thdr.data; switch(f->qtype){ case Qroot: j = 0; for(i = 0; i < Nuser; i++) for(u = users[i]; u; j += m, u = u->link){ m = dostat(u, Quser, data, n); if(m <= BIT16SZ) break; if(j < off) continue; data += m; n -= m; } thdr.count = data - thdr.data; return 0; case Quser: max = Qmax; max -= Quser + 1; j = 0; for(i = 0; i < max; j += m, i++){ m = dostat(f->user, i + Quser + 1, data, n); if(m <= BIT16SZ) break; if(j < off) continue; data += m; n -= m; } thdr.count = data - thdr.data; return 0; case Qkey: if(f->user->status != Sok) return "user disabled"; if(f->user->purgatory > time(0)) return "user in purgatory"; if(f->user->expire != 0 && f->user->expire < time(0)) return "user expired"; if(off != 0) return 0; if(n > DESKEYLEN) n = DESKEYLEN; memmove(thdr.data, f->user->key, n); thdr.count = n; return 0; case Qsecret: if(f->user->status != Sok) return "user disabled"; if(f->user->purgatory > time(0)) return "user in purgatory"; if(f->user->expire != 0 && f->user->expire < time(0)) return "user expired"; if(off != 0) return 0; if(n > strlen(f->user->secret)) n = strlen(f->user->secret); memmove(thdr.data, f->user->secret, n); thdr.count = n; return 0; case Qstatus: if(off != 0){ thdr.count = 0; return 0; } if(f->user->status == Sok && f->user->expire && f->user->expire < time(0)) sprint(thdr.data, "expired\n"); else sprint(thdr.data, "%s\n", status[f->user->status]); thdr.count = strlen(thdr.data); return 0; case Qexpire: if(off != 0){ thdr.count = 0; return 0; } if(!f->user->expire) strcpy(data, "never\n"); else sprint(data, "%lud\n", f->user->expire); if(n > strlen(data)) n = strlen(data); thdr.count = n; return 0; case Qlog: if(off != 0){ thdr.count = 0; return 0; } sprint(data, "%lud\n", f->user->bad); if(n > strlen(data)) n = strlen(data); thdr.count = n;