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