keyfs.c 17 KB

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