]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devcap.c
merge
[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 };
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 };