123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "netif.h"
- #include <libsec.h>
- enum
- {
- Hashlen= SHA1dlen,
- Maxhash= 256,
- };
- /*
- * if a process knows cap->cap, it can change user
- * to capabilty->user.
- */
- typedef struct Caphash Caphash;
- struct Caphash
- {
- Caphash *next;
- char hash[Hashlen];
- ulong ticks;
- };
- struct
- {
- QLock;
- Caphash *first;
- int nhash;
- } capalloc;
- enum
- {
- Qdir,
- Qhash,
- Quse,
- };
- /* caphash must be last */
- Dirtab capdir[] =
- {
- ".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
- "capuse", {Quse}, 0, 0222,
- "caphash", {Qhash}, 0, 0200,
- };
- int ncapdir = nelem(capdir);
- static Chan*
- capattach(char *spec)
- {
- return devattach(L'¤', spec);
- }
- static Walkqid*
- capwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, capdir, ncapdir, devgen);
- }
- static void
- capremove(Chan *c)
- {
- if(iseve() && c->qid.path == Qhash)
- ncapdir = nelem(capdir)-1;
- else
- error(Eperm);
- }
- static int
- capstat(Chan *c, uchar *db, int n)
- {
- return devstat(c, db, n, capdir, ncapdir, devgen);
- }
- /*
- * if the stream doesn't exist, create it
- */
- static Chan*
- capopen(Chan *c, int omode)
- {
- if(c->qid.type & QTDIR){
- if(omode != OREAD)
- error(Ebadarg);
- c->mode = omode;
- c->flag |= COPEN;
- c->offset = 0;
- return c;
- }
- switch((ulong)c->qid.path){
- case Qhash:
- if(!iseve())
- error(Eperm);
- break;
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
- }
- static Caphash*
- remcap(uchar *hash)
- {
- Caphash *t, **l;
- qlock(&capalloc);
- /* find the matching capability */
- for(l = &capalloc.first; *l != nil;){
- t = *l;
- if(memcmp(hash, t->hash, Hashlen) == 0)
- break;
- l = &t->next;
- }
- t = *l;
- if(t != nil){
- capalloc.nhash--;
- *l = t->next;
- }
- qunlock(&capalloc);
- return t;
- }
- /* add a capability, throwing out any old ones */
- static void
- addcap(uchar *hash)
- {
- Caphash *p, *t, **l;
- p = smalloc(sizeof *p);
- memmove(p->hash, hash, Hashlen);
- p->next = nil;
- p->ticks = m->ticks;
- qlock(&capalloc);
- /* trim extras */
- while(capalloc.nhash >= Maxhash){
- t = capalloc.first;
- if(t == nil)
- panic("addcap");
- capalloc.first = t->next;
- free(t);
- capalloc.nhash--;
- }
- /* add new one */
- for(l = &capalloc.first; *l != nil; l = &(*l)->next)
- ;
- *l = p;
- capalloc.nhash++;
- qunlock(&capalloc);
- }
- static void
- capclose(Chan*)
- {
- }
- static long
- capread(Chan *c, void *va, long n, vlong)
- {
- switch((ulong)c->qid.path){
- case Qdir:
- return devdirread(c, va, n, capdir, ncapdir, devgen);
- default:
- error(Eperm);
- break;
- }
- return n;
- }
- static long
- capwrite(Chan *c, void *va, long n, vlong)
- {
- Caphash *p;
- char *cp;
- uchar hash[Hashlen];
- char *key, *from, *to;
- char err[256];
- switch((ulong)c->qid.path){
- case Qhash:
- if(n < Hashlen)
- error(Eshort);
- memmove(hash, va, Hashlen);
- addcap(hash);
- break;
- case Quse:
- /* copy key to avoid a fault in hmac_xx */
- cp = nil;
- if(waserror()){
- free(cp);
- nexterror();
- }
- cp = smalloc(n+1);
- memmove(cp, va, n);
- cp[n] = 0;
- from = cp;
- key = strrchr(cp, '@');
- if(key == nil)
- error(Eshort);
- *key++ = 0;
- hmac_sha1((uchar*)from, strlen(from), (uchar*)key, strlen(key), hash, nil);
- p = remcap(hash);
- if(p == nil){
- snprint(err, sizeof err, "invalid capability %s@%s", from, key);
- error(err);
- }
- /* if a from user is supplied, make sure it matches */
- to = strchr(from, '@');
- if(to == nil){
- to = from;
- } else {
- *to++ = 0;
- if(strcmp(from, up->user) != 0)
- error("capability must match user");
- }
- /* set user id */
- kstrdup(&up->user, to);
- up->basepri = PriNormal;
- free(p);
- free(cp);
- poperror();
- break;
- default:
- error(Eperm);
- break;
- }
- return n;
- }
- Dev capdevtab = {
- .dc= L'¤',
- .name= "cap",
- .reset= devreset,
- .init= devinit,
- .shutdown= devshutdown,
- .attach= capattach,
- .walk= capwalk,
- .stat= capstat,
- .open= capopen,
- .create= devcreate,
- .close= capclose,
- .read= capread,
- .bread= devbread,
- .write= capwrite,
- .bwrite= devbwrite,
- .remove= capremove,
- .wstat= devwstat,
- };
|