Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/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;
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
		seprint(buf+2*i, &buf[sizeof buf], "%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);
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);
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 = m->ticks;
155
 
156
	qlock(&capalloc);
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);
175
}
176
 
177
static void
178
capclose(Chan*)
179
{
180
}
181
 
182
static long
183
capread(Chan *c, void *va, long n, vlong)
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)
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
};