xref: /plan9-contrib/sys/src/9k/port/devcap.c (revision 406c76facc4b13aa2a55454bf4091aab9f03da22)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier #include	<libsec.h>
99ef1f84bSDavid du Colombier 
109ef1f84bSDavid du Colombier enum
119ef1f84bSDavid du Colombier {
129ef1f84bSDavid du Colombier 	Hashlen=	SHA1dlen,
139ef1f84bSDavid du Colombier 	Maxhash=	256,
149ef1f84bSDavid du Colombier };
159ef1f84bSDavid du Colombier 
169ef1f84bSDavid du Colombier /*
179ef1f84bSDavid du Colombier  *  if a process knows cap->cap, it can change user
189ef1f84bSDavid du Colombier  *  to capabilty->user.
199ef1f84bSDavid du Colombier  */
209ef1f84bSDavid du Colombier typedef struct Caphash	Caphash;
219ef1f84bSDavid du Colombier struct Caphash
229ef1f84bSDavid du Colombier {
239ef1f84bSDavid du Colombier 	Caphash	*next;
249ef1f84bSDavid du Colombier 	char		hash[Hashlen];
259ef1f84bSDavid du Colombier 	ulong		ticks;
269ef1f84bSDavid du Colombier };
279ef1f84bSDavid du Colombier 
289ef1f84bSDavid du Colombier struct
299ef1f84bSDavid du Colombier {
309ef1f84bSDavid du Colombier 	QLock;
319ef1f84bSDavid du Colombier 	Caphash	*first;
329ef1f84bSDavid du Colombier 	int	nhash;
339ef1f84bSDavid du Colombier } capalloc;
349ef1f84bSDavid du Colombier 
359ef1f84bSDavid du Colombier enum
369ef1f84bSDavid du Colombier {
379ef1f84bSDavid du Colombier 	Qdir,
389ef1f84bSDavid du Colombier 	Qhash,
399ef1f84bSDavid du Colombier 	Quse,
409ef1f84bSDavid du Colombier };
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier /* caphash must be last */
439ef1f84bSDavid du Colombier Dirtab capdir[] =
449ef1f84bSDavid du Colombier {
459ef1f84bSDavid du Colombier 	".",		{Qdir,0,QTDIR},	0,		DMDIR|0500,
469ef1f84bSDavid du Colombier 	"capuse",	{Quse},		0,		0222,
479ef1f84bSDavid du Colombier 	"caphash",	{Qhash},	0,		0200,
489ef1f84bSDavid du Colombier };
499ef1f84bSDavid du Colombier int ncapdir = nelem(capdir);
509ef1f84bSDavid du Colombier 
519ef1f84bSDavid du Colombier static Chan*
capattach(char * spec)529ef1f84bSDavid du Colombier capattach(char *spec)
539ef1f84bSDavid du Colombier {
549ef1f84bSDavid du Colombier 	return devattach(L'¤', spec);
559ef1f84bSDavid du Colombier }
569ef1f84bSDavid du Colombier 
579ef1f84bSDavid du Colombier static Walkqid*
capwalk(Chan * c,Chan * nc,char ** name,int nname)589ef1f84bSDavid du Colombier capwalk(Chan *c, Chan *nc, char **name, int nname)
599ef1f84bSDavid du Colombier {
609ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, capdir, ncapdir, devgen);
619ef1f84bSDavid du Colombier }
629ef1f84bSDavid du Colombier 
639ef1f84bSDavid du Colombier static void
capremove(Chan * c)649ef1f84bSDavid du Colombier capremove(Chan *c)
659ef1f84bSDavid du Colombier {
669ef1f84bSDavid du Colombier 	if(iseve() && c->qid.path == Qhash)
679ef1f84bSDavid du Colombier 		ncapdir = nelem(capdir)-1;
689ef1f84bSDavid du Colombier 	else
699ef1f84bSDavid du Colombier 		error(Eperm);
709ef1f84bSDavid du Colombier }
719ef1f84bSDavid du Colombier 
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier static long
capstat(Chan * c,uchar * db,long n)749ef1f84bSDavid du Colombier capstat(Chan *c, uchar *db, long n)
759ef1f84bSDavid du Colombier {
769ef1f84bSDavid du Colombier 	return devstat(c, db, n, capdir, ncapdir, devgen);
779ef1f84bSDavid du Colombier }
789ef1f84bSDavid du Colombier 
799ef1f84bSDavid du Colombier /*
809ef1f84bSDavid du Colombier  *  if the stream doesn't exist, create it
819ef1f84bSDavid du Colombier  */
829ef1f84bSDavid du Colombier static Chan*
capopen(Chan * c,int omode)839ef1f84bSDavid du Colombier capopen(Chan *c, int omode)
849ef1f84bSDavid du Colombier {
859ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR){
869ef1f84bSDavid du Colombier 		if(omode != OREAD)
879ef1f84bSDavid du Colombier 			error(Ebadarg);
889ef1f84bSDavid du Colombier 		c->mode = omode;
899ef1f84bSDavid du Colombier 		c->flag |= COPEN;
909ef1f84bSDavid du Colombier 		c->offset = 0;
919ef1f84bSDavid du Colombier 		return c;
929ef1f84bSDavid du Colombier 	}
939ef1f84bSDavid du Colombier 
949ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
959ef1f84bSDavid du Colombier 	case Qhash:
969ef1f84bSDavid du Colombier 		if(!iseve())
979ef1f84bSDavid du Colombier 			error(Eperm);
989ef1f84bSDavid du Colombier 		break;
999ef1f84bSDavid du Colombier 	}
1009ef1f84bSDavid du Colombier 
1019ef1f84bSDavid du Colombier 	c->mode = openmode(omode);
1029ef1f84bSDavid du Colombier 	c->flag |= COPEN;
1039ef1f84bSDavid du Colombier 	c->offset = 0;
1049ef1f84bSDavid du Colombier 	return c;
1059ef1f84bSDavid du Colombier }
1069ef1f84bSDavid du Colombier 
1079ef1f84bSDavid du Colombier /*
1089ef1f84bSDavid du Colombier static char*
1099ef1f84bSDavid du Colombier hashstr(uchar *hash)
1109ef1f84bSDavid du Colombier {
1119ef1f84bSDavid du Colombier 	static char buf[2*Hashlen+1];
1129ef1f84bSDavid du Colombier 	int i;
1139ef1f84bSDavid du Colombier 
1149ef1f84bSDavid du Colombier 	for(i = 0; i < Hashlen; i++)
115*406c76faSDavid du Colombier 		seprint(buf+2*i, &buf[sizeof buf], "%2.2ux", hash[i]);
1169ef1f84bSDavid du Colombier 	buf[2*Hashlen] = 0;
1179ef1f84bSDavid du Colombier 	return buf;
1189ef1f84bSDavid du Colombier }
1199ef1f84bSDavid du Colombier  */
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier static Caphash*
remcap(uchar * hash)1229ef1f84bSDavid du Colombier remcap(uchar *hash)
1239ef1f84bSDavid du Colombier {
1249ef1f84bSDavid du Colombier 	Caphash *t, **l;
1259ef1f84bSDavid du Colombier 
1269ef1f84bSDavid du Colombier 	qlock(&capalloc);
1279ef1f84bSDavid du Colombier 
1289ef1f84bSDavid du Colombier 	/* find the matching capability */
1299ef1f84bSDavid du Colombier 	for(l = &capalloc.first; *l != nil;){
1309ef1f84bSDavid du Colombier 		t = *l;
1319ef1f84bSDavid du Colombier 		if(memcmp(hash, t->hash, Hashlen) == 0)
1329ef1f84bSDavid du Colombier 			break;
1339ef1f84bSDavid du Colombier 		l = &t->next;
1349ef1f84bSDavid du Colombier 	}
1359ef1f84bSDavid du Colombier 	t = *l;
1369ef1f84bSDavid du Colombier 	if(t != nil){
1379ef1f84bSDavid du Colombier 		capalloc.nhash--;
1389ef1f84bSDavid du Colombier 		*l = t->next;
1399ef1f84bSDavid du Colombier 	}
1409ef1f84bSDavid du Colombier 	qunlock(&capalloc);
1419ef1f84bSDavid du Colombier 
1429ef1f84bSDavid du Colombier 	return t;
1439ef1f84bSDavid du Colombier }
1449ef1f84bSDavid du Colombier 
1459ef1f84bSDavid du Colombier /* add a capability, throwing out any old ones */
1469ef1f84bSDavid du Colombier static void
addcap(uchar * hash)1479ef1f84bSDavid du Colombier addcap(uchar *hash)
1489ef1f84bSDavid du Colombier {
1499ef1f84bSDavid du Colombier 	Caphash *p, *t, **l;
1509ef1f84bSDavid du Colombier 
1519ef1f84bSDavid du Colombier 	p = smalloc(sizeof *p);
1529ef1f84bSDavid du Colombier 	memmove(p->hash, hash, Hashlen);
1539ef1f84bSDavid du Colombier 	p->next = nil;
1549ef1f84bSDavid du Colombier 	p->ticks = m->ticks;
1559ef1f84bSDavid du Colombier 
1569ef1f84bSDavid du Colombier 	qlock(&capalloc);
1579ef1f84bSDavid du Colombier 
1589ef1f84bSDavid du Colombier 	/* trim extras */
1599ef1f84bSDavid du Colombier 	while(capalloc.nhash >= Maxhash){
1609ef1f84bSDavid du Colombier 		t = capalloc.first;
1619ef1f84bSDavid du Colombier 		if(t == nil)
1629ef1f84bSDavid du Colombier 			panic("addcap");
1639ef1f84bSDavid du Colombier 		capalloc.first = t->next;
1649ef1f84bSDavid du Colombier 		free(t);
1659ef1f84bSDavid du Colombier 		capalloc.nhash--;
1669ef1f84bSDavid du Colombier 	}
1679ef1f84bSDavid du Colombier 
1689ef1f84bSDavid du Colombier 	/* add new one */
1699ef1f84bSDavid du Colombier 	for(l = &capalloc.first; *l != nil; l = &(*l)->next)
1709ef1f84bSDavid du Colombier 		;
1719ef1f84bSDavid du Colombier 	*l = p;
1729ef1f84bSDavid du Colombier 	capalloc.nhash++;
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier 	qunlock(&capalloc);
1759ef1f84bSDavid du Colombier }
1769ef1f84bSDavid du Colombier 
1779ef1f84bSDavid du Colombier static void
capclose(Chan *)1789ef1f84bSDavid du Colombier capclose(Chan*)
1799ef1f84bSDavid du Colombier {
1809ef1f84bSDavid du Colombier }
1819ef1f84bSDavid du Colombier 
1829ef1f84bSDavid du Colombier static long
capread(Chan * c,void * va,long n,vlong)1839ef1f84bSDavid du Colombier capread(Chan *c, void *va, long n, vlong)
1849ef1f84bSDavid du Colombier {
1859ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
1869ef1f84bSDavid du Colombier 	case Qdir:
1879ef1f84bSDavid du Colombier 		return devdirread(c, va, n, capdir, ncapdir, devgen);
1889ef1f84bSDavid du Colombier 
1899ef1f84bSDavid du Colombier 	default:
1909ef1f84bSDavid du Colombier 		error(Eperm);
1919ef1f84bSDavid du Colombier 		break;
1929ef1f84bSDavid du Colombier 	}
1939ef1f84bSDavid du Colombier 	return n;
1949ef1f84bSDavid du Colombier }
1959ef1f84bSDavid du Colombier 
1969ef1f84bSDavid du Colombier static long
capwrite(Chan * c,void * va,long n,vlong)1979ef1f84bSDavid du Colombier capwrite(Chan *c, void *va, long n, vlong)
1989ef1f84bSDavid du Colombier {
1999ef1f84bSDavid du Colombier 	Caphash *p;
2009ef1f84bSDavid du Colombier 	char *cp;
2019ef1f84bSDavid du Colombier 	uchar hash[Hashlen];
2029ef1f84bSDavid du Colombier 	char *key, *from, *to;
2039ef1f84bSDavid du Colombier 	char err[256];
2049ef1f84bSDavid du Colombier 
2059ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
2069ef1f84bSDavid du Colombier 	case Qhash:
2079ef1f84bSDavid du Colombier 		if(!iseve())
2089ef1f84bSDavid du Colombier 			error(Eperm);
2099ef1f84bSDavid du Colombier 		if(n < Hashlen)
2109ef1f84bSDavid du Colombier 			error(Eshort);
2119ef1f84bSDavid du Colombier 		memmove(hash, va, Hashlen);
2129ef1f84bSDavid du Colombier 		addcap(hash);
2139ef1f84bSDavid du Colombier 		break;
2149ef1f84bSDavid du Colombier 
2159ef1f84bSDavid du Colombier 	case Quse:
2169ef1f84bSDavid du Colombier 		/* copy key to avoid a fault in hmac_xx */
2179ef1f84bSDavid du Colombier 		cp = nil;
2189ef1f84bSDavid du Colombier 		if(waserror()){
2199ef1f84bSDavid du Colombier 			free(cp);
2209ef1f84bSDavid du Colombier 			nexterror();
2219ef1f84bSDavid du Colombier 		}
2229ef1f84bSDavid du Colombier 		cp = smalloc(n+1);
2239ef1f84bSDavid du Colombier 		memmove(cp, va, n);
2249ef1f84bSDavid du Colombier 		cp[n] = 0;
2259ef1f84bSDavid du Colombier 
2269ef1f84bSDavid du Colombier 		from = cp;
2279ef1f84bSDavid du Colombier 		key = strrchr(cp, '@');
2289ef1f84bSDavid du Colombier 		if(key == nil)
2299ef1f84bSDavid du Colombier 			error(Eshort);
2309ef1f84bSDavid du Colombier 		*key++ = 0;
2319ef1f84bSDavid du Colombier 
2329ef1f84bSDavid du Colombier 		hmac_sha1((uchar*)from, strlen(from), (uchar*)key, strlen(key), hash, nil);
2339ef1f84bSDavid du Colombier 
2349ef1f84bSDavid du Colombier 		p = remcap(hash);
2359ef1f84bSDavid du Colombier 		if(p == nil){
2369ef1f84bSDavid du Colombier 			snprint(err, sizeof err, "invalid capability %s@%s", from, key);
2379ef1f84bSDavid du Colombier 			error(err);
2389ef1f84bSDavid du Colombier 		}
2399ef1f84bSDavid du Colombier 
2409ef1f84bSDavid du Colombier 		/* if a from user is supplied, make sure it matches */
2419ef1f84bSDavid du Colombier 		to = strchr(from, '@');
2429ef1f84bSDavid du Colombier 		if(to == nil){
2439ef1f84bSDavid du Colombier 			to = from;
2449ef1f84bSDavid du Colombier 		} else {
2459ef1f84bSDavid du Colombier 			*to++ = 0;
2469ef1f84bSDavid du Colombier 			if(strcmp(from, up->user) != 0)
2479ef1f84bSDavid du Colombier 				error("capability must match user");
2489ef1f84bSDavid du Colombier 		}
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier 		/* set user id */
2519ef1f84bSDavid du Colombier 		kstrdup(&up->user, to);
2529ef1f84bSDavid du Colombier 		up->basepri = PriNormal;
2539ef1f84bSDavid du Colombier 
2549ef1f84bSDavid du Colombier 		free(p);
2559ef1f84bSDavid du Colombier 		free(cp);
2569ef1f84bSDavid du Colombier 		poperror();
2579ef1f84bSDavid du Colombier 		break;
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier 	default:
2609ef1f84bSDavid du Colombier 		error(Eperm);
2619ef1f84bSDavid du Colombier 		break;
2629ef1f84bSDavid du Colombier 	}
2639ef1f84bSDavid du Colombier 
2649ef1f84bSDavid du Colombier 	return n;
2659ef1f84bSDavid du Colombier }
2669ef1f84bSDavid du Colombier 
2679ef1f84bSDavid du Colombier Dev capdevtab = {
2689ef1f84bSDavid du Colombier 	L'¤',
2699ef1f84bSDavid du Colombier 	"cap",
2709ef1f84bSDavid du Colombier 
2719ef1f84bSDavid du Colombier 	devreset,
2729ef1f84bSDavid du Colombier 	devinit,
2739ef1f84bSDavid du Colombier 	devshutdown,
2749ef1f84bSDavid du Colombier 	capattach,
2759ef1f84bSDavid du Colombier 	capwalk,
2769ef1f84bSDavid du Colombier 	capstat,
2779ef1f84bSDavid du Colombier 	capopen,
2789ef1f84bSDavid du Colombier 	devcreate,
2799ef1f84bSDavid du Colombier 	capclose,
2809ef1f84bSDavid du Colombier 	capread,
2819ef1f84bSDavid du Colombier 	devbread,
2829ef1f84bSDavid du Colombier 	capwrite,
2839ef1f84bSDavid du Colombier 	devbwrite,
2849ef1f84bSDavid du Colombier 	capremove,
2859ef1f84bSDavid du Colombier 	devwstat
2869ef1f84bSDavid du Colombier };
287