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. - vx32 - Local 9vx git repository for patches.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit cef0d2f8a4aa3181901589321d0b289890d923a2
 (DIR) parent 31e59616e044a57c3829a225239160a5bd1dcba1
 (HTM) 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(-)
       ---
 (DIR) 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 \
 (DIR) 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.
       + */
       +ttypedef 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
       +};
 (DIR) 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;
       +.
 (DIR) 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
        };