plan 9 kernel history: overview | file list | diff list

2002/0202/port/devcap.c (diff list | history)

2002/0202/sys/src/9/port/devcap.c:1,2772002/0622/sys/src/9/port/devcap.c:1,279 (short | long | prev | next)
2001/0527    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
#include	"netif.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; 
	int	opens; 
	Caphash	*first; 
	int	nhash; 
} capalloc; 
 
enum 
{ 
	Qdir, 
	Qhash, 
	Quse, 
}; 
 
Dirtab capdir[] = 
{ 
	".",		{Qdir,0,QTDIR},	0,		DMDIR|0500, 
	"caphash",	{Qhash},	0,		0200, 
	"capuse",	{Quse},		0,		0222, 
}; 
#define NCAPDIR 3 
 
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 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; 
	} 
 
	if(waserror()){ 
		qunlock(&capalloc); 
		nexterror(); 
	} 
	qlock(&capalloc); 
	switch((ulong)c->qid.path){ 
	case Qhash: 
2002/0622    
		if(!iseve()) 
			error(Eperm); 
2001/0527    
		if(capalloc.opens > 0){ 
			qunlock(&capalloc); 
			error("exclusive use"); 
		} 
		capalloc.opens++; 
		break; 
	} 
	poperror(); 
	qunlock(&capalloc); 
 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
static Caphash* 
remcap(uchar *hash) 
{ 
	Caphash *t, **l; 
 
	qlock(&capalloc); 
 
	/* 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); 
 
	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 = m->ticks; 
 
	qlock(&capalloc); 
 
	/* 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); 
} 
 
static void 
capclose(Chan *c) 
{ 
	if(c->flag & COPEN) 
		if(c->qid.path == Qhash){ 
			qlock(&capalloc); 
			capalloc.opens--; 
			qunlock(&capalloc); 
		} 
} 
 
static long 
capread(Chan *c, void *va, long n, vlong) 
{ 
	switch((ulong)c->qid.path){ 
	case Qdir: 
		return devdirread(c, va, n, capdir, nelem(capdir), devgen); 
 
	default: 
		error(Eperm); 
		break; 
	} 
	return n; 
} 
 
static long 
capwrite(Chan *c, void *va, long n, vlong) 
{ 
	Caphash *p; 
	char *cp; 
	uchar hash[Hashlen]; 
2002/0202    
	char *key, *from, *to; 
2001/0527    
	char err[256]; 
 
	switch((ulong)c->qid.path){ 
	case Qhash: 
		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; 
 
2002/0202    
		from = cp; 
		key = strrchr(cp, '@'); 
2001/0527    
		if(key == nil) 
			error(Eshort); 
		*key++ = 0; 
 
2002/0202    
		hmac_sha1((uchar*)from, strlen(from), (uchar*)key, strlen(key), hash, nil); 
2001/0527    
 
		p = remcap(hash); 
		if(p == nil){ 
2002/0202    
			snprint(err, sizeof err, "invalid capability %s@%s", from, key); 
2001/0527    
			error(err); 
		} 
 
2002/0202    
		/* 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"); 
		} 
 
2001/0527    
		/* set user id */ 
2002/0202    
		kstrdup(&up->user, to); 
2001/0527    
		up->basepri = PriNormal; 
 
		free(p); 
		free(cp); 
		poperror(); 
		break; 
 
	default: 
		error(Eperm); 
		break; 
	} 
 
	return n; 
} 
 
Dev capdevtab = { 
	L'¤', 
	"cap", 
 
	devreset, 
	devinit, 
2002/0109    
	devshutdown, 
2001/0527    
	capattach, 
	capwalk, 
	capstat, 
	capopen, 
	devcreate, 
	capclose, 
	capread, 
	devbread, 
	capwrite, 
	devbwrite, 
	devremove, 
	devwstat, 
}; 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)