fs.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. #include "dat.h"
  2. int askforkeys = 1;
  3. char *authaddr;
  4. int debug;
  5. int doprivate = 1;
  6. int gflag;
  7. char *owner;
  8. int kflag;
  9. char *mtpt = "/mnt";
  10. Keyring *ring;
  11. char *service;
  12. int sflag;
  13. int uflag;
  14. extern Srv fs;
  15. static void notifyf(void*, char*);
  16. static void private(void);
  17. char Easproto[] = "auth server protocol botch";
  18. char Ebadarg[] = "invalid argument";
  19. char Ebadkey[] = "bad key";
  20. char Enegotiation[] = "negotiation failed, no common protocols or keys";
  21. char Etoolarge[] = "rpc too large";
  22. Proto*
  23. prototab[] =
  24. {
  25. &apop,
  26. &chap,
  27. &cram,
  28. &mschap,
  29. &p9any,
  30. &p9cr,
  31. &p9sk1,
  32. &p9sk2,
  33. &pass,
  34. /* &srs, */
  35. &rsa,
  36. &vnc,
  37. &wep,
  38. nil,
  39. };
  40. void
  41. usage(void)
  42. {
  43. fprint(2, "usage: %s [-DdkSun] [-s service] [-a authaddr] [-m mtpt]\n", argv0);
  44. fprint(2, "or %s -g 'params'\n", argv0);
  45. exits("usage");
  46. }
  47. void
  48. main(int argc, char **argv)
  49. {
  50. int i, trysecstore;
  51. char err[ERRMAX], *s;
  52. Dir d;
  53. Proto *p;
  54. char *secstorepw;
  55. trysecstore = 1;
  56. secstorepw = nil;
  57. ARGBEGIN{
  58. case 'D':
  59. chatty9p++;
  60. break;
  61. case 'S': /* server: read nvram, no prompting for keys */
  62. askforkeys = 0;
  63. trysecstore = 0;
  64. sflag = 1;
  65. break;
  66. case 'a':
  67. authaddr = EARGF(usage());
  68. break;
  69. case 'd':
  70. debug = 1;
  71. doprivate = 0;
  72. break;
  73. case 'g': /* get: prompt for key for name and domain */
  74. gflag = 1;
  75. break;
  76. case 'k': /* reinitialize nvram */
  77. kflag = 1;
  78. break;
  79. case 'm': /* set default mount point */
  80. mtpt = EARGF(usage());
  81. break;
  82. case 'n':
  83. trysecstore = 0;
  84. break;
  85. case 'p':
  86. doprivate = 0;
  87. break;
  88. case 's': /* set service name */
  89. service = EARGF(usage());
  90. break;
  91. case 'u': /* user: set hostowner */
  92. uflag = 1;
  93. break;
  94. default:
  95. usage();
  96. }ARGEND
  97. if(argc != 0 && !gflag)
  98. usage();
  99. if(doprivate)
  100. private();
  101. initcap();
  102. quotefmtinstall();
  103. fmtinstall('A', _attrfmt);
  104. fmtinstall('N', attrnamefmt);
  105. fmtinstall('H', encodefmt);
  106. ring = emalloc(sizeof(*ring));
  107. notify(notifyf);
  108. if(gflag){
  109. if(argc != 1)
  110. usage();
  111. askuser(argv[0]);
  112. exits(nil);
  113. }
  114. for(i=0; prototab[i]; i++){
  115. p = prototab[i];
  116. if(p->name == nil)
  117. sysfatal("protocol %d has no name", i);
  118. if(p->init == nil)
  119. sysfatal("protocol %s has no init", p->name);
  120. if(p->write == nil)
  121. sysfatal("protocol %s has no write", p->name);
  122. if(p->read == nil)
  123. sysfatal("protocol %s has no read", p->name);
  124. if(p->close == nil)
  125. sysfatal("protocol %s has no close", p->name);
  126. if(p->keyprompt == nil)
  127. p->keyprompt = "";
  128. }
  129. if(sflag){
  130. s = getnvramkey(kflag ? NVwrite : NVwriteonerr, &secstorepw);
  131. if(s == nil)
  132. fprint(2, "factotum warning: cannot read nvram: %r\n");
  133. else if(ctlwrite(s, 0) < 0)
  134. fprint(2, "factotum warning: cannot add nvram key: %r\n");
  135. if(secstorepw != nil)
  136. trysecstore = 1;
  137. memset(s, 0, strlen(s));
  138. free(s);
  139. } else if(uflag)
  140. promptforhostowner();
  141. owner = getuser();
  142. if(trysecstore){
  143. if(havesecstore() == 1){
  144. while(secstorefetch(secstorepw) < 0){
  145. rerrstr(err, sizeof err);
  146. if(strcmp(err, "cancel") == 0)
  147. break;
  148. fprint(2, "factotum: secstorefetch: %r\n");
  149. fprint(2, "Enter an empty password to quit.\n");
  150. free(secstorepw);
  151. secstorepw = nil; /* just try nvram pw once */
  152. }
  153. }else{
  154. /*
  155. rerrstr(err, sizeof err);
  156. if(*err)
  157. fprint(2, "factotum: havesecstore: %r\n");
  158. */
  159. }
  160. }
  161. postmountsrv(&fs, service, mtpt, MBEFORE);
  162. if(service){
  163. nulldir(&d);
  164. d.mode = 0666;
  165. s = emalloc(10+strlen(service));
  166. strcpy(s, "/srv/");
  167. strcat(s, service);
  168. if(dirwstat(s, &d) < 0)
  169. fprint(2, "factotum warning: cannot chmod 666 %s: %r\n", s);
  170. free(s);
  171. }
  172. exits(nil);
  173. }
  174. char *pmsg = "Warning! %s can't protect itself from debugging: %r\n";
  175. char *smsg = "Warning! %s can't turn off swapping: %r\n";
  176. /* don't allow other processes to debug us and steal keys */
  177. static void
  178. private(void)
  179. {
  180. int fd;
  181. char buf[64];
  182. snprint(buf, sizeof(buf), "#p/%d/ctl", getpid());
  183. fd = open(buf, OWRITE);
  184. if(fd < 0){
  185. fprint(2, pmsg, argv0);
  186. return;
  187. }
  188. if(fprint(fd, "private") < 0)
  189. fprint(2, pmsg, argv0);
  190. if(fprint(fd, "noswap") < 0)
  191. fprint(2, smsg, argv0);
  192. close(fd);
  193. }
  194. static void
  195. notifyf(void*, char *s)
  196. {
  197. if(strncmp(s, "interrupt", 9) == 0)
  198. noted(NCONT);
  199. noted(NDFLT);
  200. }
  201. enum
  202. {
  203. Qroot,
  204. Qfactotum,
  205. Qrpc,
  206. Qkeylist,
  207. Qprotolist,
  208. Qconfirm,
  209. Qlog,
  210. Qctl,
  211. Qneedkey,
  212. };
  213. Qid
  214. mkqid(int type, int path)
  215. {
  216. Qid q;
  217. q.type = type;
  218. q.path = path;
  219. q.vers = 0;
  220. return q;
  221. }
  222. static void
  223. fsattach(Req *r)
  224. {
  225. r->fid->qid = mkqid(QTDIR, Qroot);
  226. r->ofcall.qid = r->fid->qid;
  227. respond(r, nil);
  228. }
  229. static struct {
  230. char *name;
  231. int qidpath;
  232. ulong perm;
  233. } dirtab[] = {
  234. "confirm", Qconfirm, 0600|DMEXCL, /* we know this is slot #0 below */
  235. "needkey", Qneedkey, 0600|DMEXCL, /* we know this is slot #1 below */
  236. "ctl", Qctl, 0644,
  237. "rpc", Qrpc, 0666,
  238. "proto", Qprotolist, 0444,
  239. "log", Qlog, 0400|DMEXCL,
  240. };
  241. static int inuse[nelem(dirtab)];
  242. int *confirminuse = &inuse[0];
  243. int *needkeyinuse = &inuse[1];
  244. static void
  245. fillstat(Dir *dir, char *name, int type, int path, ulong perm)
  246. {
  247. dir->name = estrdup(name);
  248. dir->uid = estrdup(owner);
  249. dir->gid = estrdup(owner);
  250. dir->mode = perm;
  251. dir->length = 0;
  252. dir->qid = mkqid(type, path);
  253. dir->atime = time(0);
  254. dir->mtime = time(0);
  255. dir->muid = estrdup("");
  256. }
  257. static int
  258. rootdirgen(int n, Dir *dir, void*)
  259. {
  260. if(n > 0)
  261. return -1;
  262. fillstat(dir, "factotum", QTDIR, Qfactotum, DMDIR|0555);
  263. return 0;
  264. }
  265. static int
  266. fsdirgen(int n, Dir *dir, void*)
  267. {
  268. if(n >= nelem(dirtab))
  269. return -1;
  270. fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
  271. return 0;
  272. }
  273. static char*
  274. fswalk1(Fid *fid, char *name, Qid *qid)
  275. {
  276. int i;
  277. switch((ulong)fid->qid.path){
  278. default:
  279. return "cannot happen";
  280. case Qroot:
  281. if(strcmp(name, "factotum") == 0){
  282. *qid = mkqid(QTDIR, Qfactotum);
  283. fid->qid = *qid;
  284. return nil;
  285. }
  286. if(strcmp(name, "..") == 0){
  287. *qid = fid->qid;
  288. return nil;
  289. }
  290. return "not found";
  291. case Qfactotum:
  292. for(i=0; i<nelem(dirtab); i++)
  293. if(strcmp(name, dirtab[i].name) == 0){
  294. *qid = mkqid(0, dirtab[i].qidpath);
  295. fid->qid = *qid;
  296. return nil;
  297. }
  298. if(strcmp(name, "..") == 0){
  299. *qid = mkqid(QTDIR, Qroot);
  300. fid->qid = *qid;
  301. return nil;
  302. }
  303. return "not found";
  304. }
  305. }
  306. static void
  307. fsstat(Req *r)
  308. {
  309. int i;
  310. ulong path;
  311. path = r->fid->qid.path;
  312. if(path == Qroot){
  313. fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
  314. respond(r, nil);
  315. return;
  316. }
  317. if(path == Qfactotum){
  318. fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
  319. respond(r, nil);
  320. return;
  321. }
  322. for(i=0; i<nelem(dirtab); i++)
  323. if(dirtab[i].qidpath == path){
  324. fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
  325. respond(r, nil);
  326. return;
  327. }
  328. respond(r, "file not found");
  329. }
  330. static void
  331. fsopen(Req *r)
  332. {
  333. int i, *p, perm;
  334. static int need[4] = {4, 2, 6, 1};
  335. int n;
  336. Fsstate *fss;
  337. p = nil;
  338. for(i=0; i<nelem(dirtab); i++)
  339. if(dirtab[i].qidpath == r->fid->qid.path)
  340. break;
  341. if(i < nelem(dirtab)){
  342. if(dirtab[i].perm & DMEXCL)
  343. p = &inuse[i];
  344. if(strcmp(r->fid->uid, owner) == 0)
  345. perm = dirtab[i].perm>>6;
  346. else
  347. perm = dirtab[i].perm;
  348. }else
  349. perm = 5;
  350. n = need[r->ifcall.mode&3];
  351. if((r->ifcall.mode&~(3|OTRUNC)) || ((perm&n) != n)){
  352. respond(r, "permission denied");
  353. return;
  354. }
  355. if(p){
  356. if(*p){
  357. respond(r, "file in use");
  358. return;
  359. }
  360. (*p)++;
  361. }
  362. r->fid->aux = fss = emalloc(sizeof(Fsstate));
  363. fss->phase = Notstarted;
  364. fss->sysuser = r->fid->uid;
  365. fss->attr = nil;
  366. strcpy(fss->err, "factotum/fs.c no error");
  367. respond(r, nil);
  368. }
  369. static void
  370. fsdestroyfid(Fid *fid)
  371. {
  372. int i;
  373. Fsstate *fss;
  374. if(fid->omode != -1){
  375. for(i=0; i<nelem(dirtab); i++)
  376. if(dirtab[i].qidpath == fid->qid.path)
  377. if(dirtab[i].perm&DMEXCL)
  378. inuse[i] = 0;
  379. }
  380. fss = fid->aux;
  381. if(fss == nil)
  382. return;
  383. if(fss->ps)
  384. (*fss->proto->close)(fss);
  385. _freeattr(fss->attr);
  386. free(fss);
  387. }
  388. static int
  389. readlist(int off, int (*gen)(int, char*, uint, Fsstate*), Req *r, Fsstate *fss)
  390. {
  391. char *a, *ea;
  392. int n;
  393. a = r->ofcall.data;
  394. ea = a+r->ifcall.count;
  395. for(;;){
  396. n = (*gen)(off, a, ea-a, fss);
  397. if(n == 0){
  398. r->ofcall.count = a - (char*)r->ofcall.data;
  399. return off;
  400. }
  401. a += n;
  402. off++;
  403. }
  404. return -1; /* not reached */
  405. }
  406. static int
  407. keylist(int i, char *a, uint n, Fsstate *fss)
  408. {
  409. char buf[512];
  410. Keyinfo ki;
  411. Key *k;
  412. k = nil;
  413. mkkeyinfo(&ki, fss, nil);
  414. ki.attr = nil;
  415. ki.skip = i;
  416. ki.usedisabled = 1;
  417. if(findkey(&k, &ki, "") != RpcOk)
  418. return 0;
  419. snprint(buf, sizeof buf, "key %A %N\n", k->attr, k->privattr);
  420. closekey(k);
  421. strcpy(buf+sizeof buf-2, "\n"); /* if line is really long, just truncate */
  422. if(strlen(buf) > n)
  423. return 0;
  424. n = strlen(buf);
  425. memmove(a, buf, n);
  426. return n;
  427. }
  428. static int
  429. protolist(int i, char *a, uint n, Fsstate *fss)
  430. {
  431. USED(fss);
  432. if(i >= nelem(prototab)-1)
  433. return 0;
  434. if(strlen(prototab[i]->name)+1 > n)
  435. return 0;
  436. n = strlen(prototab[i]->name)+1;
  437. memmove(a, prototab[i]->name, n-1);
  438. a[n-1] = '\n';
  439. return n;
  440. }
  441. static void
  442. fsread(Req *r)
  443. {
  444. Fsstate *s;
  445. s = r->fid->aux;
  446. switch((ulong)r->fid->qid.path){
  447. default:
  448. respond(r, "bug in fsread");
  449. break;
  450. case Qroot:
  451. dirread9p(r, rootdirgen, nil);
  452. respond(r, nil);
  453. break;
  454. case Qfactotum:
  455. dirread9p(r, fsdirgen, nil);
  456. respond(r, nil);
  457. break;
  458. case Qrpc:
  459. rpcread(r);
  460. break;
  461. case Qneedkey:
  462. needkeyread(r);
  463. break;
  464. case Qconfirm:
  465. confirmread(r);
  466. break;
  467. case Qlog:
  468. logread(r);
  469. break;
  470. case Qctl:
  471. s->listoff = readlist(s->listoff, keylist, r, s);
  472. respond(r, nil);
  473. break;
  474. case Qprotolist:
  475. s->listoff = readlist(s->listoff, protolist, r, s);
  476. respond(r, nil);
  477. break;
  478. }
  479. }
  480. static void
  481. fswrite(Req *r)
  482. {
  483. int ret;
  484. char err[ERRMAX], *s;
  485. switch((ulong)r->fid->qid.path){
  486. default:
  487. respond(r, "bug in fswrite");
  488. break;
  489. case Qrpc:
  490. rpcwrite(r);
  491. break;
  492. case Qneedkey:
  493. case Qconfirm:
  494. case Qctl:
  495. s = emalloc(r->ifcall.count+1);
  496. memmove(s, r->ifcall.data, r->ifcall.count);
  497. s[r->ifcall.count] = '\0';
  498. switch((ulong)r->fid->qid.path){
  499. default:
  500. abort();
  501. case Qneedkey:
  502. ret = needkeywrite(s);
  503. break;
  504. case Qconfirm:
  505. ret = confirmwrite(s);
  506. break;
  507. case Qctl:
  508. ret = ctlwrite(s, 0);
  509. break;
  510. }
  511. free(s);
  512. if(ret < 0){
  513. rerrstr(err, sizeof err);
  514. respond(r, err);
  515. }else{
  516. r->ofcall.count = r->ifcall.count;
  517. respond(r, nil);
  518. }
  519. break;
  520. }
  521. }
  522. static void
  523. fsflush(Req *r)
  524. {
  525. confirmflush(r->oldreq);
  526. needkeyflush(r->oldreq);
  527. logflush(r->oldreq);
  528. respond(r, nil);
  529. }
  530. Srv fs = {
  531. .attach= fsattach,
  532. .walk1= fswalk1,
  533. .open= fsopen,
  534. .read= fsread,
  535. .write= fswrite,
  536. .stat= fsstat,
  537. .flush= fsflush,
  538. .destroyfid= fsdestroyfid,
  539. };