devcap.c (4141B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "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 l; 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.l); 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.l); 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 = msec(); 155 156 qlock(&capalloc.l); 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.l); 175 } 176 177 static void 178 capclose(Chan *c) 179 { 180 } 181 182 static long 183 capread(Chan *c, void *va, long n, vlong vl) 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 vl) 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 };