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. &httpdigest,
  29. &mschap,
  30. &p9any,
  31. &p9cr,
  32. &p9sk1,
  33. &p9sk2,
  34. &pass,
  35. /* &srs, */
  36. &rsa,
  37. &vnc,
  38. &wep,
  39. nil,
  40. };
  41. void
  42. usage(void)
  43. {
  44. fprint(2, "usage: %s [-DdkSun] [-s service] [-a authaddr] [-m mtpt]\n", argv0);
  45. fprint(2, "or %s -g 'params'\n", argv0);
  46. exits("usage");
  47. }
  48. void
  49. main(int argc, char **argv)
  50. {
  51. int i, trysecstore;
  52. char err[ERRMAX], *s;
  53. Dir d;
  54. Proto *p;
  55. char *secstorepw;
  56. trysecstore = 1;
  57. secstorepw = nil;
  58. ARGBEGIN{
  59. case 'D':
  60. chatty9p++;
  61. break;
  62. case 'S': /* server: read nvram, no prompting for keys */
  63. askforkeys = 0;
  64. trysecstore = 0;
  65. sflag = 1;
  66. break;
  67. case 'a':
  68. authaddr = EARGF(usage());
  69. break;
  70. case 'd':
  71. debug = 1;
  72. doprivate = 0;
  73. break;
  74. case 'g': /* get: prompt for key for name and domain */
  75. gflag = 1;
  76. break;
  77. case 'k': /* reinitialize nvram */
  78. kflag = 1;
  79. break;
  80. case 'm': /* set default mount point */
  81. mtpt = EARGF(usage());
  82. break;
  83. case 'n':
  84. trysecstore = 0;
  85. break;
  86. case 'p':
  87. doprivate = 0;
  88. break;
  89. case 's': /* set service name */
  90. service = EARGF(usage());
  91. break;
  92. case 'u': /* user: set hostowner */
  93. uflag = 1;
  94. break;
  95. default:
  96. usage();
  97. }ARGEND
  98. if(argc != 0 && !gflag)
  99. usage();
  100. if(doprivate)
  101. private();
  102. initcap();
  103. quotefmtinstall();
  104. fmtinstall('A', _attrfmt);
  105. fmtinstall('N', attrnamefmt);
  106. fmtinstall('H', encodefmt);
  107. ring = emalloc(sizeof(*ring));
  108. notify(notifyf);
  109. if(gflag){
  110. if(argc != 1)
  111. usage();
  112. askuser(argv[0]);
  113. exits(nil);
  114. }
  115. for(i=0; prototab[i]; i++){
  116. p = prototab[i];
  117. if(p->name == nil)
  118. sysfatal("protocol %d has no name", i);
  119. if(p->init == nil)
  120. sysfatal("protocol %s has no init", p->name);
  121. if(p->write == nil)
  122. sysfatal("protocol %s has no write", p->name);
  123. if(p->read == nil)
  124. sysfatal("protocol %s has no read", p->name);
  125. if(p->close == nil)
  126. sysfatal("protocol %s has no close", p->name);
  127. if(p->keyprompt == nil)
  128. p->keyprompt = "";
  129. }
  130. if(sflag){
  131. s = getnvramkey(kflag ? NVwrite : NVwriteonerr, &secstorepw);
  132. if(s == nil)
  133. fprint(2, "factotum warning: cannot read nvram: %r\n");
  134. else if(ctlwrite(s, 0) < 0)
  135. fprint(2, "factotum warning: cannot add nvram key: %r\n");
  136. if(secstorepw != nil)
  137. trysecstore = 1;
  138. memset(s, 0, strlen(s));
  139. free(s);
  140. } else if(uflag)
  141. promptforhostowner();
  142. owner = getuser();
  143. if(trysecstore){
  144. if(havesecstore() == 1){
  145. while(secstorefetch(secstorepw) < 0){
  146. rerrstr(err, sizeof err);
  147. if(strcmp(err, "cancel") == 0)
  148. break;
  149. fprint(2, "factotum: secstorefetch: %r\n");
  150. fprint(2, "Enter an empty password to quit.\n");
  151. free(secstorepw);
  152. secstorepw = nil; /* just try nvram pw once */
  153. }
  154. }else{
  155. /*
  156. rerrstr(err, sizeof err);
  157. if(*err)
  158. fprint(2, "factotum: havesecstore: %r\n");
  159. */
  160. }
  161. }
  162. postmountsrv(&fs, service, mtpt, MBEFORE);
  163. if(service){
  164. nulldir(&d);
  165. d.mode = 0666;
  166. s = emalloc(10+strlen(service));
  167. strcpy(s, "/srv/");
  168. strcat(s, service);
  169. if(dirwstat(s, &d) < 0)
  170. fprint(2, "factotum warning: cannot chmod 666 %s: %r\n", s);
  171. free(s);
  172. }
  173. exits(nil);
  174. }
  175. char *pmsg = "Warning! %s can't protect itself from debugging: %r\n";
  176. char *smsg = "Warning! %s can't turn off swapping: %r\n";
  177. /* don't allow other processes to debug us and steal keys */
  178. static void
  179. private(void)
  180. {
  181. int fd;
  182. char buf[64];
  183. snprint(buf, sizeof(buf), "#p/%d/ctl", getpid());
  184. fd = open(buf, OWRITE);
  185. if(fd < 0){
  186. fprint(2, pmsg, argv0);
  187. return;
  188. }
  189. if(fprint(fd, "private") < 0)
  190. fprint(2, pmsg, argv0);
  191. if(fprint(fd, "noswap") < 0)
  192. fprint(2, smsg, argv0);
  193. close(fd);
  194. }
  195. static void
  196. notifyf(void*, char *s)
  197. {
  198. if(strncmp(s, "interrupt", 9) == 0)
  199. noted(NCONT);
  200. noted(NDFLT);
  201. }
  202. enum
  203. {
  204. Qroot,
  205. Qfactotum,
  206. Qrpc,
  207. Qkeylist,
  208. Qprotolist,
  209. Qconfirm,
  210. Qlog,
  211. Qctl,
  212. Qneedkey,
  213. };
  214. Qid
  215. mkqid(int type, int path)
  216. {
  217. Qid q;
  218. q.type = type;
  219. q.path = path;
  220. q.vers = 0;
  221. return q;
  222. }
  223. static void
  224. fsattach(Req *r)
  225. {
  226. r->fid->qid = mkqid(QTDIR, Qroot);
  227. r->ofcall.qid = r->fid->qid;
  228. respond(r, nil);
  229. }
  230. static struct {
  231. char *name;
  232. int qidpath;
  233. ulong perm;
  234. } dirtab[] = {
  235. "confirm", Qconfirm, 0600|DMEXCL, /* we know this is slot #0 below */
  236. "needkey", Qneedkey, 0600|DMEXCL, /* we know this is slot #1 below */
  237. "ctl", Qctl, 0644,
  238. "rpc", Qrpc, 0666,
  239. "proto", Qprotolist, 0444,
  240. "log", Qlog, 0400|DMEXCL,
  241. };
  242. static int inuse[nelem(dirtab)];
  243. int *confirminuse = &inuse[0];
  244. int *needkeyinuse = &inuse[1];
  245. static void
  246. fillstat(Dir *dir, char *name, int type, int path, ulong perm)
  247. {
  248. dir->name = estrdup(name);
  249. dir->uid = estrdup(owner);
  250. dir->gid = estrdup(owner);
  251. dir->mode = perm;
  252. dir->length = 0;
  253. dir->qid = mkqid(type, path);
  254. dir->atime = time(0);
  255. dir->mtime = time(0);
  256. dir->muid = estrdup("");
  257. }
  258. static int
  259. rootdirgen(int n, Dir *dir, void*)
  260. {
  261. if(n > 0)
  262. return -1;
  263. fillstat(dir, "factotum", QTDIR, Qfactotum, DMDIR|0555);
  264. return 0;
  265. }
  266. static int
  267. fsdirgen(int n, Dir *dir, void*)
  268. {
  269. if(n >= nelem(dirtab))
  270. return -1;
  271. fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
  272. return 0;
  273. }
  274. static char*
  275. fswalk1(Fid *fid, char *name, Qid *qid)
  276. {
  277. int i;
  278. switch((ulong)fid->qid.path){
  279. default:
  280. return "cannot happen";
  281. case Qroot:
  282. if(strcmp(name, "factotum") == 0){
  283. *qid = mkqid(QTDIR, Qfactotum);
  284. fid->qid = *qid;
  285. return nil;
  286. }
  287. if(strcmp(name, "..") == 0){
  288. *qid = fid->qid;
  289. return nil;
  290. }
  291. return "not found";
  292. case Qfactotum:
  293. for(i=0; i<nelem(dirtab); i++)
  294. if(strcmp(name, dirtab[i].name) == 0){
  295. *qid = mkqid(0, dirtab[i].qidpath);
  296. fid->qid = *qid;
  297. return nil;
  298. }
  299. if(strcmp(name, "..") == 0){
  300. *qid = mkqid(QTDIR, Qroot);
  301. fid->qid = *qid;
  302. return nil;
  303. }
  304. return "not found";
  305. }
  306. }
  307. static void
  308. fsstat(Req *r)
  309. {
  310. int i;
  311. ulong path;
  312. path = r->fid->qid.path;
  313. if(path == Qroot){
  314. fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
  315. respond(r, nil);
  316. return;
  317. }
  318. if(path == Qfactotum){
  319. fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
  320. respond(r, nil);
  321. return;
  322. }
  323. for(i=0; i<nelem(dirtab); i++)
  324. if(dirtab[i].qidpath == path){
  325. fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
  326. respond(r, nil);
  327. return;
  328. }
  329. respond(r, "file not found");
  330. }
  331. static void
  332. fsopen(Req *r)
  333. {
  334. int i, *p, perm;
  335. static int need[4] = {4, 2, 6, 1};
  336. int n;
  337. Fsstate *fss;
  338. p = nil;
  339. for(i=0; i<nelem(dirtab); i++)
  340. if(dirtab[i].qidpath == r->fid->qid.path)
  341. break;
  342. if(i < nelem(dirtab)){
  343. if(dirtab[i].perm & DMEXCL)
  344. p = &inuse[i];
  345. if(strcmp(r->fid->uid, owner) == 0)
  346. perm = dirtab[i].perm>>6;
  347. else
  348. perm = dirtab[i].perm;
  349. }else
  350. perm = 5;
  351. n = need[r->ifcall.mode&3];
  352. if((r->ifcall.mode&~(3|OTRUNC)) || ((perm&n) != n)){
  353. respond(r, "permission denied");
  354. return;
  355. }
  356. if(p){
  357. if(*p){
  358. respond(r, "file in use");
  359. return;
  360. }
  361. (*p)++;
  362. }
  363. r->fid->aux = fss = emalloc(sizeof(Fsstate));
  364. fss->phase = Notstarted;
  365. fss->sysuser = r->fid->uid;
  366. fss->attr = nil;
  367. strcpy(fss->err, "factotum/fs.c no error");
  368. respond(r, nil);
  369. }
  370. static void
  371. fsdestroyfid(Fid *fid)
  372. {
  373. int i;
  374. Fsstate *fss;
  375. if(fid->omode != -1){
  376. for(i=0; i<nelem(dirtab); i++)
  377. if(dirtab[i].qidpath == fid->qid.path)
  378. if(dirtab[i].perm&DMEXCL)
  379. inuse[i] = 0;
  380. }
  381. fss = fid->aux;
  382. if(fss == nil)
  383. return;
  384. if(fss->ps)
  385. (*fss->proto->close)(fss);
  386. _freeattr(fss->attr);
  387. free(fss);
  388. }
  389. static int
  390. readlist(int off, int (*gen)(int, char*, uint, Fsstate*), Req *r, Fsstate *fss)
  391. {
  392. char *a, *ea;
  393. int n;
  394. a = r->ofcall.data;
  395. ea = a+r->ifcall.count;
  396. for(;;){
  397. n = (*gen)(off, a, ea-a, fss);
  398. if(n == 0){
  399. r->ofcall.count = a - (char*)r->ofcall.data;
  400. return off;
  401. }
  402. a += n;
  403. off++;
  404. }
  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. };