ab0cd95cb7d0f7f33e03ac4aabdc973ea5c1a3b6
[akaros.git] / kern / drivers / dev / capability.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 #include <vfs.h>
11 #include <kfs.h>
12 #include <slab.h>
13 #include <kmalloc.h>
14 #include <kref.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <assert.h>
18 #include <error.h>
19 #include <cpio.h>
20 #include <pmap.h>
21 #include <smp.h>
22 #include <ip.h>
23
24 enum {
25         Hashlen = 20, // SHA1dlen,
26         Maxhash = 256,
27 };
28
29 /*
30  *  if a process knows cap->cap, it can change user
31  *  to capabilty->user.
32  */
33 struct Caphash {
34         struct Caphash *next;
35         char hash[Hashlen];
36 };
37
38 struct {
39         qlock_t qlock;
40         struct Caphash *first;
41         int nhash;
42 } capalloc;
43
44 enum {
45         Qdir,
46         Qhash,
47         Quse,
48 };
49
50 /* caphash must be last */
51 struct dirtab capdir[] = {
52         {".",       {Qdir, 0, QTDIR}, 0, DMDIR | 0500},
53         {"capuse",  {Quse}, 0, 0222,},
54         {"caphash", {Qhash},          0, 0200,},
55 };
56 int ncapdir = ARRAY_SIZE(capdir);
57
58 static struct chan *capattach(char *spec)
59 {
60         return devattach("capability", spec);
61 }
62
63 static struct walkqid *capwalk(struct chan *c, struct chan *nc, char **name,
64                                int nname)
65 {
66         return devwalk(c, nc, name, nname, capdir, ncapdir, devgen);
67 }
68
69 static void capremove(struct chan *c)
70 {
71         if (iseve() && c->qid.path == Qhash)
72                 ncapdir = ARRAY_SIZE(capdir) - 1;
73         else
74                 error(EPERM, "Permission denied");
75 }
76
77 static int32_t capstat(struct chan *c, uint8_t *db, int32_t n)
78 {
79         return devstat(c, db, n, capdir, ncapdir, devgen);
80 }
81
82 /*
83  *  if the stream doesn't exist, create it
84  */
85 static struct chan *capopen(struct chan *c, int omode)
86 {
87         if (c->qid.type & QTDIR) {
88                 if (omode != O_RDONLY)
89                         error(EISDIR, "Is a directory");
90                 c->mode = omode;
91                 c->flag |= COPEN;
92                 c->offset = 0;
93                 return c;
94         }
95
96         switch ((uint32_t)c->qid.path) {
97         case Qhash:
98                 if (!iseve())
99                         error(EPERM, "Permission denied: only eve() can open Qhash");
100                 break;
101         }
102
103         c->mode = openmode(omode);
104         c->flag |= COPEN;
105         c->offset = 0;
106         return c;
107 }
108
109 /*
110   static char*
111   hashstr(uint8_t *hash)
112   {
113   static char buf[2*Hashlen+1];
114   int i;
115
116   for(i = 0; i < Hashlen; i++)
117   sprint(buf+2*i, "%2.2x", hash[i]);
118   buf[2*Hashlen] = 0;
119   return buf;
120   }
121 */
122
123 static struct Caphash *remcap(uint8_t *hash)
124 {
125         struct Caphash *t, **l;
126
127         qlock(&capalloc.qlock);
128
129         /* find the matching capability */
130         for (l = &capalloc.first; *l != NULL;) {
131                 t = *l;
132                 if (memcmp(hash, t->hash, Hashlen) == 0)
133                         break;
134                 l = &t->next;
135         }
136         t = *l;
137         if (t != NULL) {
138                 capalloc.nhash--;
139                 *l = t->next;
140         }
141         qunlock(&capalloc.qlock);
142
143         return t;
144 }
145
146 /* add a capability, throwing out any old ones */
147 static void addcap(uint8_t *hash)
148 {
149         struct Caphash *p, *t, **l;
150
151         p = kzmalloc(sizeof(*p), 0);
152         memmove(p->hash, hash, Hashlen);
153         p->next = NULL;
154
155         qlock(&capalloc.qlock);
156
157         /* trim extras */
158         while (capalloc.nhash >= Maxhash) {
159                 t = capalloc.first;
160                 if (t == NULL)
161                         panic("addcap");
162                 capalloc.first = t->next;
163                 kfree(t);
164                 capalloc.nhash--;
165         }
166
167         /* add new one */
168         for (l = &capalloc.first; *l != NULL; l = &(*l)->next)
169                 ;
170         *l = p;
171         capalloc.nhash++;
172
173         qunlock(&capalloc.qlock);
174 }
175
176 static void capclose(struct chan *c)
177 {
178 }
179
180 static long capread(struct chan *c, void *va, long n, int64_t m)
181 {
182         switch ((uint32_t)c->qid.path) {
183         case Qdir:
184                 return devdirread(c, va, n, capdir, ncapdir, devgen);
185
186         default:
187                 error(EPERM, "Permission denied: can't read capability files");
188                 break;
189         }
190         return n;
191 }
192
193 static long capwrite(struct chan *c, void *va, long n, int64_t m)
194 {
195         struct Caphash *p;
196         char *cp;
197         uint8_t hash[Hashlen];
198         char *key, *from, *to;
199         char err[256];
200         ERRSTACK(1);
201
202         switch ((uint32_t)c->qid.path) {
203         case Qhash:
204                 if (!iseve())
205                         error(EPERM, "permission denied: you must be eve");
206                 if (n < Hashlen)
207                         error(EIO, "Short read: on Qhash");
208                 memmove(hash, va, Hashlen);
209                 addcap(hash);
210                 break;
211
212         case Quse:
213                 /* copy key to avoid a fault in hmac_xx */
214                 cp = NULL;
215                 if (waserror()) {
216                         kfree(cp);
217                         nexterror();
218                 }
219                 cp = kzmalloc(n + 1, 0);
220                 memmove(cp, va, n);
221                 cp[n] = 0;
222
223                 from = cp;
224                 key = strrchr(cp, '@');
225                 if (key == NULL)
226                         error(EIO, "short read: Quse");
227                 *key++ = 0;
228
229                 panic("No way to hash");
230                 //hmac_sha1((uint8_t *)from, strlen(from), (uint8_t *)key, strlen(key),
231                 //hash, NULL);
232
233                 p = remcap(hash);
234                 if (p == NULL) {
235                         snprintf(err, sizeof(err), "invalid capability %s@%s", from, key);
236                         error(EINVAL, err);
237                 }
238
239                 /* if a from user is supplied, make sure it matches */
240                 to = strchr(from, '@');
241                 if (to == NULL) {
242                         to = from;
243                 } else {
244                         *to++ = 0;
245                         panic("todo");
246                         /*
247                         if (strcmp(from, up->user) != 0)
248                                 error(EINVAL, "capability must match user");
249                         */
250                 }
251
252                 /* set user id */
253                 // TODO: make user a char *, not a fixed array.
254                 //kstrdup(&current->user, to);
255                 // In the original user names were NULL-terminated; ensure
256                 // that is still the case.
257                 if (strlen(to) > sizeof(current->user)-1)
258                         error(EINVAL, "New user name is > %d bytes", sizeof(current->user));
259                 memset(current->user, 0, sizeof(current->user));
260                 strncpy(current->user, to, sizeof(current->user));
261                 //up->basepri = PriNormal;
262
263
264                 kfree(p);
265                 kfree(cp);
266                 poperror();
267                 break;
268
269         default:
270                 error(EPERM, "permission denied: capwrite");
271                 break;
272         }
273
274         return n;
275 }
276
277 struct dev capdevtab = {
278         .name = "capability",
279
280         .reset = devreset,
281         .init = devinit,
282         .shutdown = devshutdown,
283         .attach = capattach,
284         .walk = capwalk,
285         .stat = capstat,
286         .open = capopen,
287         .create = devcreate,
288         .close = capclose,
289         .read = capread,
290         .bread = devbread,
291         .write = capwrite,
292         .bwrite = devbwrite,
293         .remove = capremove,
294         .wstat = devwstat,
295 };