vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

devcap.c (4141B)


      1 #include	"u.h"
      2 #include	"lib.h"
      3 #include	"mem.h"
      4 #include	"dat.h"
      5 #include	"fns.h"
      6 #include	"error.h"
      7 
      8 #include	"libsec.h"
      9 
     10 enum
     11 {
     12 	Hashlen=	SHA1dlen,
     13 	Maxhash=	256,
     14 };
     15 
     16 /*
     17  *  if a process knows cap->cap, it can change user
     18  *  to capabilty->user.
     19  */
     20 typedef struct Caphash	Caphash;
     21 struct Caphash
     22 {
     23 	Caphash	*next;
     24 	char		hash[Hashlen];
     25 	ulong		ticks;
     26 };
     27 
     28 struct
     29 {
     30 	QLock l;
     31 	Caphash	*first;
     32 	int	nhash;
     33 } capalloc;
     34 
     35 enum
     36 {
     37 	Qdir,
     38 	Qhash,
     39 	Quse,
     40 };
     41 
     42 /* caphash must be last */
     43 Dirtab capdir[] =
     44 {
     45 	".",		{Qdir,0,QTDIR},	0,		DMDIR|0500,
     46 	"capuse",	{Quse},		0,		0222,
     47 	"caphash",	{Qhash},	0,		0200,
     48 };
     49 int ncapdir = nelem(capdir);
     50 
     51 static Chan*
     52 capattach(char *spec)
     53 {
     54 	return devattach(L'¤', spec);
     55 }
     56 
     57 static Walkqid*
     58 capwalk(Chan *c, Chan *nc, char **name, int nname)
     59 {
     60 	return devwalk(c, nc, name, nname, capdir, ncapdir, devgen);
     61 }
     62 
     63 static void
     64 capremove(Chan *c)
     65 {
     66 	if(iseve() && c->qid.path == Qhash)
     67 		ncapdir = nelem(capdir)-1;
     68 	else
     69 		error(Eperm);
     70 }
     71 
     72 
     73 static int
     74 capstat(Chan *c, uchar *db, int n)
     75 {
     76 	return devstat(c, db, n, capdir, ncapdir, devgen);
     77 }
     78 
     79 /*
     80  *  if the stream doesn't exist, create it
     81  */
     82 static Chan*
     83 capopen(Chan *c, int omode)
     84 {
     85 	if(c->qid.type & QTDIR){
     86 		if(omode != OREAD)
     87 			error(Ebadarg);
     88 		c->mode = omode;
     89 		c->flag |= COPEN;
     90 		c->offset = 0;
     91 		return c;
     92 	}
     93 
     94 	switch((ulong)c->qid.path){
     95 	case Qhash:
     96 		if(!iseve())
     97 			error(Eperm);
     98 		break;
     99 	}
    100 
    101 	c->mode = openmode(omode);
    102 	c->flag |= COPEN;
    103 	c->offset = 0;
    104 	return c;
    105 }
    106 
    107 /*
    108 static char*
    109 hashstr(uchar *hash)
    110 {
    111 	static char buf[2*Hashlen+1];
    112 	int i;
    113 
    114 	for(i = 0; i < Hashlen; i++)
    115 		sprint(buf+2*i, "%2.2ux", hash[i]);
    116 	buf[2*Hashlen] = 0;
    117 	return buf;
    118 }
    119  */
    120 
    121 static Caphash*
    122 remcap(uchar *hash)
    123 {
    124 	Caphash *t, **l;
    125 
    126 	qlock(&capalloc.l);
    127 
    128 	/* find the matching capability */
    129 	for(l = &capalloc.first; *l != nil;){
    130 		t = *l;
    131 		if(memcmp(hash, t->hash, Hashlen) == 0)
    132 			break;
    133 		l = &t->next;
    134 	}
    135 	t = *l;
    136 	if(t != nil){
    137 		capalloc.nhash--;
    138 		*l = t->next;
    139 	}
    140 	qunlock(&capalloc.l);
    141 
    142 	return t;
    143 }
    144 
    145 /* add a capability, throwing out any old ones */
    146 static void
    147 addcap(uchar *hash)
    148 {
    149 	Caphash *p, *t, **l;
    150 
    151 	p = smalloc(sizeof *p);
    152 	memmove(p->hash, hash, Hashlen);
    153 	p->next = nil;
    154 	p->ticks = msec();
    155 
    156 	qlock(&capalloc.l);
    157 
    158 	/* trim extras */
    159 	while(capalloc.nhash >= Maxhash){
    160 		t = capalloc.first;
    161 		if(t == nil)
    162 			panic("addcap");
    163 		capalloc.first = t->next;
    164 		free(t);
    165 		capalloc.nhash--;
    166 	}
    167 
    168 	/* add new one */
    169 	for(l = &capalloc.first; *l != nil; l = &(*l)->next)
    170 		;
    171 	*l = p;
    172 	capalloc.nhash++;
    173 
    174 	qunlock(&capalloc.l);
    175 }
    176 
    177 static void
    178 capclose(Chan *c)
    179 {
    180 }
    181 
    182 static long
    183 capread(Chan *c, void *va, long n, vlong vl)
    184 {
    185 	switch((ulong)c->qid.path){
    186 	case Qdir:
    187 		return devdirread(c, va, n, capdir, ncapdir, devgen);
    188 
    189 	default:
    190 		error(Eperm);
    191 		break;
    192 	}
    193 	return n;
    194 }
    195 
    196 static long
    197 capwrite(Chan *c, void *va, long n, vlong vl)
    198 {
    199 	Caphash *p;
    200 	char *cp;
    201 	uchar hash[Hashlen];
    202 	char *key, *from, *to;
    203 	char err[256];
    204 
    205 	switch((ulong)c->qid.path){
    206 	case Qhash:
    207 		if(!iseve())
    208 			error(Eperm);
    209 		if(n < Hashlen)
    210 			error(Eshort);
    211 		memmove(hash, va, Hashlen);
    212 		addcap(hash);
    213 		break;
    214 
    215 	case Quse:
    216 		/* copy key to avoid a fault in hmac_xx */
    217 		cp = nil;
    218 		if(waserror()){
    219 			free(cp);
    220 			nexterror();
    221 		}
    222 		cp = smalloc(n+1);
    223 		memmove(cp, va, n);
    224 		cp[n] = 0;
    225 
    226 		from = cp;
    227 		key = strrchr(cp, '@');
    228 		if(key == nil)
    229 			error(Eshort);
    230 		*key++ = 0;
    231 
    232 		hmac_sha1((uchar*)from, strlen(from), (uchar*)key, strlen(key), hash, nil);
    233 
    234 		p = remcap(hash);
    235 		if(p == nil){
    236 			snprint(err, sizeof err, "invalid capability %s@%s", from, key);
    237 			error(err);
    238 		}
    239 
    240 		/* if a from user is supplied, make sure it matches */
    241 		to = strchr(from, '@');
    242 		if(to == nil){
    243 			to = from;
    244 		} else {
    245 			*to++ = 0;
    246 			if(strcmp(from, up->user) != 0)
    247 				error("capability must match user");
    248 		}
    249 
    250 		/* set user id */
    251 		kstrdup(&up->user, to);
    252 		up->basepri = PriNormal;
    253 
    254 		free(p);
    255 		free(cp);
    256 		poperror();
    257 		break;
    258 
    259 	default:
    260 		error(Eperm);
    261 		break;
    262 	}
    263 
    264 	return n;
    265 }
    266 
    267 Dev capdevtab = {
    268 	L'¤',
    269 	"cap",
    270 
    271 	devreset,
    272 	devinit,
    273 	devshutdown,
    274 	capattach,
    275 	capwalk,
    276 	capstat,
    277 	capopen,
    278 	devcreate,
    279 	capclose,
    280 	capread,
    281 	devbread,
    282 	capwrite,
    283 	devbwrite,
    284 	capremove,
    285 	devwstat
    286 };