forsyth20121205-174063a80cc13 years agoHistory
248 lines · 3.9 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"error.h"#include	"mp.h"#include	"libsec.h" /* * Copyright © 2003 Vita Nuova Holdings Limited.  All rights reserved. */ enum {	Captimeout = 15,	/* seconds until expiry */	Capidletime = 60	/* idle seconds before capwatch exits */}; typedef struct Caps Caps;struct Caps{	uchar	hash[SHA1dlen];	ulong	time;	Caps*	next;}; struct {	QLock	l;	Caps*	caps;	int	kpstarted;} allcaps; enum {	Qdir,	Qhash,	Quse}; static Dirtab capdir[] ={	".",			{Qdir, 0, QTDIR},	0,	DMDIR|0555,	"capuse",		{Quse, 0},			0,	0222,	"caphash",	{Qhash, 0},		0,	0200,}; static int ncapdir = nelem(capdir); static voidcapwatch(void *a){	Caps *c, **l;	int idletime; 	USED(a);	idletime = 0;	for(;;){		tsleep(&up->sleep, return0, nil, 30*1000);		qlock(&allcaps.l);		for(l = &allcaps.caps; (c = *l) != nil;)			if(++c->time > Captimeout){				*l = c->next;				free(c);			}else				l = &c->next;		if(allcaps.caps == nil){			if(++idletime > Capidletime){				allcaps.kpstarted = 0;				qunlock(&allcaps.l);				pexit("", 0);			}		}else			idletime = 0;		qunlock(&allcaps.l);	}} 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, nelem(capdir), devgen);} static intcapstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, capdir, nelem(capdir), devgen);} static Chan*capopen(Chan *c, int omode){	if(c->qid.type & QTDIR) {		if(omode != OREAD)			error(Eisdir);		c->mode = omode;		c->flag |= COPEN;		c->offset = 0;		return c;	} 	if(c->qid.path == Qhash && !iseve())		error(Eperm); 	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} static voidcapclose(Chan *c){	USED(c);} static longcapread(Chan *c, void *va, long n, vlong vl){	USED(vl);	switch((ulong)c->qid.path){	case Qdir:		return devdirread(c, va, n, capdir, ncapdir, devgen); 	default:		error(Eperm);		break;	}	return n;} static intcapwritehash(uchar *a, int l){	Caps *c; 	if(l != SHA1dlen)		return -1;	c = malloc(sizeof(*c));	if(c == nil)		return -1;	memmove(c->hash, a, l);	c->time = 0;	qlock(&allcaps.l);	c->next = allcaps.caps;	allcaps.caps = c;	if(!allcaps.kpstarted){		allcaps.kpstarted = 1;		kproc("capwatch", capwatch, 0, 0);	}	qunlock(&allcaps.l);	return 0;} static intcapwriteuse(uchar *a, int len){	int n;	uchar digest[SHA1dlen];	char buf[128], *p, *users[3];	Caps *c, **l; 	if(len >= sizeof(buf)-1)		return -1;	memmove(buf, a, len);	buf[len] = 0;	p = strrchr(buf, '@');	if(p == nil)		return -1;	*p++ = 0;	len = strlen(p);	n = strlen(buf);	if(len == 0 || n == 0)		return -1;	hmac_sha1((uchar*)buf, n, (uchar*)p, len, digest, nil);	n = getfields(buf, users, nelem(users), 0, "@");	if(n == 1)		users[1] = users[0];	else if(n != 2)		return -1;	if(*users[0] == 0 || *users[1] == 0)		return -1;	qlock(&allcaps.l);	for(l = &allcaps.caps; (c = *l) != nil; l = &c->next)		if(memcmp(c->hash, digest, sizeof(c->hash)) == 0){			*l = c->next;			qunlock(&allcaps.l);			free(c);			if(n == 2 && strcmp(up->env->user, users[0]) != 0)				return -1;			kstrdup(&up->env->user, users[1]);			return 0;		}	qunlock(&allcaps.l);	return -1;} static long	 capwrite(Chan* c, void* buf, long n, vlong offset){	USED(offset);	switch((ulong)c->qid.path){	case Qhash:		if(capwritehash(buf, n) < 0)			error(Ebadarg);		return n;	case Quse:		if(capwriteuse(buf, n) < 0)			error("invalid capability");		return n;	}	error(Ebadarg);	return 0;} static voidcapremove(Chan *c){	if(c->qid.path != Qhash || !iseve())		error(Eperm);	ncapdir = nelem(capdir)-1;} Dev capdevtab = {	L'¤',	"cap", 	devreset,	devinit,	devshutdown,	capattach,	capwalk,	capstat,	capopen,	devcreate,	capclose,	capread,	devbread,	capwrite,	devbwrite,	capremove,	devwstat};