keyfs.c 17 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <authsrv.h>
  4. #include <fcall.h>
  5. #include <bio.h>
  6. #include <mp.h>
  7. #include <libsec.h>
  8. #include "authcmdlib.h"
  9. char authkey[8];
  10. typedef struct Fid Fid;
  11. typedef struct User User;
  12. enum{
  13. Qroot,
  14. Quser,
  15. Qkey,
  16. Qsecret,
  17. Qlog,
  18. Qstatus,
  19. Qexpire,
  20. Qwarnings,
  21. Qmax,
  22. Nuser = 512,
  23. MAXBAD = 10, /* max number of bad attempts before disabling the account */
  24. Namelen = ANAMELEN, /* file must be randomly addressible, so names have fixed length */
  25. };
  26. enum{
  27. Sok,
  28. Sdisabled,
  29. Stempdisabled,
  30. Smax,
  31. };
  32. struct Fid{
  33. int fid;
  34. ulong qtype;
  35. User *user;
  36. int busy;
  37. Fid *next;
  38. };
  39. struct User{
  40. char *name;
  41. char key[DESKEYLEN];
  42. char secret[SECRETLEN];
  43. ulong expire; /* 0 == never */
  44. uchar status;
  45. ulong bad; /* number of consecutive bad authentication attempts */
  46. int ref;
  47. char removed;
  48. uchar warnings;
  49. long purgatory; /* time purgatory ends */
  50. ulong uniq;
  51. User *link;
  52. };
  53. char *qinfo[Qmax] = {
  54. [Qroot] "keys",
  55. [Quser] ".",
  56. [Qkey] "key",
  57. [Qsecret] "secret",
  58. [Qlog] "log",
  59. [Qexpire] "expire",
  60. [Qstatus] "status",
  61. [Qwarnings] "warnings",
  62. };
  63. char *status[Smax] = {
  64. [Sok] "ok",
  65. [Sdisabled] "disabled",
  66. };
  67. Fid *fids;
  68. User *users[Nuser];
  69. char *userkeys;
  70. int nuser;
  71. ulong uniq = 1;
  72. Fcall rhdr,
  73. thdr;
  74. int usepass;
  75. char *warnarg;
  76. uchar mdata[8192 + IOHDRSZ];
  77. int messagesize = sizeof mdata;
  78. int readusers(void);
  79. ulong hash(char*);
  80. Fid *findfid(int);
  81. User *finduser(char*);
  82. User *installuser(char*);
  83. int removeuser(User*);
  84. void insertuser(User*);
  85. void writeusers(void);
  86. void io(int, int);
  87. void *emalloc(ulong);
  88. Qid mkqid(User*, ulong);
  89. int dostat(User*, ulong, void*, int);
  90. int newkeys(void);
  91. void warning(void);
  92. char *Auth(Fid*), *Attach(Fid*), *Version(Fid*),
  93. *Flush(Fid*), *Walk(Fid*),
  94. *Open(Fid*), *Create(Fid*),
  95. *Read(Fid *), *Write(Fid*), *Clunk(Fid*),
  96. *Remove(Fid *), *Stat(Fid*), *Wstat(Fid*);
  97. char *(*fcalls[])(Fid*) = {
  98. [Tattach] Attach,
  99. [Tauth] Auth,
  100. [Tclunk] Clunk,
  101. [Tcreate] Create,
  102. [Tflush] Flush,
  103. [Topen] Open,
  104. [Tread] Read,
  105. [Tremove] Remove,
  106. [Tstat] Stat,
  107. [Tversion] Version,
  108. [Twalk] Walk,
  109. [Twrite] Write,
  110. [Twstat] Wstat,
  111. };
  112. void
  113. main(int argc, char *argv[])
  114. {
  115. char *mntpt;
  116. int p[2];
  117. mntpt = "/mnt/keys";
  118. ARGBEGIN{
  119. case 'm':
  120. mntpt = ARGF();
  121. break;
  122. case 'w':
  123. warnarg = ARGF();
  124. break;
  125. case 'p':
  126. usepass = 1;
  127. break;
  128. }ARGEND
  129. argv0 = "keyfs";
  130. userkeys = "/adm/keys";
  131. if(argc > 0)
  132. userkeys = argv[0];
  133. if(pipe(p) < 0)
  134. error("can't make pipe: %r");
  135. switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){
  136. case 0:
  137. close(p[0]);
  138. io(p[1], p[1]);
  139. exits(0);
  140. case -1:
  141. error("fork");
  142. default:
  143. close(p[1]);
  144. if(mount(p[0], -1, mntpt, MREPL|MCREATE, "") < 0)
  145. error("can't mount: %r");
  146. exits(0);
  147. }
  148. }
  149. char *
  150. Flush(Fid *f)
  151. {
  152. USED(f);
  153. return 0;
  154. }
  155. char *
  156. Auth(Fid *)
  157. {
  158. return "keyfs: authentication not required";
  159. }
  160. char *
  161. Attach(Fid *f)
  162. {
  163. if(f->busy)
  164. Clunk(f);
  165. f->user = 0;
  166. f->qtype = Qroot;
  167. f->busy = 1;
  168. thdr.qid = mkqid(f->user, f->qtype);
  169. return 0;
  170. }
  171. char*
  172. Version(Fid*)
  173. {
  174. Fid *f;
  175. for(f = fids; f; f = f->next)
  176. if(f->busy)
  177. Clunk(f);
  178. if(rhdr.msize > sizeof mdata)
  179. thdr.msize = sizeof mdata;
  180. else
  181. thdr.msize = rhdr.msize;
  182. messagesize = thdr.msize;
  183. if(strncmp(rhdr.version, "9P2000", 6) != 0)
  184. return "bad 9P version";
  185. thdr.version = "9P2000";
  186. return 0;
  187. }
  188. char *
  189. Walk(Fid *f)
  190. {
  191. char *name, *err;
  192. int i, j, max;
  193. Fid *nf;
  194. ulong qtype;
  195. User *user;
  196. if(!f->busy)
  197. return "walk of unused fid";
  198. nf = nil;
  199. qtype = f->qtype;
  200. user = f->user;
  201. if(rhdr.fid != rhdr.newfid){
  202. nf = findfid(rhdr.newfid);
  203. if(nf->busy)
  204. return "fid in use";
  205. f = nf; /* walk f */
  206. }
  207. err = nil;
  208. i = 0;
  209. if(rhdr.nwname > 0){
  210. for(; i<rhdr.nwname; i++){
  211. if(i >= MAXWELEM){
  212. err = "too many path name elements";
  213. break;
  214. }
  215. name = rhdr.wname[i];
  216. switch(qtype){
  217. case Qroot:
  218. if(strcmp(name, "..") == 0)
  219. goto Accept;
  220. user = finduser(name);
  221. if(!user)
  222. goto Out;
  223. qtype = Quser;
  224. Accept:
  225. thdr.wqid[i] = mkqid(user, qtype);
  226. break;
  227. case Quser:
  228. max = Qmax;
  229. for(j = Quser + 1; j < Qmax; j++)
  230. if(strcmp(name, qinfo[j]) == 0){
  231. qtype = j;
  232. break;
  233. }
  234. if(j < max)
  235. goto Accept;
  236. goto Out;
  237. default:
  238. err = "file is not a directory";
  239. goto Out;
  240. }
  241. }
  242. Out:
  243. if(i < rhdr.nwname && err == nil)
  244. err = "file not found";
  245. }
  246. if(err != nil){
  247. return err;
  248. }
  249. /* if we cloned and then completed the walk, update new fid */
  250. if(rhdr.fid != rhdr.newfid && i == rhdr.nwname){
  251. nf->busy = 1;
  252. nf->qtype = qtype;
  253. if(nf->user = user)
  254. nf->user->ref++;
  255. }else if(nf == nil && rhdr.nwname > 0){ /* walk without clone (rare) */
  256. Clunk(f);
  257. f->busy = 1;
  258. f->qtype = qtype;
  259. if(f->user = user)
  260. f->user->ref++;
  261. }
  262. thdr.nwqid = i;
  263. return 0;
  264. }
  265. char *
  266. Clunk(Fid *f)
  267. {
  268. f->busy = 0;
  269. if(f->user && --f->user->ref == 0 && f->user->removed)
  270. free(f->user);
  271. f->user = 0;
  272. return 0;
  273. }
  274. char *
  275. Open(Fid *f)
  276. {
  277. int mode;
  278. if(!f->busy)
  279. return "open of unused fid";
  280. mode = rhdr.mode;
  281. if(f->qtype == Quser && (mode & (OWRITE|OTRUNC)))
  282. return "user already exists";
  283. thdr.qid = mkqid(f->user, f->qtype);
  284. thdr.iounit = messagesize - IOHDRSZ;
  285. return 0;
  286. }
  287. char *
  288. Create(Fid *f)
  289. {
  290. char *name;
  291. long perm;
  292. if(!f->busy)
  293. return "create of unused fid";
  294. name = rhdr.name;
  295. if(f->user){
  296. return "permission denied";
  297. }else{
  298. perm = rhdr.perm;
  299. if(!(perm & DMDIR))
  300. return "permission denied";
  301. if(strcmp(name, "") == 0)
  302. return "empty file name";
  303. if(strlen(name) >= Namelen)
  304. return "file name too long";
  305. if(finduser(name))
  306. return "user already exists";
  307. f->user = installuser(name);
  308. f->user->ref++;
  309. f->qtype = Quser;
  310. }
  311. thdr.qid = mkqid(f->user, f->qtype);
  312. thdr.iounit = messagesize - IOHDRSZ;
  313. writeusers();
  314. return 0;
  315. }
  316. char *
  317. Read(Fid *f)
  318. {
  319. User *u;
  320. char *data;
  321. ulong off, n, m;
  322. int i, j, max;
  323. if(!f->busy)
  324. return "read of unused fid";
  325. n = rhdr.count;
  326. off = rhdr.offset;
  327. thdr.count = 0;
  328. data = thdr.data;
  329. switch(f->qtype){
  330. case Qroot:
  331. j = 0;
  332. for(i = 0; i < Nuser; i++)
  333. for(u = users[i]; u; j += m, u = u->link){
  334. m = dostat(u, Quser, data, n);
  335. if(m <= BIT16SZ)
  336. break;
  337. if(j < off)
  338. continue;
  339. data += m;
  340. n -= m;
  341. }
  342. thdr.count = data - thdr.data;
  343. return 0;
  344. case Quser:
  345. max = Qmax;
  346. max -= Quser + 1;
  347. j = 0;
  348. for(i = 0; i < max; j += m, i++){
  349. m = dostat(f->user, i + Quser + 1, data, n);
  350. if(m <= BIT16SZ)
  351. break;
  352. if(j < off)
  353. continue;
  354. data += m;
  355. n -= m;
  356. }
  357. thdr.count = data - thdr.data;
  358. return 0;
  359. case Qkey:
  360. if(f->user->status != Sok)
  361. return "user disabled";
  362. if(f->user->purgatory > time(0))
  363. return "user in purgatory";
  364. if(f->user->expire != 0 && f->user->expire < time(0))
  365. return "user expired";
  366. if(off != 0)
  367. return 0;
  368. if(n > DESKEYLEN)
  369. n = DESKEYLEN;
  370. memmove(thdr.data, f->user->key, n);
  371. thdr.count = n;
  372. return 0;
  373. case Qsecret:
  374. if(f->user->status != Sok)
  375. return "user disabled";
  376. if(f->user->purgatory > time(0))
  377. return "user in purgatory";
  378. if(f->user->expire != 0 && f->user->expire < time(0))
  379. return "user expired";
  380. if(off != 0)
  381. return 0;
  382. if(n > strlen(f->user->secret))
  383. n = strlen(f->user->secret);
  384. memmove(thdr.data, f->user->secret, n);
  385. thdr.count = n;
  386. return 0;
  387. case Qstatus:
  388. if(off != 0){
  389. thdr.count = 0;
  390. return 0;
  391. }
  392. if(f->user->status == Sok && f->user->expire && f->user->expire < time(0))
  393. sprint(thdr.data, "expired\n");
  394. else
  395. sprint(thdr.data, "%s\n", status[f->user->status]);
  396. thdr.count = strlen(thdr.data);
  397. return 0;
  398. case Qexpire:
  399. if(off != 0){
  400. thdr.count = 0;
  401. return 0;
  402. }
  403. if(!f->user->expire)
  404. strcpy(data, "never\n");
  405. else
  406. sprint(data, "%lud\n", f->user->expire);
  407. if(n > strlen(data))
  408. n = strlen(data);
  409. thdr.count = n;
  410. return 0;
  411. case Qlog:
  412. if(off != 0){
  413. thdr.count = 0;
  414. return 0;
  415. }
  416. sprint(data, "%lud\n", f->user->bad);
  417. if(n > strlen(data))
  418. n = strlen(data);
  419. thdr.count = n;
  420. return 0;
  421. case Qwarnings:
  422. if(off != 0){
  423. thdr.count = 0;
  424. return 0;
  425. }
  426. sprint(data, "%ud\n", f->user->warnings);
  427. if(n > strlen(data))
  428. n = strlen(data);
  429. thdr.count = n;
  430. return 0;
  431. default:
  432. return "permission denied: unknown qid";
  433. }
  434. }
  435. char *
  436. Write(Fid *f)
  437. {
  438. char *data, *p;
  439. ulong n, expire;
  440. int i;
  441. if(!f->busy)
  442. return "permission denied";
  443. n = rhdr.count;
  444. data = rhdr.data;
  445. switch(f->qtype){
  446. case Qkey:
  447. if(n != DESKEYLEN)
  448. return "garbled write data";
  449. memmove(f->user->key, data, DESKEYLEN);
  450. thdr.count = DESKEYLEN;
  451. break;
  452. case Qsecret:
  453. if(n >= SECRETLEN)
  454. return "garbled write data";
  455. memmove(f->user->secret, data, n);
  456. f->user->secret[n] = 0;
  457. thdr.count = n;
  458. break;
  459. case Qstatus:
  460. data[n] = '\0';
  461. if(p = strchr(data, '\n'))
  462. *p = '\0';
  463. for(i = 0; i < Smax; i++)
  464. if(strcmp(data, status[i]) == 0){
  465. f->user->status = i;
  466. break;
  467. }
  468. if(i == Smax)
  469. return "unknown status";
  470. f->user->bad = 0;
  471. thdr.count = n;
  472. break;
  473. case Qexpire:
  474. data[n] = '\0';
  475. if(p = strchr(data, '\n'))
  476. *p = '\0';
  477. else
  478. p = &data[n];
  479. if(strcmp(data, "never") == 0)
  480. expire = 0;
  481. else{
  482. expire = strtoul(data, &data, 10);
  483. if(data != p)
  484. return "bad expiration date";
  485. }
  486. f->user->expire = expire;
  487. f->user->warnings = 0;
  488. thdr.count = n;
  489. break;
  490. case Qlog:
  491. data[n] = '\0';
  492. if(strcmp(data, "good") == 0)
  493. f->user->bad = 0;
  494. else
  495. f->user->bad++;
  496. if(f->user->bad && ((f->user->bad)%MAXBAD) == 0)
  497. f->user->purgatory = time(0) + f->user->bad;
  498. return 0;
  499. case Qwarnings:
  500. data[n] = '\0';
  501. f->user->warnings = strtoul(data, 0, 10);
  502. thdr.count = n;
  503. break;
  504. case Qroot:
  505. case Quser:
  506. default:
  507. return "permission denied";
  508. }
  509. writeusers();
  510. return 0;
  511. }
  512. char *
  513. Remove(Fid *f)
  514. {
  515. if(!f->busy)
  516. return "permission denied";
  517. if(f->qtype == Qwarnings)
  518. f->user->warnings = 0;
  519. else if(f->qtype == Quser)
  520. removeuser(f->user);
  521. else
  522. return "permission denied";
  523. Clunk(f);
  524. writeusers();
  525. return 0;
  526. }
  527. char *
  528. Stat(Fid *f)
  529. {
  530. static uchar statbuf[1024];
  531. if(!f->busy)
  532. return "stat on unattached fid";
  533. thdr.nstat = dostat(f->user, f->qtype, statbuf, sizeof statbuf);
  534. if(thdr.nstat <= BIT16SZ)
  535. return "stat buffer too small";
  536. thdr.stat = statbuf;
  537. return 0;
  538. }
  539. char *
  540. Wstat(Fid *f)
  541. {
  542. Dir d;
  543. int n;
  544. char buf[1024];
  545. if(!f->busy || f->qtype != Quser)
  546. return "permission denied";
  547. if(rhdr.nstat > sizeof buf)
  548. return "wstat buffer too big";
  549. if(convM2D(rhdr.stat, rhdr.nstat, &d, buf) == 0)
  550. return "bad stat buffer";
  551. n = strlen(d.name);
  552. if(n == 0 || n >= Namelen)
  553. return "bad user name";
  554. if(finduser(d.name))
  555. return "user already exists";
  556. if(!removeuser(f->user))
  557. return "user previously removed";
  558. free(f->user->name);
  559. f->user->name = strdup(d.name);
  560. if(f->user->name == nil)
  561. error("wstat: malloc failed: %r");
  562. insertuser(f->user);
  563. writeusers();
  564. return 0;
  565. }
  566. Qid
  567. mkqid(User *u, ulong qtype)
  568. {
  569. Qid q;
  570. q.vers = 0;
  571. q.path = qtype;
  572. if(u)
  573. q.path |= u->uniq * 0x100;
  574. if(qtype == Quser || qtype == Qroot)
  575. q.type = QTDIR;
  576. else
  577. q.type = QTFILE;
  578. return q;
  579. }
  580. int
  581. dostat(User *user, ulong qtype, void *p, int n)
  582. {
  583. Dir d;
  584. if(qtype == Quser)
  585. d.name = user->name;
  586. else
  587. d.name = qinfo[qtype];
  588. d.uid = d.gid = d.muid = "auth";
  589. d.qid = mkqid(user, qtype);
  590. if(d.qid.type & QTDIR)
  591. d.mode = 0777|DMDIR;
  592. else
  593. d.mode = 0666;
  594. d.atime = d.mtime = time(0);
  595. d.length = 0;
  596. return convD2M(&d, p, n);
  597. }
  598. int
  599. passline(Biobuf *b, void *vbuf)
  600. {
  601. char *buf = vbuf;
  602. if(Bread(b, buf, KEYDBLEN) != KEYDBLEN)
  603. return 0;
  604. decrypt(authkey, buf, KEYDBLEN);
  605. buf[Namelen-1] = '\0';
  606. return 1;
  607. }
  608. void
  609. randombytes(uchar *p, int len)
  610. {
  611. int i, fd;
  612. fd = open("/dev/random", OREAD);
  613. if(fd < 0){
  614. fprint(2, "can't open /dev/random, using rand()\n");
  615. srand(time(0));
  616. for(i = 0; i < len; i++)
  617. p[i] = rand();
  618. return;
  619. }
  620. read(fd, p, len);
  621. close(fd);
  622. }
  623. void
  624. oldCBCencrypt(char *key7, uchar *p, int len)
  625. {
  626. uchar ivec[8];
  627. uchar key[8];
  628. DESstate s;
  629. memset(ivec, 0, 8);
  630. des56to64((uchar*)key7, key);
  631. setupDESstate(&s, key, ivec);
  632. desCBCencrypt((uchar*)p, len, &s);
  633. }
  634. void
  635. oldCBCdecrypt(char *key7, uchar *p, int len)
  636. {
  637. uchar ivec[8];
  638. uchar key[8];
  639. DESstate s;
  640. memset(ivec, 0, 8);
  641. des56to64((uchar*)key7, key);
  642. setupDESstate(&s, key, ivec);
  643. desCBCdecrypt((uchar*)p, len, &s);
  644. }
  645. void
  646. writeusers(void)
  647. {
  648. int fd, i, nu;
  649. User *u;
  650. uchar *p, *buf;
  651. ulong expire;
  652. /* count users */
  653. nu = 0;
  654. for(i = 0; i < Nuser; i++)
  655. for(u = users[i]; u; u = u->link)
  656. nu++;
  657. /* pack into buffer */
  658. buf = malloc(KEYDBOFF + nu*KEYDBLEN);
  659. if(buf == 0){
  660. fprint(2, "keyfs: can't write keys file, out of memory\n");
  661. return;
  662. }
  663. p = buf;
  664. randombytes(p, KEYDBOFF);
  665. p += KEYDBOFF;
  666. for(i = 0; i < Nuser; i++)
  667. for(u = users[i]; u; u = u->link){
  668. strncpy((char*)p, u->name, Namelen);
  669. p += Namelen;
  670. memmove(p, u->key, DESKEYLEN);
  671. p += DESKEYLEN;
  672. *p++ = u->status;
  673. *p++ = u->warnings;
  674. expire = u->expire;
  675. *p++ = expire;
  676. *p++ = expire >> 8;
  677. *p++ = expire >> 16;
  678. *p++ = expire >> 24;
  679. memmove(p, u->secret, SECRETLEN);
  680. p += SECRETLEN;
  681. }
  682. /* encrypt */
  683. oldCBCencrypt(authkey, buf, p - buf);
  684. /* write file */
  685. fd = create(userkeys, OWRITE, 0660);
  686. if(fd < 0){
  687. free(buf);
  688. fprint(2, "keyfs: can't write keys file\n");
  689. return;
  690. }
  691. if(write(fd, buf, p - buf) != (p - buf))
  692. fprint(2, "keyfs: can't write keys file\n");
  693. free(buf);
  694. close(fd);
  695. }
  696. int
  697. readusers(void)
  698. {
  699. int fd, i, n, nu;
  700. uchar *p, *buf, *ep;
  701. User *u;
  702. Dir *d;
  703. if(usepass) {
  704. if(*authkey == 0)
  705. getpass(authkey, nil, 0, 0);
  706. } else {
  707. if(!getauthkey(authkey))
  708. print("keyfs: warning: can't read /dev/key\n");
  709. }
  710. /* read file into an array */
  711. fd = open(userkeys, OREAD);
  712. if(fd < 0)
  713. return 0;
  714. d = dirfstat(fd);
  715. if(d == nil){
  716. close(fd);
  717. return 0;
  718. }
  719. buf = malloc(d->length);
  720. if(buf == 0){
  721. close(fd);
  722. free(d);
  723. return 0;
  724. }
  725. n = readn(fd, buf, d->length);
  726. close(fd);
  727. free(d);
  728. if(n != d->length){
  729. free(buf);
  730. return 0;
  731. }
  732. /* decrypt */
  733. n -= n % KEYDBLEN;
  734. oldCBCdecrypt(authkey, buf, n);
  735. /* unpack */
  736. nu = 0;
  737. for(i = KEYDBOFF; i < n; i += KEYDBLEN){
  738. ep = buf + i;
  739. u = finduser((char*)ep);
  740. if(u == 0)
  741. u = installuser((char*)ep);
  742. memmove(u->key, ep + Namelen, DESKEYLEN);
  743. p = ep + Namelen + DESKEYLEN;
  744. u->status = *p++;
  745. u->warnings = *p++;
  746. if(u->status >= Smax)
  747. fprint(2, "keyfs: warning: bad status in key file\n");
  748. u->expire = p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24);
  749. p += 4;
  750. memmove(u->secret, p, SECRETLEN);
  751. u->secret[SECRETLEN-1] = 0;
  752. nu++;
  753. }
  754. free(buf);
  755. print("%d keys read\n", nu);
  756. return 1;
  757. }
  758. User *
  759. installuser(char *name)
  760. {
  761. User *u;
  762. int h;
  763. h = hash(name);
  764. u = emalloc(sizeof *u);
  765. u->name = strdup(name);
  766. if(u->name == nil)
  767. error("malloc failed: %r");
  768. u->removed = 0;
  769. u->ref = 0;
  770. u->purgatory = 0;
  771. u->expire = 0;
  772. u->status = Sok;
  773. u->bad = 0;
  774. u->warnings = 0;
  775. u->uniq = uniq++;
  776. u->link = users[h];
  777. users[h] = u;
  778. return u;
  779. }
  780. User *
  781. finduser(char *name)
  782. {
  783. User *u;
  784. for(u = users[hash(name)]; u; u = u->link)
  785. if(strcmp(name, u->name) == 0)
  786. return u;
  787. return 0;
  788. }
  789. int
  790. removeuser(User *user)
  791. {
  792. User *u, **last;
  793. char *name;
  794. user->removed = 1;
  795. name = user->name;
  796. last = &users[hash(name)];
  797. for(u = *last; u; u = *last){
  798. if(strcmp(name, u->name) == 0){
  799. *last = u->link;
  800. return 1;
  801. }
  802. last = &u->link;
  803. }
  804. return 0;
  805. }
  806. void
  807. insertuser(User *user)
  808. {
  809. int h;
  810. user->removed = 0;
  811. h = hash(user->name);
  812. user->link = users[h];
  813. users[h] = user;
  814. }
  815. ulong
  816. hash(char *s)
  817. {
  818. ulong h;
  819. h = 0;
  820. while(*s)
  821. h = (h << 1) ^ *s++;
  822. return h % Nuser;
  823. }
  824. Fid *
  825. findfid(int fid)
  826. {
  827. Fid *f, *ff;
  828. ff = 0;
  829. for(f = fids; f; f = f->next)
  830. if(f->fid == fid)
  831. return f;
  832. else if(!ff && !f->busy)
  833. ff = f;
  834. if(ff){
  835. ff->fid = fid;
  836. return ff;
  837. }
  838. f = emalloc(sizeof *f);
  839. f->fid = fid;
  840. f->busy = 0;
  841. f->user = 0;
  842. f->next = fids;
  843. fids = f;
  844. return f;
  845. }
  846. void
  847. io(int in, int out)
  848. {
  849. char *err;
  850. int n;
  851. long now, lastwarning;
  852. /* after restart, let the system settle for 5 mins before warning */
  853. lastwarning = time(0) - 24*60*60 + 5*60;
  854. for(;;){
  855. n = read9pmsg(in, mdata, messagesize);
  856. if(n == 0)
  857. continue;
  858. if(n < 0)
  859. error("mount read %d", n);
  860. if(convM2S(mdata, n, &rhdr) == 0)
  861. continue;
  862. if(newkeys())
  863. readusers();
  864. thdr.data = (char*)mdata + IOHDRSZ;
  865. thdr.fid = rhdr.fid;
  866. if(!fcalls[rhdr.type])
  867. err = "fcall request";
  868. else
  869. err = (*fcalls[rhdr.type])(findfid(rhdr.fid));
  870. thdr.tag = rhdr.tag;
  871. thdr.type = rhdr.type+1;
  872. if(err){
  873. thdr.type = Rerror;
  874. thdr.ename = err;
  875. }
  876. n = convS2M(&thdr, mdata, messagesize);
  877. if(write(out, mdata, n) != n)
  878. error("mount write");
  879. now = time(0);
  880. if(warnarg && (now - lastwarning > 24*60*60)){
  881. syslog(0, "auth", "keyfs starting warnings: %lux %lux", now, lastwarning);
  882. warning();
  883. lastwarning = now;
  884. }
  885. }
  886. }
  887. int
  888. newkeys(void)
  889. {
  890. Dir *d;
  891. static long ftime;
  892. d = dirstat(userkeys);
  893. if(d == nil)
  894. return 0;
  895. if(d->mtime > ftime){
  896. ftime = d->mtime;
  897. free(d);
  898. return 1;
  899. }
  900. free(d);
  901. return 0;
  902. }
  903. void *
  904. emalloc(ulong n)
  905. {
  906. void *p;
  907. if(p = malloc(n))
  908. return p;
  909. error("out of memory");
  910. return 0; /* not reached */
  911. }
  912. void
  913. warning(void)
  914. {
  915. int i;
  916. char buf[64];
  917. snprint(buf, sizeof buf, "-%s", warnarg);
  918. switch(rfork(RFPROC|RFNAMEG|RFNOTEG|RFNOWAIT|RFENVG|RFFDG)){
  919. case 0:
  920. i = open("/sys/log/auth", OWRITE);
  921. if(i >= 0){
  922. dup(i, 2);
  923. seek(2, 0, 2);
  924. close(i);
  925. }
  926. execl("/bin/auth/warning", "warning", warnarg, 0);
  927. error("can't exec warning");
  928. }
  929. }