9p.c 21 KB

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