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 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 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* 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 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 143 rauth(Fcall *f) 144 { 145 reply(f, "ratfs: authentication not required"); 146 } 147 148 static void 149 rflush(Fcall *f) 150 { 151 reply(f, 0); 152 } 153 154 static void 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 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 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 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 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 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 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 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 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 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 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 508 rwstat(Fcall *f) 509 { 510 reply(f, "wstat not implemented"); 511 } 512 513