proto.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "ratfs.h"
  10. /*
  11. * 9P protocol interface
  12. */
  13. enum {
  14. RELOAD = 0, /* commands written to ctl file */
  15. RDEBUG,
  16. RNODEBUG,
  17. RNONE,
  18. };
  19. static void rflush(Fcall*), rnop(Fcall*),
  20. rauth(Fcall*), rattach(Fcall*),
  21. rclone(Fcall*), rwalk(Fcall*),
  22. rclwalk(Fcall*), ropen(Fcall*),
  23. rcreate(Fcall*), rread(Fcall*),
  24. rwrite(Fcall*), rclunk(Fcall*),
  25. rremove(Fcall*), rstat(Fcall*),
  26. rwstat(Fcall*), rversion(Fcall*);
  27. static Fid* newfid(int);
  28. static void reply(Fcall*, char*);
  29. static void (*fcalls[])(Fcall*) = {
  30. [Tversion] rversion,
  31. [Tflush] rflush,
  32. [Tauth] rauth,
  33. [Tattach] rattach,
  34. [Twalk] rwalk,
  35. [Topen] ropen,
  36. [Tcreate] rcreate,
  37. [Tread] rread,
  38. [Twrite] rwrite,
  39. [Tclunk] rclunk,
  40. [Tremove] rremove,
  41. [Tstat] rstat,
  42. [Twstat] rwstat,
  43. };
  44. static Keyword cmds[] = {
  45. "reload", RELOAD,
  46. "debug", RDEBUG,
  47. "nodebug", RNODEBUG,
  48. 0, RNONE,
  49. };
  50. /*
  51. * Main protocol loop
  52. */
  53. void
  54. io(void)
  55. {
  56. Fcall rhdr;
  57. int n;
  58. for(;;){
  59. n = read9pmsg(srvfd, rbuf, sizeof rbuf-1);
  60. if(n <= 0)
  61. fatal("mount read");
  62. if(convM2S(rbuf, n, &rhdr) == 0){
  63. if(debugfd >= 0)
  64. fprint(2, "%s: malformed message\n", argv0);
  65. continue;
  66. }
  67. if(debugfd >= 0)
  68. fprint(debugfd, "<-%F\n", &rhdr);/**/
  69. if(!fcalls[rhdr.type])
  70. reply(&rhdr, "bad fcall type");
  71. else
  72. (*fcalls[rhdr.type])(&rhdr);
  73. }
  74. }
  75. /*
  76. * write a protocol reply to the client
  77. */
  78. static void
  79. reply(Fcall *r, char *error)
  80. {
  81. int n;
  82. if(error == nil)
  83. r->type++;
  84. else {
  85. r->type = Rerror;
  86. r->ename = error;
  87. }
  88. if(debugfd >= 0)
  89. fprint(debugfd, "->%F\n", r);/**/
  90. n = convS2M(r, rbuf, sizeof rbuf);
  91. if(n == 0)
  92. sysfatal("convS2M: %r");
  93. if(write(srvfd, rbuf, n) < 0)
  94. sysfatal("reply: %r");
  95. }
  96. /*
  97. * lookup a fid. if not found, create a new one.
  98. */
  99. static Fid*
  100. newfid(int fid)
  101. {
  102. Fid *f, *ff;
  103. static Fid *fids;
  104. ff = 0;
  105. for(f = fids; f; f = f->next){
  106. if(f->fid == fid){
  107. if(!f->busy)
  108. f->node = 0;
  109. return f;
  110. } else if(!ff && !f->busy)
  111. ff = f;
  112. }
  113. if(ff == 0){
  114. ff = mallocz(sizeof(*f), 1);
  115. ff->next = fids;
  116. fids = ff;
  117. }
  118. ff->node = 0;
  119. ff->fid = fid;
  120. return ff;
  121. }
  122. static void
  123. rversion(Fcall *f)
  124. {
  125. f->version = "9P2000";
  126. if(f->msize > MAXRPC)
  127. f->msize = MAXRPC;
  128. reply(f, 0);
  129. }
  130. static void
  131. rauth(Fcall *f)
  132. {
  133. reply(f, "ratfs: authentication not required");
  134. }
  135. static void
  136. rflush(Fcall *f)
  137. {
  138. reply(f, 0);
  139. }
  140. static void
  141. rattach(Fcall *f)
  142. {
  143. Fid *fidp;
  144. Dir *d;
  145. if((d=dirstat(conffile)) != nil && d->mtime > lastconftime)
  146. getconf();
  147. free(d);
  148. if((d=dirstat(ctlfile)) != nil && d->mtime > lastctltime)
  149. reload();
  150. free(d);
  151. cleantrusted();
  152. fidp = newfid(f->fid);
  153. fidp->busy = 1;
  154. fidp->node = root;
  155. fidp->name = root->d.name;
  156. fidp->uid = atom(f->uname);
  157. f->qid = root->d.qid;
  158. reply(f,0);
  159. }
  160. static void
  161. rclone(Fcall *f)
  162. {
  163. Fid *fidp, *nf;
  164. fidp = newfid(f->fid);
  165. if(fidp->node && fidp->node->d.type == Dummynode){
  166. reply(f, "can't clone an address");
  167. return;
  168. }
  169. nf = newfid(f->newfid);
  170. nf->busy = 1;
  171. nf->node = fidp->node;
  172. nf->uid = fidp->uid;
  173. nf->name = fidp->name;
  174. if(debugfd >= 0)
  175. printfid(nf);
  176. reply(f,0);
  177. }
  178. static void
  179. rwalk(Fcall *f)
  180. {
  181. int i, j;
  182. Fcall r;
  183. Fid *fidp, *nf;
  184. char *err;
  185. fidp = newfid(f->fid);
  186. if(fidp->node && fidp->node->d.type == Dummynode){
  187. reply(f, "can't walk an address node");
  188. return;
  189. }
  190. if(f->fid == f->newfid)
  191. nf = fidp;
  192. else{
  193. nf = newfid(f->newfid);
  194. nf->busy = 1;
  195. nf->node = fidp->node;
  196. nf->uid = fidp->uid;
  197. nf->name = fidp->name;
  198. if(debugfd >= 0)
  199. printfid(nf);
  200. }
  201. err = nil;
  202. for(i=0; i<f->nwname; i++){
  203. err = walk(f->wname[i], nf);
  204. if(err)
  205. break;
  206. r.wqid[i] = nf->node->d.qid;
  207. }
  208. if(i < f->nwname && f->fid != f->newfid){
  209. nf->busy = 0;
  210. nf->node = 0;
  211. nf->name = 0;
  212. nf->uid = 0;
  213. }
  214. if(i > 0 && i < f->nwname && f->fid == f->newfid){
  215. /*
  216. * try to put things back;
  217. * we never get this sort of call from the kernel
  218. */
  219. for(j=0; j<i; j++)
  220. walk("..", nf);
  221. }
  222. memmove(f->wqid, r.wqid, sizeof f->wqid);
  223. f->nwqid = i;
  224. if(err && i==0)
  225. reply(f, err);
  226. else
  227. reply(f, 0);
  228. }
  229. /*
  230. * We don't have to do full permission checking because most files
  231. * have restricted semantics:
  232. * The ctl file is only writable
  233. * All others, including directories, are only readable
  234. */
  235. static void
  236. ropen(Fcall *f)
  237. {
  238. Fid *fidp;
  239. int mode;
  240. fidp = newfid(f->fid);
  241. if(debugfd >= 0)
  242. printfid(fidp);
  243. mode = f->mode&(OREAD|OWRITE|ORDWR);
  244. if(fidp->node->d.type == Ctlfile) {
  245. if(mode != OWRITE) {
  246. reply(f, "permission denied");
  247. return;
  248. }
  249. } else
  250. if (mode != OREAD) {
  251. reply(f, "permission denied or operation not supported");
  252. return;
  253. }
  254. f->qid = fidp->node->d.qid;
  255. fidp->open = 1;
  256. reply(f, 0);
  257. }
  258. static int
  259. permitted(Fid *fp, Node *np, int mask)
  260. {
  261. int mode;
  262. mode = np->d.mode;
  263. return (fp->uid==np->d.uid && (mode&(mask<<6)))
  264. || (fp->uid==np->d.gid && (mode&(mask<<3)))
  265. || (mode&mask);
  266. }
  267. /*
  268. * creates are only allowed in the "trusted" subdirectory
  269. * we also assume that the groupid == the uid
  270. */
  271. static void
  272. rcreate(Fcall *f)
  273. {
  274. Fid *fidp;
  275. Node *np;
  276. fidp = newfid(f->fid);
  277. np = fidp->node;
  278. if((np->d.mode&DMDIR) == 0){
  279. reply(f, "not a directory");
  280. return;
  281. }
  282. if(!permitted(fidp, np, AWRITE)) {
  283. reply(f, "permission denied");
  284. return;
  285. }
  286. /* Ignore the supplied mode and force it to be non-writable */
  287. np = newnode(np, f->name, Trustedtemp, 0444, trustedqid++);
  288. if(trustedqid >= Qaddrfile) /* wrap QIDs */
  289. trustedqid = Qtrustedfile;
  290. cidrparse(&np->ip, f->name);
  291. f->qid = np->d.qid;
  292. np->d.uid = fidp->uid;
  293. np->d.gid = np->d.uid;
  294. np->d.muid = np->d.muid;
  295. fidp->node = np;
  296. fidp->open = 1;
  297. reply(f, 0);
  298. return;
  299. }
  300. /*
  301. * only directories can be read. everthing else returns EOF.
  302. */
  303. static void
  304. rread(Fcall *f)
  305. {
  306. int32_t cnt;
  307. Fid *fidp;
  308. cnt = f->count;
  309. f->count = 0;
  310. fidp = newfid(f->fid);
  311. f->data = (char*)rbuf+IOHDRSZ;
  312. if(fidp->open == 0) {
  313. reply(f, "file not open");
  314. return;
  315. }
  316. if ((fidp->node->d.mode&DMDIR) == 0){
  317. reply(f, 0); /*EOF*/
  318. return;
  319. }
  320. if(cnt > MAXRPC)
  321. cnt = MAXRPC;
  322. if(f->offset == 0)
  323. fidp->dirindex = 0;
  324. switch(fidp->node->d.type) {
  325. case Directory:
  326. case Addrdir:
  327. case Trusted:
  328. f->count = dread(fidp, cnt);
  329. break;
  330. case IPaddr:
  331. case Acctaddr:
  332. f->count = hread(fidp, cnt);
  333. break;
  334. default:
  335. reply(f, "can't read this type of file");
  336. return;
  337. }
  338. reply(f, 0);
  339. }
  340. /*
  341. * only the 'ctl' file in the top level directory is writable
  342. */
  343. static void
  344. rwrite(Fcall *f)
  345. {
  346. Fid *fidp;
  347. int n;
  348. char *err, *argv[10];
  349. fidp = newfid(f->fid);
  350. if(fidp->node->d.mode & DMDIR){
  351. reply(f, "directories are not writable");
  352. return;
  353. }
  354. if(fidp->open == 0) {
  355. reply(f, "file not open");
  356. return;
  357. }
  358. if (!permitted(fidp, fidp->node, AWRITE)) {
  359. reply(f, "permission denied");
  360. return;
  361. }
  362. f->data[f->count] = 0; /* the extra byte in rbuf leaves room */
  363. n = tokenize(f->data, argv, 10);
  364. err = 0;
  365. switch(findkey(argv[0], cmds)){
  366. case RELOAD:
  367. getconf();
  368. reload();
  369. break;
  370. case RDEBUG:
  371. if(n > 1){
  372. debugfd = create(argv[1], OWRITE, 0666);
  373. if(debugfd < 0)
  374. err = "create failed";
  375. } else
  376. debugfd = 2;
  377. break;
  378. case RNODEBUG:
  379. if(debugfd >= 0)
  380. close(debugfd);
  381. debugfd = -1;
  382. break;
  383. default:
  384. err = "unknown command";
  385. break;
  386. }
  387. reply(f, err);
  388. }
  389. static void
  390. rclunk(Fcall *f)
  391. {
  392. Fid *fidp;
  393. fidp = newfid(f->fid);
  394. fidp->open = 0;
  395. fidp->busy = 0;
  396. fidp->node = 0;
  397. fidp->name = 0;
  398. fidp->uid = 0;
  399. reply(f, 0);
  400. }
  401. /*
  402. * no files or directories are removable; this becomes clunk;
  403. */
  404. static void
  405. rremove(Fcall *f)
  406. {
  407. Fid *fidp;
  408. Node *dir, *np;
  409. fidp = newfid(f->fid);
  410. /*
  411. * only trusted temporary files can be removed
  412. * and only by their owner.
  413. */
  414. if(fidp->node->d.type != Trustedtemp){
  415. reply(f, "can't be removed");
  416. return;
  417. }
  418. if(fidp->uid != fidp->node->d.uid){
  419. reply(f, "permission denied");
  420. return;
  421. }
  422. dir = fidp->node->parent;
  423. for(np = dir->children; np; np = np->sibs)
  424. if(np->sibs == fidp->node)
  425. break;
  426. if(np)
  427. np->sibs = fidp->node->sibs;
  428. else
  429. dir->children = fidp->node->sibs;
  430. dir->count--;
  431. free(fidp->node);
  432. fidp->node = 0;
  433. fidp->open = 0;
  434. fidp->busy = 0;
  435. fidp->name = 0;
  436. fidp->uid = 0;
  437. reply(f, 0);
  438. }
  439. static void
  440. rstat(Fcall *f)
  441. {
  442. Fid *fidp;
  443. fidp = newfid(f->fid);
  444. if (fidp->node->d.type == Dummynode)
  445. dummy.d.name = fidp->name;
  446. f->stat = (uint8_t*)rbuf+4+1+2+2; /* knows about stat(5) */
  447. f->nstat = convD2M(&fidp->node->d, f->stat, MAXRPC);
  448. if(f->nstat <= BIT16SZ)
  449. reply(f, "ratfs: convD2M");
  450. else
  451. reply(f, 0);
  452. return;
  453. }
  454. static void
  455. rwstat(Fcall *f)
  456. {
  457. reply(f, "wstat not implemented");
  458. }