vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

commit cef0d2f8a4aa3181901589321d0b289890d923a2
parent 31e59616e044a57c3829a225239160a5bd1dcba1
Author: Michael Teichgräber <mt4swm@googlemail.com>
Date:   Sun, 27 Dec 2009 09:48:22 -0800

To make it possible to log into 9vx using drawterm a
device #¤ (devcap) is needed, otherwise auth_chuid()
will fail, because it cannot open #¤/capuse.

This patch adds `9/port/devcap.c' from Plan 9 to
9vx/a, with only a few adaptions (see a/devcap.ed).

R=rsc_swtch, rsc
CC=codebot
http://codereview.appspot.com/151042

Committer: Russ Cox <rsc@swtch.com>

Diffstat:
src/9vx/Makefrag | 1+
src/9vx/a/devcap.c | 286+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/9vx/a/devcap.ed | 27+++++++++++++++++++++++++++
src/9vx/devtab.c | 2++
4 files changed, 316 insertions(+), 0 deletions(-)

diff --git a/src/9vx/Makefrag b/src/9vx/Makefrag @@ -66,6 +66,7 @@ PLAN9_A_OBJS = \ convS2M.o \ convM2S.o \ dev.o \ + devcap.o \ devcons.o \ devdraw.o \ devdup.o \ diff --git a/src/9vx/a/devcap.c b/src/9vx/a/devcap.c @@ -0,0 +1,286 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "error.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 l; + 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 char* +hashstr(uchar *hash) +{ + static char buf[2*Hashlen+1]; + int i; + + for(i = 0; i < Hashlen; i++) + sprint(buf+2*i, "%2.2ux", hash[i]); + buf[2*Hashlen] = 0; + return buf; +} + */ + +static Caphash* +remcap(uchar *hash) +{ + Caphash *t, **l; + + qlock(&capalloc.l); + + /* 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.l); + + 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 = msec(); + + qlock(&capalloc.l); + + /* 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.l); +} + +static void +capclose(Chan *c) +{ +} + +static long +capread(Chan *c, void *va, long n, vlong vl) +{ + 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 vl) +{ + Caphash *p; + char *cp; + uchar hash[Hashlen]; + char *key, *from, *to; + char err[256]; + + switch((ulong)c->qid.path){ + case Qhash: + if(!iseve()) + error(Eperm); + 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 = { + L'¤', + "cap", + + devreset, + devinit, + devshutdown, + capattach, + capwalk, + capstat, + capopen, + devcreate, + capclose, + capread, + devbread, + capwrite, + devbwrite, + capremove, + devwstat +}; diff --git a/src/9vx/a/devcap.ed b/src/9vx/a/devcap.ed @@ -0,0 +1,27 @@ +197c +capwrite(Chan *c, void *va, long n, vlong vl) +. +183c +capread(Chan *c, void *va, long n, vlong vl) +. +178c +capclose(Chan *c) +. +174c + qunlock(&capalloc.l); +. +156c + qlock(&capalloc.l); +. +154c + p->ticks = msec(); +. +140c + qunlock(&capalloc.l); +. +126c + qlock(&capalloc.l); +. +30c + QLock l; +. diff --git a/src/9vx/devtab.c b/src/9vx/devtab.c @@ -22,6 +22,7 @@ extern Dev procdevtab; extern Dev mntloopdevtab; extern Dev dupdevtab; extern Dev sddevtab; +extern Dev capdevtab; Dev *devtab[] = { &rootdevtab, /* must be first */ @@ -41,6 +42,7 @@ Dev *devtab[] = { &ssldevtab, &tlsdevtab, &sddevtab, + &capdevtab, 0 };