9p.c 21 KB

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