fs.c 10 KB

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