FreeBSD/Linux Kernel Cross Reference
sys/port/devcap.c
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 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);
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 };
Cache object: bf3747d00eebda856605c05b87442b51
|