devcap.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devcap.c (4141B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 #include        "libsec.h"
            9 
           10 enum
           11 {
           12         Hashlen=        SHA1dlen,
           13         Maxhash=        256,
           14 };
           15 
           16 /*
           17  *  if a process knows cap->cap, it can change user
           18  *  to capabilty->user.
           19  */
           20 typedef struct Caphash        Caphash;
           21 struct Caphash
           22 {
           23         Caphash        *next;
           24         char                hash[Hashlen];
           25         ulong                ticks;
           26 };
           27 
           28 struct
           29 {
           30         QLock l;
           31         Caphash        *first;
           32         int        nhash;
           33 } capalloc;
           34 
           35 enum
           36 {
           37         Qdir,
           38         Qhash,
           39         Quse,
           40 };
           41 
           42 /* caphash must be last */
           43 Dirtab capdir[] =
           44 {
           45         ".",                {Qdir,0,QTDIR},        0,                DMDIR|0500,
           46         "capuse",        {Quse},                0,                0222,
           47         "caphash",        {Qhash},        0,                0200,
           48 };
           49 int ncapdir = nelem(capdir);
           50 
           51 static Chan*
           52 capattach(char *spec)
           53 {
           54         return devattach(L'¤', spec);
           55 }
           56 
           57 static Walkqid*
           58 capwalk(Chan *c, Chan *nc, char **name, int nname)
           59 {
           60         return devwalk(c, nc, name, nname, capdir, ncapdir, devgen);
           61 }
           62 
           63 static void
           64 capremove(Chan *c)
           65 {
           66         if(iseve() && c->qid.path == Qhash)
           67                 ncapdir = nelem(capdir)-1;
           68         else
           69                 error(Eperm);
           70 }
           71 
           72 
           73 static int
           74 capstat(Chan *c, uchar *db, int n)
           75 {
           76         return devstat(c, db, n, capdir, ncapdir, devgen);
           77 }
           78 
           79 /*
           80  *  if the stream doesn't exist, create it
           81  */
           82 static Chan*
           83 capopen(Chan *c, int omode)
           84 {
           85         if(c->qid.type & QTDIR){
           86                 if(omode != OREAD)
           87                         error(Ebadarg);
           88                 c->mode = omode;
           89                 c->flag |= COPEN;
           90                 c->offset = 0;
           91                 return c;
           92         }
           93 
           94         switch((ulong)c->qid.path){
           95         case Qhash:
           96                 if(!iseve())
           97                         error(Eperm);
           98                 break;
           99         }
          100 
          101         c->mode = openmode(omode);
          102         c->flag |= COPEN;
          103         c->offset = 0;
          104         return c;
          105 }
          106 
          107 /*
          108 static char*
          109 hashstr(uchar *hash)
          110 {
          111         static char buf[2*Hashlen+1];
          112         int i;
          113 
          114         for(i = 0; i < Hashlen; i++)
          115                 sprint(buf+2*i, "%2.2ux", hash[i]);
          116         buf[2*Hashlen] = 0;
          117         return buf;
          118 }
          119  */
          120 
          121 static Caphash*
          122 remcap(uchar *hash)
          123 {
          124         Caphash *t, **l;
          125 
          126         qlock(&capalloc.l);
          127 
          128         /* find the matching capability */
          129         for(l = &capalloc.first; *l != nil;){
          130                 t = *l;
          131                 if(memcmp(hash, t->hash, Hashlen) == 0)
          132                         break;
          133                 l = &t->next;
          134         }
          135         t = *l;
          136         if(t != nil){
          137                 capalloc.nhash--;
          138                 *l = t->next;
          139         }
          140         qunlock(&capalloc.l);
          141 
          142         return t;
          143 }
          144 
          145 /* add a capability, throwing out any old ones */
          146 static void
          147 addcap(uchar *hash)
          148 {
          149         Caphash *p, *t, **l;
          150 
          151         p = smalloc(sizeof *p);
          152         memmove(p->hash, hash, Hashlen);
          153         p->next = nil;
          154         p->ticks = msec();
          155 
          156         qlock(&capalloc.l);
          157 
          158         /* trim extras */
          159         while(capalloc.nhash >= Maxhash){
          160                 t = capalloc.first;
          161                 if(t == nil)
          162                         panic("addcap");
          163                 capalloc.first = t->next;
          164                 free(t);
          165                 capalloc.nhash--;
          166         }
          167 
          168         /* add new one */
          169         for(l = &capalloc.first; *l != nil; l = &(*l)->next)
          170                 ;
          171         *l = p;
          172         capalloc.nhash++;
          173 
          174         qunlock(&capalloc.l);
          175 }
          176 
          177 static void
          178 capclose(Chan *c)
          179 {
          180 }
          181 
          182 static long
          183 capread(Chan *c, void *va, long n, vlong vl)
          184 {
          185         switch((ulong)c->qid.path){
          186         case Qdir:
          187                 return devdirread(c, va, n, capdir, ncapdir, devgen);
          188 
          189         default:
          190                 error(Eperm);
          191                 break;
          192         }
          193         return n;
          194 }
          195 
          196 static long
          197 capwrite(Chan *c, void *va, long n, vlong vl)
          198 {
          199         Caphash *p;
          200         char *cp;
          201         uchar hash[Hashlen];
          202         char *key, *from, *to;
          203         char err[256];
          204 
          205         switch((ulong)c->qid.path){
          206         case Qhash:
          207                 if(!iseve())
          208                         error(Eperm);
          209                 if(n < Hashlen)
          210                         error(Eshort);
          211                 memmove(hash, va, Hashlen);
          212                 addcap(hash);
          213                 break;
          214 
          215         case Quse:
          216                 /* copy key to avoid a fault in hmac_xx */
          217                 cp = nil;
          218                 if(waserror()){
          219                         free(cp);
          220                         nexterror();
          221                 }
          222                 cp = smalloc(n+1);
          223                 memmove(cp, va, n);
          224                 cp[n] = 0;
          225 
          226                 from = cp;
          227                 key = strrchr(cp, '@');
          228                 if(key == nil)
          229                         error(Eshort);
          230                 *key++ = 0;
          231 
          232                 hmac_sha1((uchar*)from, strlen(from), (uchar*)key, strlen(key), hash, nil);
          233 
          234                 p = remcap(hash);
          235                 if(p == nil){
          236                         snprint(err, sizeof err, "invalid capability %s@%s", from, key);
          237                         error(err);
          238                 }
          239 
          240                 /* if a from user is supplied, make sure it matches */
          241                 to = strchr(from, '@');
          242                 if(to == nil){
          243                         to = from;
          244                 } else {
          245                         *to++ = 0;
          246                         if(strcmp(from, up->user) != 0)
          247                                 error("capability must match user");
          248                 }
          249 
          250                 /* set user id */
          251                 kstrdup(&up->user, to);
          252                 up->basepri = PriNormal;
          253 
          254                 free(p);
          255                 free(cp);
          256                 poperror();
          257                 break;
          258 
          259         default:
          260                 error(Eperm);
          261                 break;
          262         }
          263 
          264         return n;
          265 }
          266 
          267 Dev capdevtab = {
          268         L'¤',
          269         "cap",
          270 
          271         devreset,
          272         devinit,
          273         devshutdown,
          274         capattach,
          275         capwalk,
          276         capstat,
          277         capopen,
          278         devcreate,
          279         capclose,
          280         capread,
          281         devbread,
          282         capwrite,
          283         devbwrite,
          284         capremove,
          285         devwstat
          286 };