19a747e4fSDavid du Colombier #include "u.h"
29a747e4fSDavid du Colombier #include "../port/lib.h"
39a747e4fSDavid du Colombier #include "mem.h"
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier #include "fns.h"
69a747e4fSDavid du Colombier #include "../port/error.h"
79a747e4fSDavid du Colombier
89a747e4fSDavid du Colombier #include <libsec.h>
99a747e4fSDavid du Colombier
109a747e4fSDavid du Colombier enum
119a747e4fSDavid du Colombier {
129a747e4fSDavid du Colombier Hashlen= SHA1dlen,
139a747e4fSDavid du Colombier Maxhash= 256,
149a747e4fSDavid du Colombier };
159a747e4fSDavid du Colombier
169a747e4fSDavid du Colombier /*
179a747e4fSDavid du Colombier * if a process knows cap->cap, it can change user
189a747e4fSDavid du Colombier * to capabilty->user.
199a747e4fSDavid du Colombier */
209a747e4fSDavid du Colombier typedef struct Caphash Caphash;
219a747e4fSDavid du Colombier struct Caphash
229a747e4fSDavid du Colombier {
239a747e4fSDavid du Colombier Caphash *next;
249a747e4fSDavid du Colombier char hash[Hashlen];
259a747e4fSDavid du Colombier ulong ticks;
269a747e4fSDavid du Colombier };
279a747e4fSDavid du Colombier
289a747e4fSDavid du Colombier struct
299a747e4fSDavid du Colombier {
309a747e4fSDavid du Colombier QLock;
319a747e4fSDavid du Colombier Caphash *first;
329a747e4fSDavid du Colombier int nhash;
339a747e4fSDavid du Colombier } capalloc;
349a747e4fSDavid du Colombier
359a747e4fSDavid du Colombier enum
369a747e4fSDavid du Colombier {
379a747e4fSDavid du Colombier Qdir,
389a747e4fSDavid du Colombier Qhash,
399a747e4fSDavid du Colombier Quse,
409a747e4fSDavid du Colombier };
419a747e4fSDavid du Colombier
423ff48bf5SDavid du Colombier /* caphash must be last */
439a747e4fSDavid du Colombier Dirtab capdir[] =
449a747e4fSDavid du Colombier {
459a747e4fSDavid du Colombier ".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
469a747e4fSDavid du Colombier "capuse", {Quse}, 0, 0222,
473ff48bf5SDavid du Colombier "caphash", {Qhash}, 0, 0200,
489a747e4fSDavid du Colombier };
493ff48bf5SDavid du Colombier int ncapdir = nelem(capdir);
509a747e4fSDavid du Colombier
519a747e4fSDavid du Colombier static Chan*
capattach(char * spec)529a747e4fSDavid du Colombier capattach(char *spec)
539a747e4fSDavid du Colombier {
549a747e4fSDavid du Colombier return devattach(L'¤', spec);
559a747e4fSDavid du Colombier }
569a747e4fSDavid du Colombier
579a747e4fSDavid du Colombier static Walkqid*
capwalk(Chan * c,Chan * nc,char ** name,int nname)589a747e4fSDavid du Colombier capwalk(Chan *c, Chan *nc, char **name, int nname)
599a747e4fSDavid du Colombier {
603ff48bf5SDavid du Colombier return devwalk(c, nc, name, nname, capdir, ncapdir, devgen);
619a747e4fSDavid du Colombier }
629a747e4fSDavid du Colombier
633ff48bf5SDavid du Colombier static void
capremove(Chan * c)643ff48bf5SDavid du Colombier capremove(Chan *c)
653ff48bf5SDavid du Colombier {
663ff48bf5SDavid du Colombier if(iseve() && c->qid.path == Qhash)
673ff48bf5SDavid du Colombier ncapdir = nelem(capdir)-1;
683ff48bf5SDavid du Colombier else
693ff48bf5SDavid du Colombier error(Eperm);
703ff48bf5SDavid du Colombier }
713ff48bf5SDavid du Colombier
723ff48bf5SDavid du Colombier
739a747e4fSDavid du Colombier static int
capstat(Chan * c,uchar * db,int n)749a747e4fSDavid du Colombier capstat(Chan *c, uchar *db, int n)
759a747e4fSDavid du Colombier {
763ff48bf5SDavid du Colombier return devstat(c, db, n, capdir, ncapdir, devgen);
779a747e4fSDavid du Colombier }
789a747e4fSDavid du Colombier
799a747e4fSDavid du Colombier /*
809a747e4fSDavid du Colombier * if the stream doesn't exist, create it
819a747e4fSDavid du Colombier */
829a747e4fSDavid du Colombier static Chan*
capopen(Chan * c,int omode)839a747e4fSDavid du Colombier capopen(Chan *c, int omode)
849a747e4fSDavid du Colombier {
859a747e4fSDavid du Colombier if(c->qid.type & QTDIR){
869a747e4fSDavid du Colombier if(omode != OREAD)
879a747e4fSDavid du Colombier error(Ebadarg);
889a747e4fSDavid du Colombier c->mode = omode;
899a747e4fSDavid du Colombier c->flag |= COPEN;
909a747e4fSDavid du Colombier c->offset = 0;
919a747e4fSDavid du Colombier return c;
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier
949a747e4fSDavid du Colombier switch((ulong)c->qid.path){
959a747e4fSDavid du Colombier case Qhash:
963ff48bf5SDavid du Colombier if(!iseve())
973ff48bf5SDavid du Colombier error(Eperm);
989a747e4fSDavid du Colombier break;
999a747e4fSDavid du Colombier }
1009a747e4fSDavid du Colombier
1019a747e4fSDavid du Colombier c->mode = openmode(omode);
1029a747e4fSDavid du Colombier c->flag |= COPEN;
1039a747e4fSDavid du Colombier c->offset = 0;
1049a747e4fSDavid du Colombier return c;
1059a747e4fSDavid du Colombier }
1069a747e4fSDavid du Colombier
107208510e1SDavid du Colombier /*
108fb7f0c93SDavid du Colombier static char*
109fb7f0c93SDavid du Colombier hashstr(uchar *hash)
110fb7f0c93SDavid du Colombier {
111208510e1SDavid du Colombier static char buf[2*Hashlen+1];
112fb7f0c93SDavid du Colombier int i;
113fb7f0c93SDavid du Colombier
114fb7f0c93SDavid du Colombier for(i = 0; i < Hashlen; i++)
115*4e3613abSDavid du Colombier seprint(buf+2*i, &buf[sizeof buf], "%2.2ux", hash[i]);
116fb7f0c93SDavid du Colombier buf[2*Hashlen] = 0;
117fb7f0c93SDavid du Colombier return buf;
118fb7f0c93SDavid du Colombier }
119208510e1SDavid du Colombier */
120fb7f0c93SDavid du Colombier
1219a747e4fSDavid du Colombier static Caphash*
remcap(uchar * hash)1229a747e4fSDavid du Colombier remcap(uchar *hash)
1239a747e4fSDavid du Colombier {
1249a747e4fSDavid du Colombier Caphash *t, **l;
1259a747e4fSDavid du Colombier
1269a747e4fSDavid du Colombier qlock(&capalloc);
1279a747e4fSDavid du Colombier
1289a747e4fSDavid du Colombier /* find the matching capability */
1299a747e4fSDavid du Colombier for(l = &capalloc.first; *l != nil;){
1309a747e4fSDavid du Colombier t = *l;
1319a747e4fSDavid du Colombier if(memcmp(hash, t->hash, Hashlen) == 0)
1329a747e4fSDavid du Colombier break;
1339a747e4fSDavid du Colombier l = &t->next;
1349a747e4fSDavid du Colombier }
1359a747e4fSDavid du Colombier t = *l;
1369a747e4fSDavid du Colombier if(t != nil){
1379a747e4fSDavid du Colombier capalloc.nhash--;
1389a747e4fSDavid du Colombier *l = t->next;
1399a747e4fSDavid du Colombier }
1409a747e4fSDavid du Colombier qunlock(&capalloc);
1419a747e4fSDavid du Colombier
1429a747e4fSDavid du Colombier return t;
1439a747e4fSDavid du Colombier }
1449a747e4fSDavid du Colombier
1459a747e4fSDavid du Colombier /* add a capability, throwing out any old ones */
1469a747e4fSDavid du Colombier static void
addcap(uchar * hash)1479a747e4fSDavid du Colombier addcap(uchar *hash)
1489a747e4fSDavid du Colombier {
1499a747e4fSDavid du Colombier Caphash *p, *t, **l;
1509a747e4fSDavid du Colombier
1519a747e4fSDavid du Colombier p = smalloc(sizeof *p);
1529a747e4fSDavid du Colombier memmove(p->hash, hash, Hashlen);
1539a747e4fSDavid du Colombier p->next = nil;
1549a747e4fSDavid du Colombier p->ticks = m->ticks;
1559a747e4fSDavid du Colombier
1569a747e4fSDavid du Colombier qlock(&capalloc);
1579a747e4fSDavid du Colombier
1589a747e4fSDavid du Colombier /* trim extras */
1599a747e4fSDavid du Colombier while(capalloc.nhash >= Maxhash){
1609a747e4fSDavid du Colombier t = capalloc.first;
1619a747e4fSDavid du Colombier if(t == nil)
1629a747e4fSDavid du Colombier panic("addcap");
1639a747e4fSDavid du Colombier capalloc.first = t->next;
1649a747e4fSDavid du Colombier free(t);
1659a747e4fSDavid du Colombier capalloc.nhash--;
1669a747e4fSDavid du Colombier }
1679a747e4fSDavid du Colombier
1689a747e4fSDavid du Colombier /* add new one */
1699a747e4fSDavid du Colombier for(l = &capalloc.first; *l != nil; l = &(*l)->next)
1709a747e4fSDavid du Colombier ;
1719a747e4fSDavid du Colombier *l = p;
1729a747e4fSDavid du Colombier capalloc.nhash++;
1739a747e4fSDavid du Colombier
1749a747e4fSDavid du Colombier qunlock(&capalloc);
1759a747e4fSDavid du Colombier }
1769a747e4fSDavid du Colombier
1779a747e4fSDavid du Colombier static void
capclose(Chan *)1783ff48bf5SDavid du Colombier capclose(Chan*)
1799a747e4fSDavid du Colombier {
1809a747e4fSDavid du Colombier }
1819a747e4fSDavid du Colombier
1829a747e4fSDavid du Colombier static long
capread(Chan * c,void * va,long n,vlong)1839a747e4fSDavid du Colombier capread(Chan *c, void *va, long n, vlong)
1849a747e4fSDavid du Colombier {
1859a747e4fSDavid du Colombier switch((ulong)c->qid.path){
1869a747e4fSDavid du Colombier case Qdir:
1873ff48bf5SDavid du Colombier return devdirread(c, va, n, capdir, ncapdir, devgen);
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier default:
1909a747e4fSDavid du Colombier error(Eperm);
1919a747e4fSDavid du Colombier break;
1929a747e4fSDavid du Colombier }
1939a747e4fSDavid du Colombier return n;
1949a747e4fSDavid du Colombier }
1959a747e4fSDavid du Colombier
1969a747e4fSDavid du Colombier static long
capwrite(Chan * c,void * va,long n,vlong)1979a747e4fSDavid du Colombier capwrite(Chan *c, void *va, long n, vlong)
1989a747e4fSDavid du Colombier {
1999a747e4fSDavid du Colombier Caphash *p;
2009a747e4fSDavid du Colombier char *cp;
2019a747e4fSDavid du Colombier uchar hash[Hashlen];
2029a747e4fSDavid du Colombier char *key, *from, *to;
2039a747e4fSDavid du Colombier char err[256];
2049a747e4fSDavid du Colombier
2059a747e4fSDavid du Colombier switch((ulong)c->qid.path){
2069a747e4fSDavid du Colombier case Qhash:
2074dc626cdSDavid du Colombier if(!iseve())
2084dc626cdSDavid du Colombier error(Eperm);
2099a747e4fSDavid du Colombier if(n < Hashlen)
2109a747e4fSDavid du Colombier error(Eshort);
2119a747e4fSDavid du Colombier memmove(hash, va, Hashlen);
2129a747e4fSDavid du Colombier addcap(hash);
2139a747e4fSDavid du Colombier break;
2149a747e4fSDavid du Colombier
2159a747e4fSDavid du Colombier case Quse:
2169a747e4fSDavid du Colombier /* copy key to avoid a fault in hmac_xx */
2179a747e4fSDavid du Colombier cp = nil;
2189a747e4fSDavid du Colombier if(waserror()){
2199a747e4fSDavid du Colombier free(cp);
2209a747e4fSDavid du Colombier nexterror();
2219a747e4fSDavid du Colombier }
2229a747e4fSDavid du Colombier cp = smalloc(n+1);
2239a747e4fSDavid du Colombier memmove(cp, va, n);
2249a747e4fSDavid du Colombier cp[n] = 0;
2259a747e4fSDavid du Colombier
2269a747e4fSDavid du Colombier from = cp;
2279a747e4fSDavid du Colombier key = strrchr(cp, '@');
2289a747e4fSDavid du Colombier if(key == nil)
2299a747e4fSDavid du Colombier error(Eshort);
2309a747e4fSDavid du Colombier *key++ = 0;
2319a747e4fSDavid du Colombier
2329a747e4fSDavid du Colombier hmac_sha1((uchar*)from, strlen(from), (uchar*)key, strlen(key), hash, nil);
2339a747e4fSDavid du Colombier
2349a747e4fSDavid du Colombier p = remcap(hash);
2359a747e4fSDavid du Colombier if(p == nil){
2369a747e4fSDavid du Colombier snprint(err, sizeof err, "invalid capability %s@%s", from, key);
2379a747e4fSDavid du Colombier error(err);
2389a747e4fSDavid du Colombier }
2399a747e4fSDavid du Colombier
2409a747e4fSDavid du Colombier /* if a from user is supplied, make sure it matches */
2419a747e4fSDavid du Colombier to = strchr(from, '@');
2429a747e4fSDavid du Colombier if(to == nil){
2439a747e4fSDavid du Colombier to = from;
2449a747e4fSDavid du Colombier } else {
2459a747e4fSDavid du Colombier *to++ = 0;
2469a747e4fSDavid du Colombier if(strcmp(from, up->user) != 0)
2479a747e4fSDavid du Colombier error("capability must match user");
2489a747e4fSDavid du Colombier }
2499a747e4fSDavid du Colombier
2509a747e4fSDavid du Colombier /* set user id */
2519a747e4fSDavid du Colombier kstrdup(&up->user, to);
2529a747e4fSDavid du Colombier up->basepri = PriNormal;
2539a747e4fSDavid du Colombier
2549a747e4fSDavid du Colombier free(p);
2559a747e4fSDavid du Colombier free(cp);
2569a747e4fSDavid du Colombier poperror();
2579a747e4fSDavid du Colombier break;
2589a747e4fSDavid du Colombier
2599a747e4fSDavid du Colombier default:
2609a747e4fSDavid du Colombier error(Eperm);
2619a747e4fSDavid du Colombier break;
2629a747e4fSDavid du Colombier }
2639a747e4fSDavid du Colombier
2649a747e4fSDavid du Colombier return n;
2659a747e4fSDavid du Colombier }
2669a747e4fSDavid du Colombier
2679a747e4fSDavid du Colombier Dev capdevtab = {
268fb7f0c93SDavid du Colombier L'¤',
269fb7f0c93SDavid du Colombier "cap",
2709a747e4fSDavid du Colombier
271fb7f0c93SDavid du Colombier devreset,
272fb7f0c93SDavid du Colombier devinit,
273fb7f0c93SDavid du Colombier devshutdown,
274fb7f0c93SDavid du Colombier capattach,
275fb7f0c93SDavid du Colombier capwalk,
276fb7f0c93SDavid du Colombier capstat,
277fb7f0c93SDavid du Colombier capopen,
278fb7f0c93SDavid du Colombier devcreate,
279fb7f0c93SDavid du Colombier capclose,
280fb7f0c93SDavid du Colombier capread,
281fb7f0c93SDavid du Colombier devbread,
282fb7f0c93SDavid du Colombier capwrite,
283fb7f0c93SDavid du Colombier devbwrite,
284fb7f0c93SDavid du Colombier capremove,
285fb7f0c93SDavid du Colombier devwstat
2869a747e4fSDavid du Colombier };
287