devcap.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. #include <libsec.h>
  16. enum
  17. {
  18. Hashlen= SHA1dlen,
  19. Maxhash= 256,
  20. };
  21. /*
  22. * if a process knows cap->cap, it can change user
  23. * to capabilty->user.
  24. */
  25. typedef struct Caphash Caphash;
  26. struct Caphash
  27. {
  28. Caphash *next;
  29. char hash[Hashlen];
  30. uint32_t ticks;
  31. };
  32. struct
  33. {
  34. QLock QLock;
  35. Caphash *first;
  36. int nhash;
  37. } capalloc;
  38. enum
  39. {
  40. Qdir,
  41. Qhash,
  42. Quse,
  43. };
  44. /* caphash must be last */
  45. Dirtab capdir[] =
  46. {
  47. ".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
  48. "capuse", {Quse}, 0, 0222,
  49. "caphash", {Qhash}, 0, 0200,
  50. };
  51. int ncapdir = nelem(capdir);
  52. static Chan*
  53. capattach(char *spec)
  54. {
  55. return devattach(L'¤', spec);
  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. static void
  63. capremove(Chan *c)
  64. {
  65. if(iseve() && c->qid.path == Qhash)
  66. ncapdir = nelem(capdir)-1;
  67. else
  68. error(Eperm);
  69. }
  70. static int32_t
  71. capstat(Chan *c, uint8_t *db, int32_t n)
  72. {
  73. return devstat(c, db, n, capdir, ncapdir, devgen);
  74. }
  75. /*
  76. * if the stream doesn't exist, create it
  77. */
  78. static Chan*
  79. capopen(Chan *c, int omode)
  80. {
  81. if(c->qid.type & QTDIR){
  82. if(omode != OREAD)
  83. error(Ebadarg);
  84. c->mode = omode;
  85. c->flag |= COPEN;
  86. c->offset = 0;
  87. return c;
  88. }
  89. switch((uint32_t)c->qid.path){
  90. case Qhash:
  91. if(!iseve())
  92. error(Eperm);
  93. break;
  94. }
  95. c->mode = openmode(omode);
  96. c->flag |= COPEN;
  97. c->offset = 0;
  98. return c;
  99. }
  100. /*
  101. static char*
  102. hashstr(uchar *hash)
  103. {
  104. static char buf[2*Hashlen+1];
  105. int i;
  106. for(i = 0; i < Hashlen; i++)
  107. sprint(buf+2*i, "%2.2x", hash[i]);
  108. buf[2*Hashlen] = 0;
  109. return buf;
  110. }
  111. */
  112. static Caphash*
  113. remcap(uint8_t *hash)
  114. {
  115. Caphash *t, **l;
  116. qlock(&capalloc.QLock);
  117. /* find the matching capability */
  118. for(l = &capalloc.first; *l != nil;){
  119. t = *l;
  120. if(memcmp(hash, t->hash, Hashlen) == 0)
  121. break;
  122. l = &t->next;
  123. }
  124. t = *l;
  125. if(t != nil){
  126. capalloc.nhash--;
  127. *l = t->next;
  128. }
  129. qunlock(&capalloc.QLock);
  130. return t;
  131. }
  132. /* add a capability, throwing out any old ones */
  133. static void
  134. addcap(uint8_t *hash)
  135. {
  136. Caphash *p, *t, **l;
  137. p = smalloc(sizeof *p);
  138. memmove(p->hash, hash, Hashlen);
  139. p->next = nil;
  140. p->ticks = machp()->ticks;
  141. qlock(&capalloc.QLock);
  142. /* trim extras */
  143. while(capalloc.nhash >= Maxhash){
  144. t = capalloc.first;
  145. if(t == nil)
  146. panic("addcap");
  147. capalloc.first = t->next;
  148. free(t);
  149. capalloc.nhash--;
  150. }
  151. /* add new one */
  152. for(l = &capalloc.first; *l != nil; l = &(*l)->next)
  153. ;
  154. *l = p;
  155. capalloc.nhash++;
  156. qunlock(&capalloc.QLock);
  157. }
  158. static void
  159. capclose(Chan* c)
  160. {
  161. }
  162. static int32_t
  163. capread(Chan *c, void *va, int32_t n, int64_t m)
  164. {
  165. switch((uint32_t)c->qid.path){
  166. case Qdir:
  167. return devdirread(c, va, n, capdir, ncapdir, devgen);
  168. default:
  169. error(Eperm);
  170. break;
  171. }
  172. return n;
  173. }
  174. static int32_t
  175. capwrite(Chan *c, void *va, int32_t n, int64_t m)
  176. {
  177. Caphash *p;
  178. char *cp;
  179. uint8_t hash[Hashlen];
  180. char *key, *from, *to;
  181. char err[256];
  182. switch((uint32_t)c->qid.path){
  183. case Qhash:
  184. if(!iseve())
  185. error(Eperm);
  186. if(n < Hashlen)
  187. error(Eshort);
  188. memmove(hash, va, Hashlen);
  189. addcap(hash);
  190. break;
  191. case Quse:
  192. /* copy key to avoid a fault in hmac_xx */
  193. cp = nil;
  194. if(waserror()){
  195. free(cp);
  196. nexterror();
  197. }
  198. cp = smalloc(n+1);
  199. memmove(cp, va, n);
  200. cp[n] = 0;
  201. from = cp;
  202. key = strrchr(cp, '@');
  203. if(key == nil)
  204. error(Eshort);
  205. *key++ = 0;
  206. panic("need a sha256");
  207. //hmac_sha1((uint8_t*)from, strlen(from), (uint8_t*)key,
  208. //strlen(key), hash, nil);
  209. p = remcap(hash);
  210. if(p == nil){
  211. snprint(err, sizeof err, "invalid capability %s@%s", from, key);
  212. error(err);
  213. }
  214. /* if a from user is supplied, make sure it matches */
  215. to = strchr(from, '@');
  216. if(to == nil){
  217. to = from;
  218. } else {
  219. *to++ = 0;
  220. if(strcmp(from, up->user) != 0)
  221. error("capability must match user");
  222. }
  223. /* set user id */
  224. kstrdup(&up->user, to);
  225. up->basepri = PriNormal;
  226. free(p);
  227. free(cp);
  228. poperror();
  229. break;
  230. default:
  231. error(Eperm);
  232. break;
  233. }
  234. return n;
  235. }
  236. Dev capdevtab = {
  237. .dc = L'¤',
  238. .name = "cap",
  239. .reset = devreset,
  240. .init = devinit,
  241. .shutdown = devshutdown,
  242. .attach = capattach,
  243. .walk = capwalk,
  244. .stat = capstat,
  245. .open = capopen,
  246. .create = devcreate,
  247. .close = capclose,
  248. .read = capread,
  249. .bread = devbread,
  250. .write = capwrite,
  251. .bwrite = devbwrite,
  252. .remove = capremove,
  253. .wstat = devwstat
  254. };