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