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 "netif.h" 9 #include <libsec.h> 10 11 enum 12 { 13 Hashlen= SHA1dlen, 14 Maxhash= 256, 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 char hash[Hashlen]; 26 ulong ticks; 27 }; 28 29 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 char* 109 hashstr(uchar *hash) 110 { 111 static char buf[256]; 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 static Caphash* 121 remcap(uchar *hash) 122 { 123 Caphash *t, **l; 124 125 qlock(&capalloc); 126 127 /* find the matching capability */ 128 for(l = &capalloc.first; *l != nil;){ 129 t = *l; 130 if(memcmp(hash, t->hash, Hashlen) == 0) 131 break; 132 l = &t->next; 133 } 134 t = *l; 135 if(t != nil){ 136 capalloc.nhash--; 137 *l = t->next; 138 } 139 qunlock(&capalloc); 140 141 return t; 142 } 143 144 /* add a capability, throwing out any old ones */ 145 static void 146 addcap(uchar *hash) 147 { 148 Caphash *p, *t, **l; 149 150 p = smalloc(sizeof *p); 151 memmove(p->hash, hash, Hashlen); 152 p->next = nil; 153 p->ticks = m->ticks; 154 155 qlock(&capalloc); 156 157 /* trim extras */ 158 while(capalloc.nhash >= Maxhash){ 159 t = capalloc.first; 160 if(t == nil) 161 panic("addcap"); 162 capalloc.first = t->next; 163 free(t); 164 capalloc.nhash--; 165 } 166 167 /* add new one */ 168 for(l = &capalloc.first; *l != nil; l = &(*l)->next) 169 ; 170 *l = p; 171 capalloc.nhash++; 172 173 qunlock(&capalloc); 174 } 175 176 static void 177 capclose(Chan*) 178 { 179 } 180 181 static long 182 capread(Chan *c, void *va, long n, vlong) 183 { 184 switch((ulong)c->qid.path){ 185 case Qdir: 186 return devdirread(c, va, n, capdir, ncapdir, devgen); 187 188 default: 189 error(Eperm); 190 break; 191 } 192 return n; 193 } 194 195 static long 196 capwrite(Chan *c, void *va, long n, vlong) 197 { 198 Caphash *p; 199 char *cp; 200 uchar hash[Hashlen]; 201 char *key, *from, *to; 202 char err[256]; 203 204 switch((ulong)c->qid.path){ 205 case Qhash: 206 if(n < Hashlen) 207 error(Eshort); 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 = nil; 215 if(waserror()){ 216 free(cp); 217 nexterror(); 218 } 219 cp = smalloc(n+1); 220 memmove(cp, va, n); 221 cp[n] = 0; 222 223 from = cp; 224 key = strrchr(cp, '@'); 225 if(key == nil) 226 error(Eshort); 227 *key++ = 0; 228 229 hmac_sha1((uchar*)from, strlen(from), (uchar*)key, strlen(key), hash, nil); 230 231 p = remcap(hash); 232 if(p == nil){ 233 snprint(err, sizeof err, "invalid capability %s@%s", from, key); 234 error(err); 235 } 236 237 /* if a from user is supplied, make sure it matches */ 238 to = strchr(from, '@'); 239 if(to == nil){ 240 to = from; 241 } else { 242 *to++ = 0; 243 if(strcmp(from, up->user) != 0) 244 error("capability must match user"); 245 } 246 247 /* set user id */ 248 kstrdup(&up->user, to); 249 up->basepri = PriNormal; 250 251 free(p); 252 free(cp); 253 poperror(); 254 break; 255 256 default: 257 error(Eperm); 258 break; 259 } 260 261 return n; 262 } 263 264 Dev capdevtab = { 265 L'¤', 266 "cap", 267 268 devreset, 269 devinit, 270 devshutdown, 271 capattach, 272 capwalk, 273 capstat, 274 capopen, 275 devcreate, 276 capclose, 277 capread, 278 devbread, 279 capwrite, 280 devbwrite, 281 capremove, 282 devwstat 283 }; 284