1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 #include "mp.h" 8 #include "libsec.h" 9 10 /* 11 * Copyright © 2003 Vita Nuova Holdings Limited. All rights reserved. 12 */ 13 14 enum { 15 Captimeout = 15, /* seconds until expiry */ 16 Capidletime = 60 /* idle seconds before capwatch exits */ 17 }; 18 19 typedef struct Caps Caps; 20 struct Caps 21 { 22 uchar hash[SHA1dlen]; 23 ulong time; 24 Caps* next; 25 }; 26 27 struct { 28 QLock l; 29 Caps* caps; 30 int kpstarted; 31 } allcaps; 32 33 enum { 34 Qdir, 35 Qhash, 36 Quse 37 }; 38 39 static Dirtab capdir[] = 40 { 41 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 42 "capuse", {Quse, 0}, 0, 0222, 43 "caphash", {Qhash, 0}, 0, 0200, 44 }; 45 46 static int ncapdir = nelem(capdir); 47 48 static void 49 capwatch(void *a) 50 { 51 Caps *c, **l; 52 int idletime; 53 54 USED(a); 55 idletime = 0; 56 for(;;){ 57 tsleep(&up->sleep, return0, nil, 30*1000); 58 qlock(&allcaps.l); 59 for(l = &allcaps.caps; (c = *l) != nil;) 60 if(++c->time > Captimeout){ 61 *l = c->next; 62 free(c); 63 }else 64 l = &c->next; 65 if(allcaps.caps == nil){ 66 if(++idletime > Capidletime){ 67 allcaps.kpstarted = 0; 68 qunlock(&allcaps.l); 69 pexit("", 0); 70 } 71 }else 72 idletime = 0; 73 qunlock(&allcaps.l); 74 } 75 } 76 77 static Chan * 78 capattach(char *spec) 79 { 80 return devattach(L'¤', spec); 81 } 82 83 static Walkqid* 84 capwalk(Chan *c, Chan *nc, char **name, int nname) 85 { 86 return devwalk(c, nc, name, nname, capdir, nelem(capdir), devgen); 87 } 88 89 static int 90 capstat(Chan *c, uchar *db, int n) 91 { 92 return devstat(c, db, n, capdir, nelem(capdir), devgen); 93 } 94 95 static Chan* 96 capopen(Chan *c, int omode) 97 { 98 if(c->qid.type & QTDIR) { 99 if(omode != OREAD) 100 error(Eisdir); 101 c->mode = omode; 102 c->flag |= COPEN; 103 c->offset = 0; 104 return c; 105 } 106 107 if(c->qid.path == Qhash && !iseve()) 108 error(Eperm); 109 110 c->mode = openmode(omode); 111 c->flag |= COPEN; 112 c->offset = 0; 113 return c; 114 } 115 116 static void 117 capclose(Chan *c) 118 { 119 USED(c); 120 } 121 122 static long 123 capread(Chan *c, void *va, long n, vlong vl) 124 { 125 USED(vl); 126 switch((ulong)c->qid.path){ 127 case Qdir: 128 return devdirread(c, va, n, capdir, ncapdir, devgen); 129 130 default: 131 error(Eperm); 132 break; 133 } 134 return n; 135 } 136 137 static int 138 capwritehash(uchar *a, int l) 139 { 140 Caps *c; 141 142 if(l != SHA1dlen) 143 return -1; 144 c = malloc(sizeof(*c)); 145 if(c == nil) 146 return -1; 147 memmove(c->hash, a, l); 148 c->time = 0; 149 qlock(&allcaps.l); 150 c->next = allcaps.caps; 151 allcaps.caps = c; 152 if(!allcaps.kpstarted){ 153 allcaps.kpstarted = 1; 154 kproc("capwatch", capwatch, 0, 0); 155 } 156 qunlock(&allcaps.l); 157 return 0; 158 } 159 160 static int 161 capwriteuse(uchar *a, int len) 162 { 163 int n; 164 uchar digest[SHA1dlen]; 165 char buf[128], *p, *users[3]; 166 Caps *c, **l; 167 168 if(len >= sizeof(buf)-1) 169 return -1; 170 memmove(buf, a, len); 171 buf[len] = 0; 172 p = strrchr(buf, '@'); 173 if(p == nil) 174 return -1; 175 *p++ = 0; 176 len = strlen(p); 177 n = strlen(buf); 178 if(len == 0 || n == 0) 179 return -1; 180 hmac_sha1((uchar*)buf, n, (uchar*)p, len, digest, nil); 181 n = getfields(buf, users, nelem(users), 0, "@"); 182 if(n == 1) 183 users[1] = users[0]; 184 else if(n != 2) 185 return -1; 186 if(*users[0] == 0 || *users[1] == 0) 187 return -1; 188 qlock(&allcaps.l); 189 for(l = &allcaps.caps; (c = *l) != nil; l = &c->next) 190 if(memcmp(c->hash, digest, sizeof(c->hash)) == 0){ 191 *l = c->next; 192 qunlock(&allcaps.l); 193 free(c); 194 if(n == 2 && strcmp(up->env->user, users[0]) != 0) 195 return -1; 196 kstrdup(&up->env->user, users[1]); 197 return 0; 198 } 199 qunlock(&allcaps.l); 200 return -1; 201 } 202 203 static long 204 capwrite(Chan* c, void* buf, long n, vlong offset) 205 { 206 USED(offset); 207 switch((ulong)c->qid.path){ 208 case Qhash: 209 if(capwritehash(buf, n) < 0) 210 error(Ebadarg); 211 return n; 212 case Quse: 213 if(capwriteuse(buf, n) < 0) 214 error("invalid capability"); 215 return n; 216 } 217 error(Ebadarg); 218 return 0; 219 } 220 221 static void 222 capremove(Chan *c) 223 { 224 if(c->qid.path != Qhash || !iseve()) 225 error(Eperm); 226 ncapdir = nelem(capdir)-1; 227 } 228 229 Dev capdevtab = { 230 L'¤', 231 "cap", 232 233 devreset, 234 devinit, 235 devshutdown, 236 capattach, 237 capwalk, 238 capstat, 239 capopen, 240 devcreate, 241 capclose, 242 capread, 243 devbread, 244 capwrite, 245 devbwrite, 246 capremove, 247 devwstat 248 }; 249