xref: /plan9/sys/src/9/port/devcap.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
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