keyfs.c 17 KB

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