9p.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110
  1. #include "stdinc.h"
  2. #include "9.h"
  3. enum {
  4. OMODE = 0x7, /* Topen/Tcreate mode */
  5. };
  6. enum {
  7. PermX = 1,
  8. PermW = 2,
  9. PermR = 4,
  10. };
  11. static char EPermission[] = "permission denied";
  12. static int
  13. permFile(File* file, Fid* fid, int perm)
  14. {
  15. char *u;
  16. DirEntry de;
  17. if(!fileGetDir(file, &de))
  18. return 0;
  19. /*
  20. * User none only gets other permissions.
  21. */
  22. if(strcmp(fid->uname, unamenone) != 0){
  23. /*
  24. * There is only one uid<->uname mapping
  25. * and it's already cached in the Fid, but
  26. * it might have changed during the lifetime
  27. * if this Fid.
  28. */
  29. if((u = unameByUid(de.uid)) != nil){
  30. if(strcmp(fid->uname, u) == 0 && ((perm<<6) & de.mode)){
  31. vtMemFree(u);
  32. deCleanup(&de);
  33. return 1;
  34. }
  35. vtMemFree(u);
  36. }
  37. if(groupMember(de.gid, fid->uname) && ((perm<<3) & de.mode)){
  38. deCleanup(&de);
  39. return 1;
  40. }
  41. }
  42. if(perm & de.mode){
  43. if(perm == PermX && (de.mode & ModeDir)){
  44. deCleanup(&de);
  45. return 1;
  46. }
  47. if(!groupMember(uidnoworld, fid->uname)){
  48. deCleanup(&de);
  49. return 1;
  50. }
  51. }
  52. if(fsysNoPermCheck(fid->fsys) || fid->con->noperm){
  53. deCleanup(&de);
  54. return 1;
  55. }
  56. vtSetError(EPermission);
  57. deCleanup(&de);
  58. return 0;
  59. }
  60. static int
  61. permFid(Fid* fid, int p)
  62. {
  63. return permFile(fid->file, fid, p);
  64. }
  65. static int
  66. permParent(Fid* fid, int p)
  67. {
  68. int r;
  69. File *parent;
  70. parent = fileGetParent(fid->file);
  71. r = permFile(parent, fid, p);
  72. fileDecRef(parent);
  73. return r;
  74. }
  75. int
  76. validFileName(char* name)
  77. {
  78. char *p;
  79. if(name == nil || name[0] == '\0'){
  80. vtSetError("no file name");
  81. return 0;
  82. }
  83. if(name[0] == '.'){
  84. if(name[1] == '\0' || (name[1] == '.' && name[2] == '\0')){
  85. vtSetError(". and .. illegal as file name");
  86. return 0;
  87. }
  88. }
  89. for(p = name; *p != '\0'; p++){
  90. if((*p & 0xFF) < 040){
  91. vtSetError("bad character in file name");
  92. return 0;
  93. }
  94. }
  95. return 1;
  96. }
  97. static int
  98. rTwstat(Msg* m)
  99. {
  100. Dir dir;
  101. Fid *fid;
  102. ulong mode, oldmode;
  103. DirEntry de;
  104. char *gid, *strs, *uid;
  105. int gl, op, retval, tsync;
  106. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  107. return 0;
  108. gid = uid = nil;
  109. retval = 0;
  110. if(strcmp(fid->uname, unamenone) == 0 || (fid->qid.type & QTAUTH)){
  111. vtSetError(EPermission);
  112. goto error0;
  113. }
  114. if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){
  115. vtSetError("read-only filesystem");
  116. goto error0;
  117. }
  118. if(!fileGetDir(fid->file, &de))
  119. goto error0;
  120. strs = vtMemAlloc(m->t.nstat);
  121. if(convM2D(m->t.stat, m->t.nstat, &dir, strs) == 0){
  122. vtSetError("wstat -- protocol botch");
  123. goto error;
  124. }
  125. /*
  126. * Run through each of the (sub-)fields in the provided Dir
  127. * checking for validity and whether it's a default:
  128. * .type, .dev and .atime are completely ignored and not checked;
  129. * .qid.path, .qid.vers and .muid are checked for validity but
  130. * any attempt to change them is an error.
  131. * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can
  132. * possibly be changed.
  133. *
  134. * 'Op' flags there are changed fields, i.e. it's not a no-op.
  135. * 'Tsync' flags all fields are defaulted.
  136. */
  137. tsync = 1;
  138. if(dir.qid.path != ~0){
  139. if(dir.qid.path != de.qid){
  140. vtSetError("wstat -- attempt to change qid.path");
  141. goto error;
  142. }
  143. tsync = 0;
  144. }
  145. if(dir.qid.vers != ~0){
  146. if(dir.qid.vers != de.mcount){
  147. vtSetError("wstat -- attempt to change qid.vers");
  148. goto error;
  149. }
  150. tsync = 0;
  151. }
  152. if(dir.muid != nil && *dir.muid != '\0'){
  153. if((uid = uidByUname(dir.muid)) == nil){
  154. vtSetError("wstat -- unknown muid");
  155. goto error;
  156. }
  157. if(strcmp(uid, de.mid) != 0){
  158. vtSetError("wstat -- attempt to change muid");
  159. goto error;
  160. }
  161. vtMemFree(uid);
  162. uid = nil;
  163. tsync = 0;
  164. }
  165. /*
  166. * Check .qid.type and .mode agree if neither is defaulted.
  167. */
  168. if(dir.qid.type != (uchar)~0 && dir.mode != ~0){
  169. if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
  170. vtSetError("wstat -- qid.type/mode mismatch");
  171. goto error;
  172. }
  173. }
  174. op = 0;
  175. oldmode = de.mode;
  176. if(dir.qid.type != (uchar)~0 || dir.mode != ~0){
  177. /*
  178. * .qid.type or .mode isn't defaulted, check for unknown bits.
  179. */
  180. if(dir.mode == ~0)
  181. dir.mode = (dir.qid.type<<24)|(de.mode & 0777);
  182. if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){
  183. vtSetError("wstat -- unknown bits in qid.type/mode");
  184. goto error;
  185. }
  186. /*
  187. * Synthesise a mode to check against the current settings.
  188. */
  189. mode = dir.mode & 0777;
  190. if(dir.mode & DMEXCL)
  191. mode |= ModeExclusive;
  192. if(dir.mode & DMAPPEND)
  193. mode |= ModeAppend;
  194. if(dir.mode & DMDIR)
  195. mode |= ModeDir;
  196. if((de.mode^mode) & ModeDir){
  197. vtSetError("wstat -- attempt to change directory bit");
  198. goto error;
  199. }
  200. if((de.mode & (ModeAppend|ModeExclusive|0777)) != mode){
  201. de.mode &= ~(ModeAppend|ModeExclusive|0777);
  202. de.mode |= mode;
  203. op = 1;
  204. }
  205. tsync = 0;
  206. }
  207. if(dir.mtime != ~0){
  208. if(dir.mtime != de.mtime){
  209. de.mtime = dir.mtime;
  210. op = 1;
  211. }
  212. tsync = 0;
  213. }
  214. if(dir.length != ~0){
  215. /*
  216. * Cannot change length on append-only files.
  217. * If we're changing the append bit, it's okay.
  218. */
  219. if(de.mode & oldmode & ModeAppend){
  220. vtSetError("wstat -- attempt to change length of append-only file");
  221. goto error;
  222. }
  223. if(de.mode & ModeDir){
  224. vtSetError("wstat -- attempt to change length of directory");
  225. goto error;
  226. }
  227. if(dir.length != de.size){
  228. de.size = dir.length;
  229. op = 1;
  230. }
  231. tsync = 0;
  232. }
  233. /*
  234. * Check for permission to change .mode, .mtime or .length,
  235. * must be owner or leader of either group, for which test gid
  236. * is needed; permission checks on gid will be done later.
  237. */
  238. if(dir.gid != nil && *dir.gid != '\0'){
  239. if((gid = uidByUname(dir.gid)) == nil){
  240. vtSetError("wstat -- unknown gid");
  241. goto error;
  242. }
  243. tsync = 0;
  244. }
  245. else
  246. gid = vtStrDup(de.gid);
  247. /*
  248. * 'Gl' counts whether neither, one or both groups are led.
  249. */
  250. gl = groupLeader(gid, fid->uname) != 0;
  251. gl += groupLeader(de.gid, fid->uname) != 0;
  252. if(op && !fsysWstatAllow(fid->fsys)){
  253. if(strcmp(fid->uid, de.uid) != 0 && !gl){
  254. vtSetError("wstat -- not owner or group leader");
  255. goto error;
  256. }
  257. }
  258. /*
  259. * Check for permission to change group, must be
  260. * either owner and in new group or leader of both groups.
  261. * If gid is nil here then
  262. */
  263. if(strcmp(gid, de.gid) != 0){
  264. if(!fsysWstatAllow(fid->fsys)
  265. && !(strcmp(fid->uid, de.uid) == 0 && groupMember(gid, fid->uname))
  266. && !(gl == 2)){
  267. vtSetError("wstat -- not owner and not group leaders");
  268. goto error;
  269. }
  270. vtMemFree(de.gid);
  271. de.gid = gid;
  272. gid = nil;
  273. op = 1;
  274. tsync = 0;
  275. }
  276. /*
  277. * Rename.
  278. * Check .name is valid and different to the current.
  279. * If so, check write permission in parent.
  280. */
  281. if(dir.name != nil && *dir.name != '\0'){
  282. if(!validFileName(dir.name))
  283. goto error;
  284. if(strcmp(dir.name, de.elem) != 0){
  285. if(!permParent(fid, PermW))
  286. goto error;
  287. vtMemFree(de.elem);
  288. de.elem = vtStrDup(dir.name);
  289. op = 1;
  290. }
  291. tsync = 0;
  292. }
  293. /*
  294. * Check for permission to change owner - must be god.
  295. */
  296. if(dir.uid != nil && *dir.uid != '\0'){
  297. if((uid = uidByUname(dir.uid)) == nil){
  298. vtSetError("wstat -- unknown uid");
  299. goto error;
  300. }
  301. if(strcmp(uid, de.uid) != 0){
  302. if(!fsysWstatAllow(fid->fsys)){
  303. vtSetError("wstat -- not owner");
  304. goto error;
  305. }
  306. if(strcmp(uid, uidnoworld) == 0){
  307. vtSetError(EPermission);
  308. goto error;
  309. }
  310. vtMemFree(de.uid);
  311. de.uid = uid;
  312. uid = nil;
  313. op = 1;
  314. }
  315. tsync = 0;
  316. }
  317. if(op)
  318. retval = fileSetDir(fid->file, &de, fid->uid);
  319. else
  320. retval = 1;
  321. if(tsync){
  322. /*
  323. * All values were defaulted,
  324. * make the state of the file exactly what it
  325. * claims to be before returning...
  326. */
  327. USED(tsync);
  328. }
  329. error:
  330. deCleanup(&de);
  331. vtMemFree(strs);
  332. if(gid != nil)
  333. vtMemFree(gid);
  334. if(uid != nil)
  335. vtMemFree(uid);
  336. error0:
  337. fidPut(fid);
  338. return retval;
  339. };
  340. static int
  341. rTstat(Msg* m)
  342. {
  343. Dir dir;
  344. Fid *fid;
  345. DirEntry de;
  346. if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
  347. return 0;
  348. if(fid->qid.type & QTAUTH){
  349. memset(&dir, 0, sizeof(Dir));
  350. dir.qid = fid->qid;
  351. dir.mode = DMAUTH;
  352. dir.atime = time(0L);
  353. dir.mtime = dir.atime;
  354. dir.length = 0;
  355. dir.name = "#¿";
  356. dir.uid = fid->uname;
  357. dir.gid = fid->uname;
  358. dir.muid = fid->uname;
  359. if((m->r.nstat = convD2M(&dir, m->data, m->con->msize)) == 0){
  360. vtSetError("stat QTAUTH botch");
  361. fidPut(fid);
  362. return 0;
  363. }
  364. m->r.stat = m->data;
  365. fidPut(fid);
  366. return 1;
  367. }
  368. if(!fileGetDir(fid->file, &de)){
  369. fidPut(fid);
  370. return 0;
  371. }
  372. fidPut(fid);
  373. /*
  374. * TODO: optimise this copy (in convS2M) away somehow.
  375. * This pettifoggery with m->data will do for the moment.
  376. */
  377. m->r.nstat = dirDe2M(&de, m->data, m->con->msize);
  378. m->r.stat = m->data;
  379. deCleanup(&de);
  380. return 1;
  381. }
  382. static int
  383. _rTclunk(Fid* fid, int remove)
  384. {
  385. int rok;
  386. if(fid->excl)
  387. exclFree(fid);
  388. rok = 1;
  389. if(remove && !(fid->qid.type & QTAUTH)){
  390. if((rok = permParent(fid, PermW)) != 0)
  391. rok = fileRemove(fid->file, fid->uid);
  392. }
  393. fidClunk(fid);
  394. return rok;
  395. }
  396. static int
  397. rTremove(Msg* m)
  398. {
  399. Fid *fid;
  400. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  401. return 0;
  402. return _rTclunk(fid, 1);
  403. }
  404. static int
  405. rTclunk(Msg* m)
  406. {
  407. Fid *fid;
  408. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  409. return 0;
  410. _rTclunk(fid, (fid->open & FidORclose));
  411. return 1;
  412. }
  413. static int
  414. rTwrite(Msg* m)
  415. {
  416. Fid *fid;
  417. int count, n;
  418. if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
  419. return 0;
  420. if(!(fid->open & FidOWrite)){
  421. vtSetError("fid not open for write");
  422. goto error;
  423. }
  424. count = m->t.count;
  425. if(count < 0 || count > m->con->msize-IOHDRSZ){
  426. vtSetError("write count too big");
  427. goto error;
  428. }
  429. if(m->t.offset < 0){
  430. vtSetError("write offset negative");
  431. goto error;
  432. }
  433. if(fid->excl != nil && !exclUpdate(fid))
  434. goto error;
  435. if(fid->qid.type & QTDIR){
  436. vtSetError("is a directory");
  437. goto error;
  438. }
  439. else if(fid->qid.type & QTAUTH)
  440. n = authWrite(fid, m->t.data, count);
  441. else
  442. n = fileWrite(fid->file, m->t.data, count, m->t.offset, fid->uid);
  443. if(n < 0)
  444. goto error;
  445. m->r.count = n;
  446. fidPut(fid);
  447. return 1;
  448. error:
  449. fidPut(fid);
  450. return 0;
  451. }
  452. static int
  453. rTread(Msg* m)
  454. {
  455. Fid *fid;
  456. uchar *data;
  457. int count, n;
  458. if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
  459. return 0;
  460. if(!(fid->open & FidORead)){
  461. vtSetError("fid not open for read");
  462. goto error;
  463. }
  464. count = m->t.count;
  465. if(count < 0 || count > m->con->msize-IOHDRSZ){
  466. vtSetError("read count too big");
  467. goto error;
  468. }
  469. if(m->t.offset < 0){
  470. vtSetError("read offset negative");
  471. goto error;
  472. }
  473. if(fid->excl != nil && !exclUpdate(fid))
  474. goto error;
  475. /*
  476. * TODO: optimise this copy (in convS2M) away somehow.
  477. * This pettifoggery with m->data will do for the moment.
  478. */
  479. data = m->data+IOHDRSZ;
  480. if(fid->qid.type & QTDIR)
  481. n = dirRead(fid, data, count, m->t.offset);
  482. else if(fid->qid.type & QTAUTH)
  483. n = authRead(fid, data, count);
  484. else
  485. n = fileRead(fid->file, data, count, m->t.offset);
  486. if(n < 0)
  487. goto error;
  488. m->r.count = n;
  489. m->r.data = (char*)data;
  490. fidPut(fid);
  491. return 1;
  492. error:
  493. fidPut(fid);
  494. return 0;
  495. }
  496. static int
  497. rTcreate(Msg* m)
  498. {
  499. Fid *fid;
  500. File *file;
  501. ulong mode;
  502. int omode, open, perm;
  503. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  504. return 0;
  505. if(fid->open){
  506. vtSetError("fid open for I/O");
  507. goto error;
  508. }
  509. if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){
  510. vtSetError("read-only filesystem");
  511. goto error;
  512. }
  513. if(!fileIsDir(fid->file)){
  514. vtSetError("not a directory");
  515. goto error;
  516. }
  517. if(!permFid(fid, PermW))
  518. goto error;
  519. if(!validFileName(m->t.name))
  520. goto error;
  521. if(strcmp(fid->uid, uidnoworld) == 0){
  522. vtSetError(EPermission);
  523. goto error;
  524. }
  525. omode = m->t.mode & OMODE;
  526. open = 0;
  527. if(omode == OREAD || omode == ORDWR || omode == OEXEC)
  528. open |= FidORead;
  529. if(omode == OWRITE || omode == ORDWR)
  530. open |= FidOWrite;
  531. if((open & (FidOWrite|FidORead)) == 0){
  532. vtSetError("unknown mode");
  533. goto error;
  534. }
  535. if(m->t.perm & DMDIR){
  536. if((m->t.mode & (ORCLOSE|OTRUNC)) || (open & FidOWrite)){
  537. vtSetError("illegal mode");
  538. goto error;
  539. }
  540. if(m->t.perm & DMAPPEND){
  541. vtSetError("illegal perm");
  542. goto error;
  543. }
  544. }
  545. mode = fileGetMode(fid->file);
  546. perm = m->t.perm;
  547. if(m->t.perm & DMDIR)
  548. perm &= ~0777|(mode & 0777);
  549. else
  550. perm &= ~0666|(mode & 0666);
  551. mode = perm & 0777;
  552. if(m->t.perm & DMDIR)
  553. mode |= ModeDir;
  554. if(m->t.perm & DMAPPEND)
  555. mode |= ModeAppend;
  556. if(m->t.perm & DMEXCL)
  557. mode |= ModeExclusive;
  558. if((file = fileCreate(fid->file, m->t.name, mode, fid->uid)) == nil){
  559. fidPut(fid);
  560. return 0;
  561. }
  562. fileDecRef(fid->file);
  563. fid->qid.vers = fileGetMcount(file);
  564. fid->qid.path = fileGetId(file);
  565. fid->file = file;
  566. mode = fileGetMode(fid->file);
  567. if(mode & ModeDir)
  568. fid->qid.type = QTDIR;
  569. else
  570. fid->qid.type = QTFILE;
  571. if(mode & ModeAppend)
  572. fid->qid.type |= QTAPPEND;
  573. if(mode & ModeExclusive){
  574. fid->qid.type |= QTEXCL;
  575. assert(exclAlloc(fid) != 0);
  576. }
  577. if(m->t.mode & ORCLOSE)
  578. open |= FidORclose;
  579. fid->open = open;
  580. m->r.qid = fid->qid;
  581. m->r.iounit = m->con->msize-IOHDRSZ;
  582. fidPut(fid);
  583. return 1;
  584. error:
  585. fidPut(fid);
  586. return 0;
  587. }
  588. static int
  589. rTopen(Msg* m)
  590. {
  591. Fid *fid;
  592. int isdir, mode, omode, open, rofs;
  593. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  594. return 0;
  595. if(fid->open){
  596. vtSetError("fid open for I/O");
  597. goto error;
  598. }
  599. isdir = fileIsDir(fid->file);
  600. open = 0;
  601. rofs = fileIsRoFs(fid->file) || !groupWriteMember(fid->uname);
  602. if(m->t.mode & ORCLOSE){
  603. if(isdir){
  604. vtSetError("is a directory");
  605. goto error;
  606. }
  607. if(rofs){
  608. vtSetError("read-only filesystem");
  609. goto error;
  610. }
  611. if(!permParent(fid, PermW))
  612. goto error;
  613. open |= FidORclose;
  614. }
  615. omode = m->t.mode & OMODE;
  616. if(omode == OREAD || omode == ORDWR){
  617. if(!permFid(fid, PermR))
  618. goto error;
  619. open |= FidORead;
  620. }
  621. if(omode == OWRITE || omode == ORDWR || (m->t.mode & OTRUNC)){
  622. if(isdir){
  623. vtSetError("is a directory");
  624. goto error;
  625. }
  626. if(rofs){
  627. vtSetError("read-only filesystem");
  628. goto error;
  629. }
  630. if(!permFid(fid, PermW))
  631. goto error;
  632. open |= FidOWrite;
  633. }
  634. if(omode == OEXEC){
  635. if(isdir){
  636. vtSetError("is a directory");
  637. goto error;
  638. }
  639. if(!permFid(fid, PermX))
  640. goto error;
  641. open |= FidORead;
  642. }
  643. if((open & (FidOWrite|FidORead)) == 0){
  644. vtSetError("unknown mode");
  645. goto error;
  646. }
  647. mode = fileGetMode(fid->file);
  648. if((mode & ModeExclusive) && exclAlloc(fid) == 0)
  649. goto error;
  650. /*
  651. * Everything checks out, try to commit any changes.
  652. */
  653. if((m->t.mode & OTRUNC) && !(mode & ModeAppend)){
  654. if(!fileTruncate(fid->file, fid->uid))
  655. goto error;
  656. fid->qid.vers = fileGetMcount(fid->file);
  657. }
  658. if(isdir && fid->db != nil){
  659. dirBufFree(fid->db);
  660. fid->db = nil;
  661. }
  662. m->r.qid = fid->qid;
  663. m->r.iounit = m->con->msize-IOHDRSZ;
  664. fid->open = open;
  665. fidPut(fid);
  666. return 1;
  667. error:
  668. if(fid->excl != nil)
  669. exclFree(fid);
  670. fidPut(fid);
  671. return 0;
  672. }
  673. static int
  674. rTwalk(Msg* m)
  675. {
  676. Qid qid;
  677. Fcall *r, *t;
  678. int nwname, wlock;
  679. File *file, *nfile;
  680. Fid *fid, *ofid, *nfid;
  681. t = &m->t;
  682. if(t->fid == t->newfid)
  683. wlock = FidFWlock;
  684. else
  685. wlock = 0;
  686. /*
  687. * The file identified by t->fid must be valid in the
  688. * current session and must not have been opened for I/O
  689. * by an open or create message.
  690. */
  691. if((ofid = fidGet(m->con, t->fid, wlock)) == nil)
  692. return 0;
  693. if(ofid->open){
  694. vtSetError("file open for I/O");
  695. fidPut(ofid);
  696. return 0;
  697. }
  698. /*
  699. * If newfid is not the same as fid, allocate a new file;
  700. * a side effect is checking newfid is not already in use (error);
  701. * if there are no names to walk this will be equivalent to a
  702. * simple 'clone' operation.
  703. * It's a no-op if newfid is the same as fid and t->nwname is 0.
  704. */
  705. nfid = nil;
  706. if(t->fid != t->newfid){
  707. nfid = fidGet(m->con, t->newfid, FidFWlock|FidFCreate);
  708. if(nfid == nil){
  709. vtSetError("fid in use");
  710. fidPut(ofid);
  711. return 0;
  712. }
  713. nfid->open = ofid->open & ~FidORclose;
  714. nfid->file = fileIncRef(ofid->file);
  715. nfid->qid = ofid->qid;
  716. nfid->uid = vtStrDup(ofid->uid);
  717. nfid->uname = vtStrDup(ofid->uname);
  718. nfid->fsys = fsysIncRef(ofid->fsys);
  719. fid = nfid;
  720. }
  721. else
  722. fid = ofid;
  723. r = &m->r;
  724. r->nwqid = 0;
  725. if(t->nwname == 0){
  726. if(nfid != nil)
  727. fidPut(nfid);
  728. fidPut(ofid);
  729. return 1;
  730. }
  731. file = fid->file;
  732. fileIncRef(file);
  733. qid = fid->qid;
  734. for(nwname = 0; nwname < t->nwname; nwname++){
  735. /*
  736. * Walked elements must represent a directory and
  737. * the implied user must have permission to search
  738. * the directory. Walking .. is always allowed, so that
  739. * you can't walk into a directory and then not be able
  740. * to walk out of it.
  741. */
  742. if(!(qid.type & QTDIR)){
  743. vtSetError("not a directory");
  744. break;
  745. }
  746. if(!permFile(file, fid, PermX) && strcmp(t->wname[nwname], "..") != 0)
  747. break;
  748. if((nfile = fileWalk(file, t->wname[nwname])) == nil)
  749. break;
  750. fileDecRef(file);
  751. file = nfile;
  752. qid.type = QTFILE;
  753. if(fileIsDir(file))
  754. qid.type = QTDIR;
  755. qid.vers = fileGetMcount(file);
  756. qid.path = fileGetId(file);
  757. r->wqid[r->nwqid++] = qid;
  758. }
  759. if(nwname == t->nwname){
  760. /*
  761. * Walked all elements. Update the target fid
  762. * from the temporary qid used during the walk,
  763. * and tidy up.
  764. */
  765. fid->qid = r->wqid[r->nwqid-1];
  766. fileDecRef(fid->file);
  767. fid->file = file;
  768. if(nfid != nil)
  769. fidPut(nfid);
  770. fidPut(ofid);
  771. return 1;
  772. }
  773. /*
  774. * Didn't walk all elements, 'clunk' nfid if it exists
  775. * and leave fid untouched.
  776. * It's not an error if some of the elements were walked OK.
  777. */
  778. fileDecRef(file);
  779. if(nfid != nil)
  780. fidClunk(nfid);
  781. fidPut(ofid);
  782. if(nwname == 0)
  783. return 0;
  784. return 1;
  785. }
  786. static int
  787. rTflush(Msg* m)
  788. {
  789. if(m->t.oldtag != NOTAG)
  790. msgFlush(m);
  791. return 1;
  792. }
  793. static void
  794. parseAname(char *aname, char **fsname, char **path)
  795. {
  796. char *s;
  797. if(aname && aname[0])
  798. s = vtStrDup(aname);
  799. else
  800. s = vtStrDup("main/active");
  801. *fsname = s;
  802. if((*path = strchr(s, '/')) != nil)
  803. *(*path)++ = '\0';
  804. else
  805. *path = "";
  806. }
  807. static int
  808. rTattach(Msg* m)
  809. {
  810. Fid *fid;
  811. Fsys *fsys;
  812. char *fsname, *path;
  813. if((fid = fidGet(m->con, m->t.fid, FidFWlock|FidFCreate)) == nil)
  814. return 0;
  815. parseAname(m->t.aname, &fsname, &path);
  816. if((fsys = fsysGet(fsname)) == nil){
  817. fidClunk(fid);
  818. vtMemFree(fsname);
  819. return 0;
  820. }
  821. fid->fsys = fsys;
  822. if(m->t.uname[0] != '\0')
  823. fid->uname = vtStrDup(m->t.uname);
  824. else
  825. fid->uname = vtStrDup(unamenone);
  826. if(fsysNoAuthCheck(fsys) || m->con->noauth){
  827. if((fid->uid = uidByUname(fid->uname)) == nil)
  828. fid->uid = vtStrDup(unamenone);
  829. }
  830. else if(!authCheck(&m->t, fid, fsys)){
  831. fidClunk(fid);
  832. vtMemFree(fsname);
  833. vtSetError("authentication failed");
  834. return 0;
  835. }
  836. fsysFsRlock(fsys);
  837. if((fid->file = fsysGetRoot(fsys, path)) == nil){
  838. fsysFsRUnlock(fsys);
  839. fidClunk(fid);
  840. vtMemFree(fsname);
  841. return 0;
  842. }
  843. fsysFsRUnlock(fsys);
  844. vtMemFree(fsname);
  845. fid->qid = (Qid){fileGetId(fid->file), 0, QTDIR};
  846. m->r.qid = fid->qid;
  847. fidPut(fid);
  848. return 1;
  849. }
  850. static int
  851. rTauth(Msg* m)
  852. {
  853. int afd;
  854. Con *con;
  855. Fid *afid;
  856. Fsys *fsys;
  857. char *fsname, *path;
  858. parseAname(m->t.aname, &fsname, &path);
  859. if((fsys = fsysGet(fsname)) == nil){
  860. vtMemFree(fsname);
  861. return 0;
  862. }
  863. vtMemFree(fsname);
  864. if(fsysNoAuthCheck(fsys) || m->con->noauth){
  865. m->con->aok = 1;
  866. vtSetError("authentication disabled");
  867. fsysPut(fsys);
  868. return 0;
  869. }
  870. if(strcmp(m->t.uname, unamenone) == 0){
  871. vtSetError("user 'none' requires no authentication");
  872. fsysPut(fsys);
  873. return 0;
  874. }
  875. con = m->con;
  876. if((afid = fidGet(con, m->t.afid, FidFWlock|FidFCreate)) == nil){
  877. fsysPut(fsys);
  878. return 0;
  879. }
  880. afid->fsys = fsys;
  881. if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
  882. vtSetError("can't open \"/mnt/factotum/rpc\"");
  883. fidClunk(afid);
  884. return 0;
  885. }
  886. if((afid->rpc = auth_allocrpc(afd)) == nil){
  887. close(afd);
  888. vtSetError("can't auth_allocrpc");
  889. fidClunk(afid);
  890. return 0;
  891. }
  892. if(auth_rpc(afid->rpc, "start", "proto=p9any role=server", 23) != ARok){
  893. vtSetError("can't auth_rpc");
  894. fidClunk(afid);
  895. return 0;
  896. }
  897. afid->open = FidOWrite|FidORead;
  898. afid->qid.type = QTAUTH;
  899. afid->qid.path = m->t.afid;
  900. afid->uname = vtStrDup(m->t.uname);
  901. m->r.qid = afid->qid;
  902. fidPut(afid);
  903. return 1;
  904. }
  905. static int
  906. rTversion(Msg* m)
  907. {
  908. int v;
  909. Con *con;
  910. Fcall *r, *t;
  911. t = &m->t;
  912. r = &m->r;
  913. con = m->con;
  914. vtLock(con->lock);
  915. if(con->state != ConInit){
  916. vtUnlock(con->lock);
  917. vtSetError("Tversion: down");
  918. return 0;
  919. }
  920. con->state = ConNew;
  921. /*
  922. * Release the karma of past lives and suffering.
  923. * Should this be done before or after checking the
  924. * validity of the Tversion?
  925. */
  926. fidClunkAll(con);
  927. if(t->tag != NOTAG){
  928. vtUnlock(con->lock);
  929. vtSetError("Tversion: invalid tag");
  930. return 0;
  931. }
  932. if(t->msize < 256){
  933. vtUnlock(con->lock);
  934. vtSetError("Tversion: message size too small");
  935. return 0;
  936. }
  937. if(t->msize < con->msize)
  938. r->msize = t->msize;
  939. else
  940. r->msize = con->msize;
  941. r->version = "unknown";
  942. if(t->version[0] == '9' && t->version[1] == 'P'){
  943. /*
  944. * Currently, the only defined version
  945. * is "9P2000"; ignore any later versions.
  946. */
  947. v = strtol(&t->version[2], 0, 10);
  948. if(v >= 2000){
  949. r->version = VERSION9P;
  950. con->msize = r->msize;
  951. con->state = ConUp;
  952. }
  953. else if(strcmp(t->version, "9PEoF") == 0){
  954. r->version = "9PEoF";
  955. con->msize = r->msize;
  956. con->state = ConMoribund;
  957. }
  958. }
  959. vtUnlock(con->lock);
  960. return 1;
  961. }
  962. int (*rFcall[Tmax])(Msg*) = {
  963. [Tversion] = rTversion,
  964. [Tauth] = rTauth,
  965. [Tattach] = rTattach,
  966. [Tflush] = rTflush,
  967. [Twalk] = rTwalk,
  968. [Topen] = rTopen,
  969. [Tcreate] = rTcreate,
  970. [Tread] = rTread,
  971. [Twrite] = rTwrite,
  972. [Tclunk] = rTclunk,
  973. [Tremove] = rTremove,
  974. [Tstat] = rTstat,
  975. [Twstat] = rTwstat,
  976. };