keyfs.c 17 KB

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