ftpd.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <auth.h>
  5. #include <ip.h>
  6. #include <libsec.h>
  7. #include <String.h>
  8. #include "glob.h"
  9. enum
  10. {
  11. /* telnet control character */
  12. Iac= 255,
  13. /* representation types */
  14. Tascii= 0,
  15. Timage= 1,
  16. /* transmission modes */
  17. Mstream= 0,
  18. Mblock= 1,
  19. Mpage= 2,
  20. /* file structure */
  21. Sfile= 0,
  22. Sblock= 1,
  23. Scompressed= 2,
  24. /* read/write buffer size */
  25. Nbuf= 4096,
  26. /* maximum ms we'll wait for a command */
  27. Maxwait= 1000*60*30, /* inactive for 30 minutes, we hang up */
  28. Maxerr= 128,
  29. Maxpath= 512,
  30. };
  31. int abortcmd(char*);
  32. int appendcmd(char*);
  33. int cdupcmd(char*);
  34. int cwdcmd(char*);
  35. int delcmd(char*);
  36. int helpcmd(char*);
  37. int listcmd(char*);
  38. int mdtmcmd(char*);
  39. int mkdircmd(char*);
  40. int modecmd(char*);
  41. int namelistcmd(char*);
  42. int nopcmd(char*);
  43. int passcmd(char*);
  44. int pasvcmd(char*);
  45. int portcmd(char*);
  46. int pwdcmd(char*);
  47. int quitcmd(char*);
  48. int rnfrcmd(char*);
  49. int rntocmd(char*);
  50. int reply(char*, ...);
  51. int restartcmd(char*);
  52. int retrievecmd(char*);
  53. int sizecmd(char*);
  54. int storecmd(char*);
  55. int storeucmd(char*);
  56. int structcmd(char*);
  57. int systemcmd(char*);
  58. int typecmd(char*);
  59. int usercmd(char*);
  60. int dialdata(void);
  61. char* abspath(char*);
  62. int crlfwrite(int, char*, int);
  63. int sodoff(void);
  64. int accessok(char*);
  65. typedef struct Cmd Cmd;
  66. struct Cmd
  67. {
  68. char *name;
  69. int (*f)(char*);
  70. int needlogin;
  71. };
  72. Cmd cmdtab[] =
  73. {
  74. { "abor", abortcmd, 0, },
  75. { "appe", appendcmd, 1, },
  76. { "cdup", cdupcmd, 1, },
  77. { "cwd", cwdcmd, 1, },
  78. { "dele", delcmd, 1, },
  79. { "help", helpcmd, 0, },
  80. { "list", listcmd, 1, },
  81. { "mdtm", mdtmcmd, 1, },
  82. { "mkd", mkdircmd, 1, },
  83. { "mode", modecmd, 0, },
  84. { "nlst", namelistcmd, 1, },
  85. { "noop", nopcmd, 0, },
  86. { "pass", passcmd, 0, },
  87. { "pasv", pasvcmd, 1, },
  88. { "pwd", pwdcmd, 0, },
  89. { "port", portcmd, 1, },
  90. { "quit", quitcmd, 0, },
  91. { "rest", restartcmd, 1, },
  92. { "retr", retrievecmd, 1, },
  93. { "rmd", delcmd, 1, },
  94. { "rnfr", rnfrcmd, 1, },
  95. { "rnto", rntocmd, 1, },
  96. { "size", sizecmd, 1, },
  97. { "stor", storecmd, 1, },
  98. { "stou", storeucmd, 1, },
  99. { "stru", structcmd, 1, },
  100. { "syst", systemcmd, 0, },
  101. { "type", typecmd, 0, },
  102. { "user", usercmd, 0, },
  103. { 0, 0, 0 },
  104. };
  105. #define NONENS "/lib/namespace.ftp" /* default ns for none */
  106. char user[Maxpath]; /* logged in user */
  107. char curdir[Maxpath]; /* current directory path */
  108. Chalstate *ch;
  109. int loggedin;
  110. int type; /* transmission type */
  111. int mode; /* transmission mode */
  112. int structure; /* file structure */
  113. char data[64]; /* data address */
  114. int pid; /* transfer process */
  115. int encryption; /* encryption state */
  116. int isnone, anon_ok, anon_only, anon_everybody;
  117. char cputype[Maxpath]; /* the environment variable of the same name */
  118. char bindir[Maxpath]; /* bin directory for this architecture */
  119. char mailaddr[Maxpath];
  120. char *namespace = NONENS;
  121. int debug;
  122. NetConnInfo *nci;
  123. int createperm = 0660;
  124. int isnoworld;
  125. vlong offset; /* from restart command */
  126. ulong id;
  127. typedef struct Passive Passive;
  128. struct Passive
  129. {
  130. int inuse;
  131. char adir[40];
  132. int afd;
  133. int port;
  134. uchar ipaddr[IPaddrlen];
  135. } passive;
  136. #define FTPLOG "ftp"
  137. void
  138. logit(char *fmt, ...)
  139. {
  140. char buf[8192];
  141. va_list arg;
  142. char errstr[128];
  143. rerrstr(errstr, sizeof errstr);
  144. va_start(arg, fmt);
  145. vseprint(buf, buf+sizeof(buf), fmt, arg);
  146. va_end(arg);
  147. syslog(0, FTPLOG, "%s.%s %s", nci->rsys, nci->rserv, buf);
  148. werrstr(errstr, sizeof errstr);
  149. }
  150. /*
  151. * read commands from the control stream and dispatch
  152. */
  153. void
  154. main(int argc, char **argv)
  155. {
  156. char *cmd;
  157. char *arg;
  158. char *p;
  159. Cmd *t;
  160. Biobuf in;
  161. int i;
  162. ARGBEGIN{
  163. case 'd':
  164. debug++;
  165. break;
  166. case 'a': /* anonymous OK */
  167. anon_ok = 1;
  168. break;
  169. case 'A':
  170. anon_ok = 1;
  171. anon_only = 1;
  172. break;
  173. case 'e':
  174. anon_ok = 1;
  175. anon_everybody = 1;
  176. break;
  177. case 'n':
  178. namespace = ARGF();
  179. break;
  180. }ARGEND
  181. /* open log file before doing a newns */
  182. syslog(0, FTPLOG, nil);
  183. /* find out who is calling */
  184. if(argc < 1)
  185. nci = getnetconninfo(nil, 0);
  186. else
  187. nci = getnetconninfo(argv[argc-1], 0);
  188. if(nci == nil)
  189. sysfatal("ftpd needs a network address");
  190. strcpy(mailaddr, "?");
  191. id = getpid();
  192. /* figure out which binaries to bind in later */
  193. arg = getenv("cputype");
  194. if(arg)
  195. strecpy(cputype, cputype+sizeof cputype, arg);
  196. else
  197. strcpy(cputype, "mips");
  198. snprint(bindir, sizeof(bindir), "/bin/%s/bin", cputype);
  199. Binit(&in, 0, OREAD);
  200. reply("220 Plan 9 FTP server ready");
  201. alarm(Maxwait);
  202. while(cmd = Brdline(&in, '\n')){
  203. alarm(0);
  204. /*
  205. * strip out trailing cr's & lf and delimit with null
  206. */
  207. i = Blinelen(&in)-1;
  208. cmd[i] = 0;
  209. if(debug)
  210. logit("%s", cmd);
  211. while(i > 0 && cmd[i-1] == '\r')
  212. cmd[--i] = 0;
  213. /*
  214. * hack for GatorFTP+, look for a 0x10 used as a delimiter
  215. */
  216. p = strchr(cmd, 0x10);
  217. if(p)
  218. *p = 0;
  219. /*
  220. * get rid of telnet control sequences (we don't need them)
  221. */
  222. while(*cmd && (uchar)*cmd == Iac){
  223. cmd++;
  224. if(*cmd)
  225. cmd++;
  226. }
  227. /*
  228. * parse the message (command arg)
  229. */
  230. arg = strchr(cmd, ' ');
  231. if(arg){
  232. *arg++ = 0;
  233. while(*arg == ' ')
  234. arg++;
  235. }
  236. /*
  237. * ignore blank commands
  238. */
  239. if(*cmd == 0)
  240. continue;
  241. /*
  242. * lookup the command and do it
  243. */
  244. for(p = cmd; *p; p++)
  245. *p = tolower(*p);
  246. for(t = cmdtab; t->name; t++)
  247. if(strcmp(cmd, t->name) == 0){
  248. if(t->needlogin && !loggedin)
  249. sodoff();
  250. else if((*t->f)(arg) < 0)
  251. exits(0);
  252. break;
  253. }
  254. if(t->f != restartcmd){
  255. /*
  256. * the file offset is set to zero following
  257. * all commands except the restart command
  258. */
  259. offset = 0;
  260. }
  261. if(t->name == 0){
  262. /*
  263. * the OOB bytes preceding an abort from UCB machines
  264. * comes out as something unrecognizable instead of
  265. * IAC's. Certainly a Plan 9 bug but I can't find it.
  266. * This is a major hack to avoid the problem. -- presotto
  267. */
  268. i = strlen(cmd);
  269. if(i > 4 && strcmp(cmd+i-4, "abor") == 0){
  270. abortcmd(0);
  271. } else{
  272. logit("%s (%s) command not implemented", cmd, arg?arg:"");
  273. reply("502 %s command not implemented", cmd);
  274. }
  275. }
  276. alarm(Maxwait);
  277. }
  278. if(pid)
  279. postnote(PNPROC, pid, "kill");
  280. }
  281. /*
  282. * reply to a command
  283. */
  284. int
  285. reply(char *fmt, ...)
  286. {
  287. va_list arg;
  288. char buf[8192], *s;
  289. va_start(arg, fmt);
  290. s = vseprint(buf, buf+sizeof(buf)-3, fmt, arg);
  291. va_end(arg);
  292. if(debug){
  293. *s = 0;
  294. logit("%s", buf);
  295. }
  296. *s++ = '\r';
  297. *s++ = '\n';
  298. write(1, buf, s - buf);
  299. return 0;
  300. }
  301. int
  302. sodoff(void)
  303. {
  304. return reply("530 Sod off, service requires login");
  305. }
  306. /*
  307. * run a command in a separate process
  308. */
  309. int
  310. asproc(void (*f)(char*, int), char *arg, int arg2)
  311. {
  312. int i;
  313. if(pid){
  314. /* wait for previous command to finish */
  315. for(;;){
  316. i = waitpid();
  317. if(i == pid || i < 0)
  318. break;
  319. }
  320. }
  321. switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
  322. case -1:
  323. return reply("450 Out of processes: %r");
  324. case 0:
  325. (*f)(arg, arg2);
  326. exits(0);
  327. default:
  328. break;
  329. }
  330. return 0;
  331. }
  332. /*
  333. * run a command to filter a tail
  334. */
  335. int
  336. transfer(char *cmd, char *a1, char *a2, char *a3, int image)
  337. {
  338. int n, dfd, fd, bytes, eofs, pid;
  339. int pfd[2];
  340. char buf[Nbuf], *p;
  341. Waitmsg *w;
  342. reply("150 Opening data connection for %s (%s)", cmd, data);
  343. dfd = dialdata();
  344. if(dfd < 0)
  345. return reply("425 Error opening data connection: %r");
  346. if(pipe(pfd) < 0)
  347. return reply("520 Internal Error: %r");
  348. bytes = 0;
  349. switch(pid = rfork(RFFDG|RFPROC|RFNAMEG)){
  350. case -1:
  351. return reply("450 Out of processes: %r");
  352. case 0:
  353. logit("running %s %s %s %s pid %d",
  354. cmd, a1?a1:"", a2?a2:"" , a3?a3:"",getpid());
  355. close(pfd[1]);
  356. close(dfd);
  357. dup(pfd[0], 1);
  358. dup(pfd[0], 2);
  359. if(isnone){
  360. fd = open("#s/boot", ORDWR);
  361. if(fd < 0
  362. || bind("#/", "/", MAFTER) < 0
  363. || amount(fd, "/bin", MREPL, "") < 0
  364. || bind("#c", "/dev", MAFTER) < 0
  365. || bind(bindir, "/bin", MREPL) < 0)
  366. exits("building name space");
  367. close(fd);
  368. }
  369. execl(cmd, cmd, a1, a2, a3, nil);
  370. exits(cmd);
  371. default:
  372. close(pfd[0]);
  373. eofs = 0;
  374. while((n = read(pfd[1], buf, sizeof buf)) >= 0){
  375. if(n == 0){
  376. if(eofs++ > 5)
  377. break;
  378. else
  379. continue;
  380. }
  381. eofs = 0;
  382. p = buf;
  383. if(offset > 0){
  384. if(n > offset){
  385. p = buf+offset;
  386. n -= offset;
  387. offset = 0;
  388. } else {
  389. offset -= n;
  390. continue;
  391. }
  392. }
  393. if(!image)
  394. n = crlfwrite(dfd, p, n);
  395. else
  396. n = write(dfd, p, n);
  397. if(n < 0){
  398. postnote(PNPROC, pid, "kill");
  399. bytes = -1;
  400. break;
  401. }
  402. bytes += n;
  403. }
  404. close(pfd[1]);
  405. close(dfd);
  406. break;
  407. }
  408. /* wait for this command to finish */
  409. for(;;){
  410. w = wait();
  411. if(w == nil || w->pid == pid)
  412. break;
  413. free(w);
  414. }
  415. if(w != nil && w->msg != nil && w->msg[0] != 0){
  416. bytes = -1;
  417. logit("%s", w->msg);
  418. logit("%s %s %s %s failed %s", cmd, a1?a1:"", a2?a2:"" , a3?a3:"", w->msg);
  419. }
  420. free(w);
  421. reply("226 Transfer complete");
  422. return bytes;
  423. }
  424. /*
  425. * just reply OK
  426. */
  427. int
  428. nopcmd(char *arg)
  429. {
  430. USED(arg);
  431. reply("510 Plan 9 FTP daemon still alive");
  432. return 0;
  433. }
  434. /*
  435. * login as user
  436. */
  437. int
  438. loginuser(char *user, char *nsfile, int gotoslash)
  439. {
  440. logit("login %s %s %s %s", user, mailaddr, nci->rsys, nsfile);
  441. if(nsfile != nil && newns(user, nsfile) < 0){
  442. logit("namespace file %s does not exist", nsfile);
  443. return reply("530 Not logged in: login out of service");
  444. }
  445. getwd(curdir, sizeof(curdir));
  446. if(gotoslash){
  447. chdir("/");
  448. strcpy(curdir, "/");
  449. }
  450. putenv("service", "ftp");
  451. loggedin = 1;
  452. if(debug == 0)
  453. reply("230- If you have problems, send mail to 'postmaster'.");
  454. return reply("230 Logged in");
  455. }
  456. /*
  457. * get a user id, reply with a challenge. The users 'anonymous'
  458. * and 'ftp' are equivalent to 'none'. The user 'none' requires
  459. * no challenge.
  460. */
  461. int
  462. usercmd(char *name)
  463. {
  464. logit("user %s %s", name, nci->rsys);
  465. if(loggedin)
  466. return reply("530 Already logged in as %s", user);
  467. if(name == 0 || *name == 0)
  468. return reply("530 user command needs user name");
  469. isnoworld = 0;
  470. if(*name == ':'){
  471. debug = 1;
  472. name++;
  473. }
  474. strncpy(user, name, sizeof(user));
  475. if(debug)
  476. logit("debugging");
  477. user[sizeof(user)-1] = 0;
  478. if(strcmp(user, "anonymous") == 0 || strcmp(user, "ftp") == 0)
  479. strcpy(user, "none");
  480. else if(anon_everybody)
  481. strcpy(user,"none");
  482. if(strcmp(user, "*none") == 0){
  483. if(!anon_ok)
  484. return reply("530 Not logged in: anonymous disallowed");
  485. return loginuser("none", namespace, 1);
  486. }
  487. if(strcmp(user, "none") == 0){
  488. if(!anon_ok)
  489. return reply("530 Not logged in: anonymous disallowed");
  490. return reply("331 Send email address as password");
  491. }
  492. if(anon_only)
  493. return reply("530 Not logged in: anonymous access only");
  494. isnoworld = noworld(name);
  495. if(isnoworld)
  496. return reply("331 OK");
  497. if(ch)
  498. auth_freechal(ch);
  499. if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
  500. return reply("421 %r");
  501. return reply("331 encrypt challenge, %s, as a password", ch->chal);
  502. }
  503. /*
  504. * get a password, set up user if it works.
  505. */
  506. int
  507. passcmd(char *response)
  508. {
  509. char namefile[128];
  510. AuthInfo *ai;
  511. if(response == nil)
  512. response = "";
  513. if(strcmp(user, "none") == 0 || strcmp(user, "*none") == 0){
  514. /* for none, accept anything as a password */
  515. isnone = 1;
  516. strncpy(mailaddr, response, sizeof(mailaddr)-1);
  517. return loginuser("none", namespace, 1);
  518. }
  519. if(isnoworld){
  520. /* noworld gets a password in the clear */
  521. if(login(user, response, "/lib/namespace.noworld") < 0)
  522. return reply("530 Not logged in");
  523. createperm = 0664;
  524. /* login has already setup the namespace */
  525. return loginuser(user, nil, 0);
  526. } else {
  527. /* for everyone else, do challenge response */
  528. if(ch == nil)
  529. return reply("531 Send user id before encrypted challenge");
  530. ch->resp = response;
  531. ch->nresp = strlen(response);
  532. ai = auth_response(ch);
  533. if(ai == nil)
  534. return reply("530 Not logged in: %r");
  535. if(auth_chuid(ai, nil) < 0)
  536. return reply("530 Not logged in: %r");
  537. auth_freechal(ch);
  538. ch = nil;
  539. /* if the user has specified a namespace for ftp, use it */
  540. snprint(namefile, sizeof(namefile), "/usr/%s/lib/namespace.ftp", user);
  541. strcpy(mailaddr, user);
  542. createperm = 0660;
  543. if(access(namefile, 0) == 0)
  544. return loginuser(user, namefile, 0);
  545. else
  546. return loginuser(user, "/lib/namespace", 0);
  547. }
  548. }
  549. /*
  550. * print working directory
  551. */
  552. int
  553. pwdcmd(char *arg)
  554. {
  555. if(arg)
  556. return reply("550 Pwd takes no argument");
  557. return reply("257 \"%s\" is the current directory", curdir);
  558. }
  559. /*
  560. * chdir
  561. */
  562. int
  563. cwdcmd(char *dir)
  564. {
  565. char *rp;
  566. char buf[Maxpath];
  567. /* shell cd semantics */
  568. if(dir == 0 || *dir == 0){
  569. if(isnone)
  570. rp = "/";
  571. else {
  572. snprint(buf, sizeof buf, "/usr/%s", user);
  573. rp = buf;
  574. }
  575. if(accessok(rp) == 0)
  576. rp = nil;
  577. } else
  578. rp = abspath(dir);
  579. if(rp == nil)
  580. return reply("550 Permission denied");
  581. if(chdir(rp) < 0)
  582. return reply("550 Cwd failed: %r");
  583. strcpy(curdir, rp);
  584. return reply("250 directory changed to %s", curdir);
  585. }
  586. /*
  587. * chdir ..
  588. */
  589. int
  590. cdupcmd(char *dp)
  591. {
  592. USED(dp);
  593. return cwdcmd("..");
  594. }
  595. int
  596. quitcmd(char *arg)
  597. {
  598. USED(arg);
  599. reply("200 Bye");
  600. if(pid)
  601. postnote(PNPROC, pid, "kill");
  602. return -1;
  603. }
  604. int
  605. typecmd(char *arg)
  606. {
  607. int c;
  608. char *x;
  609. x = arg;
  610. if(arg == 0)
  611. return reply("501 Type command needs arguments");
  612. while(c = *arg++){
  613. switch(tolower(c)){
  614. case 'a':
  615. type = Tascii;
  616. break;
  617. case 'i':
  618. case 'l':
  619. type = Timage;
  620. break;
  621. case '8':
  622. case ' ':
  623. case 'n':
  624. case 't':
  625. case 'c':
  626. break;
  627. default:
  628. return reply("501 Unimplemented type %s", x);
  629. }
  630. }
  631. return reply("200 Type %s", type==Tascii ? "Ascii" : "Image");
  632. }
  633. int
  634. modecmd(char *arg)
  635. {
  636. if(arg == 0)
  637. return reply("501 Mode command needs arguments");
  638. while(*arg){
  639. switch(tolower(*arg)){
  640. case 's':
  641. mode = Mstream;
  642. break;
  643. default:
  644. return reply("501 Unimplemented mode %c", *arg);
  645. }
  646. arg++;
  647. }
  648. return reply("200 Stream mode");
  649. }
  650. int
  651. structcmd(char *arg)
  652. {
  653. if(arg == 0)
  654. return reply("501 Struct command needs arguments");
  655. for(; *arg; arg++){
  656. switch(tolower(*arg)){
  657. case 'f':
  658. structure = Sfile;
  659. break;
  660. default:
  661. return reply("501 Unimplemented structure %c", *arg);
  662. }
  663. }
  664. return reply("200 File structure");
  665. }
  666. int
  667. portcmd(char *arg)
  668. {
  669. char *field[7];
  670. int n;
  671. if(arg == 0)
  672. return reply("501 Port command needs arguments");
  673. n = getfields(arg, field, 7, 0, ", ");
  674. if(n != 6)
  675. return reply("501 Incorrect port specification");
  676. snprint(data, sizeof data, "tcp!%.3s.%.3s.%.3s.%.3s!%d", field[0], field[1], field[2],
  677. field[3], atoi(field[4])*256 + atoi(field[5]));
  678. return reply("200 Data port is %s", data);
  679. }
  680. int
  681. mountnet(void)
  682. {
  683. int rv;
  684. rv = 0;
  685. if(bind("#/", "/", MAFTER) < 0){
  686. logit("can't bind #/ to /: %r");
  687. return reply("500 can't bind #/ to /: %r");
  688. }
  689. if(bind(nci->spec, "/net", MBEFORE) < 0){
  690. logit("can't bind %s to /net: %r", nci->spec);
  691. rv = reply("500 can't bind %s to /net: %r", nci->spec);
  692. unmount("#/", "/");
  693. }
  694. return rv;
  695. }
  696. void
  697. unmountnet(void)
  698. {
  699. unmount(0, "/net");
  700. unmount("#/", "/");
  701. }
  702. int
  703. pasvcmd(char *arg)
  704. {
  705. NetConnInfo *nnci;
  706. Passive *p;
  707. USED(arg);
  708. p = &passive;
  709. if(p->inuse){
  710. close(p->afd);
  711. p->inuse = 0;
  712. }
  713. if(mountnet() < 0)
  714. return 0;
  715. p->afd = announce("tcp!*!0", passive.adir);
  716. if(p->afd < 0){
  717. unmountnet();
  718. return reply("500 No free ports");
  719. }
  720. nnci = getnetconninfo(p->adir, -1);
  721. unmountnet();
  722. /* parse the local address */
  723. if(debug)
  724. logit("local sys is %s", nci->lsys);
  725. parseip(p->ipaddr, nci->lsys);
  726. if(ipcmp(p->ipaddr, v4prefix) == 0 || ipcmp(p->ipaddr, IPnoaddr) == 0)
  727. parseip(p->ipaddr, nci->lsys);
  728. p->port = atoi(nnci->lserv);
  729. freenetconninfo(nnci);
  730. p->inuse = 1;
  731. return reply("227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
  732. p->ipaddr[IPv4off+0], p->ipaddr[IPv4off+1], p->ipaddr[IPv4off+2], p->ipaddr[IPv4off+3],
  733. p->port>>8, p->port&0xff);
  734. }
  735. enum
  736. {
  737. Narg=32,
  738. };
  739. int Cflag, rflag, tflag, Rflag;
  740. int maxnamelen;
  741. int col;
  742. char*
  743. mode2asc(int m)
  744. {
  745. static char asc[12];
  746. char *p;
  747. strcpy(asc, "----------");
  748. if(DMDIR & m)
  749. asc[0] = 'd';
  750. if(DMAPPEND & m)
  751. asc[0] = 'a';
  752. else if(DMEXCL & m)
  753. asc[3] = 'l';
  754. for(p = asc+1; p < asc + 10; p += 3, m<<=3){
  755. if(m & 0400)
  756. p[0] = 'r';
  757. if(m & 0200)
  758. p[1] = 'w';
  759. if(m & 0100)
  760. p[2] = 'x';
  761. }
  762. return asc;
  763. }
  764. void
  765. listfile(Biobufhdr *b, char *name, int lflag, char *dname)
  766. {
  767. char ts[32];
  768. int n, links, pad;
  769. long now;
  770. char *x;
  771. Dir *d;
  772. x = abspath(name);
  773. if(x == nil)
  774. return;
  775. d = dirstat(x);
  776. if(d == nil)
  777. return;
  778. if(isnone){
  779. if(strncmp(x, "/incoming/", sizeof("/incoming/")-1) != 0)
  780. d->mode &= ~0222;
  781. d->uid = "none";
  782. d->gid = "none";
  783. }
  784. strcpy(ts, ctime(d->mtime));
  785. ts[16] = 0;
  786. now = time(0);
  787. if(now - d->mtime > 6*30*24*60*60)
  788. memmove(ts+11, ts+23, 5);
  789. if(lflag){
  790. /* Unix style long listing */
  791. if(DMDIR&d->mode){
  792. links = 2;
  793. d->length = 512;
  794. } else
  795. links = 1;
  796. Bprint(b, "%s %3d %-8s %-8s %7lld %s ",
  797. mode2asc(d->mode), links,
  798. d->uid, d->gid, d->length, ts+4);
  799. }
  800. if(Cflag && maxnamelen < 40){
  801. n = strlen(name);
  802. pad = ((col+maxnamelen)/(maxnamelen+1))*(maxnamelen+1);
  803. if(pad+maxnamelen+1 < 60){
  804. Bprint(b, "%*s", pad-col+n, name);
  805. col = pad+n;
  806. }
  807. else{
  808. Bprint(b, "\r\n%s", name);
  809. col = n;
  810. }
  811. }
  812. else{
  813. if(dname)
  814. Bprint(b, "%s/", dname);
  815. Bprint(b, "%s\r\n", name);
  816. }
  817. free(d);
  818. }
  819. int
  820. dircomp(void *va, void *vb)
  821. {
  822. int rv;
  823. Dir *a, *b;
  824. a = va;
  825. b = vb;
  826. if(tflag)
  827. rv = b->mtime - a->mtime;
  828. else
  829. rv = strcmp(a->name, b->name);
  830. return (rflag?-1:1)*rv;
  831. }
  832. void
  833. listdir(char *name, Biobufhdr *b, int lflag, int *printname, Globlist *gl)
  834. {
  835. Dir *p;
  836. int fd, n, i, l;
  837. char *dname;
  838. uvlong total;
  839. col = 0;
  840. fd = open(name, OREAD);
  841. if(fd < 0){
  842. Bprint(b, "can't read %s: %r\r\n", name);
  843. return;
  844. }
  845. dname = 0;
  846. if(*printname){
  847. if(Rflag || lflag)
  848. Bprint(b, "\r\n%s:\r\n", name);
  849. else
  850. dname = name;
  851. }
  852. n = dirreadall(fd, &p);
  853. close(fd);
  854. if(Cflag){
  855. for(i = 0; i < n; i++){
  856. l = strlen(p[i].name);
  857. if(l > maxnamelen)
  858. maxnamelen = l;
  859. }
  860. }
  861. /* Unix style total line */
  862. if(lflag){
  863. total = 0;
  864. for(i = 0; i < n; i++){
  865. if(p[i].qid.type & QTDIR)
  866. total += 512;
  867. else
  868. total += p[i].length;
  869. }
  870. Bprint(b, "total %ulld\r\n", total/512);
  871. }
  872. qsort(p, n, sizeof(Dir), dircomp);
  873. for(i = 0; i < n; i++){
  874. if(Rflag && (p[i].qid.type & QTDIR)){
  875. *printname = 1;
  876. globadd(gl, name, p[i].name);
  877. }
  878. listfile(b, p[i].name, lflag, dname);
  879. }
  880. free(p);
  881. }
  882. void
  883. list(char *arg, int lflag)
  884. {
  885. Dir *d;
  886. Globlist *gl;
  887. Glob *g;
  888. int dfd, printname;
  889. int i, n, argc;
  890. char *alist[Narg];
  891. char **argv;
  892. Biobufhdr bh;
  893. uchar buf[512];
  894. char *p, *s;
  895. if(arg == 0)
  896. arg = "";
  897. if(debug)
  898. logit("ls %s (. = %s)", arg, curdir);
  899. /* process arguments, understand /bin/ls -l option */
  900. argv = alist;
  901. argv[0] = "/bin/ls";
  902. argc = getfields(arg, argv+1, Narg-2, 1, " \t") + 1;
  903. argv[argc] = 0;
  904. rflag = 0;
  905. tflag = 0;
  906. Rflag = 0;
  907. Cflag = 0;
  908. col = 0;
  909. ARGBEGIN{
  910. case 'l':
  911. lflag++;
  912. break;
  913. case 'R':
  914. Rflag++;
  915. break;
  916. case 'C':
  917. Cflag++;
  918. break;
  919. case 'r':
  920. rflag++;
  921. break;
  922. case 't':
  923. tflag++;
  924. break;
  925. }ARGEND;
  926. if(Cflag)
  927. lflag = 0;
  928. dfd = dialdata();
  929. if(dfd < 0){
  930. reply("425 Error opening data connection:%r");
  931. return;
  932. }
  933. reply("150 Opened data connection (%s)", data);
  934. Binits(&bh, dfd, OWRITE, buf, sizeof(buf));
  935. if(argc == 0){
  936. argc = 1;
  937. argv = alist;
  938. argv[0] = ".";
  939. }
  940. for(i = 0; i < argc; i++){
  941. chdir(curdir);
  942. gl = glob(argv[i]);
  943. if(gl == nil)
  944. continue;
  945. printname = gl->first != nil && gl->first->next != nil;
  946. maxnamelen = 8;
  947. if(Cflag)
  948. for(g = gl->first; g; g = g->next)
  949. if(g->glob && (n = strlen(s_to_c(g->glob))) > maxnamelen)
  950. maxnamelen = n;
  951. while(s = globiter(gl)){
  952. if(debug)
  953. logit("glob %s", s);
  954. p = abspath(s);
  955. if(p == nil){
  956. free(s);
  957. continue;
  958. }
  959. d = dirstat(p);
  960. if(d == nil){
  961. free(s);
  962. continue;
  963. }
  964. if(d->qid.type & QTDIR)
  965. listdir(s, &bh, lflag, &printname, gl);
  966. else
  967. listfile(&bh, s, lflag, 0);
  968. free(s);
  969. free(d);
  970. }
  971. globlistfree(gl);
  972. }
  973. if(Cflag)
  974. Bprint(&bh, "\r\n");
  975. Bflush(&bh);
  976. close(dfd);
  977. reply("226 Transfer complete (list %s)", arg);
  978. }
  979. int
  980. namelistcmd(char *arg)
  981. {
  982. return asproc(list, arg, 0);
  983. }
  984. int
  985. listcmd(char *arg)
  986. {
  987. return asproc(list, arg, 1);
  988. }
  989. /*
  990. * return the size of the file
  991. */
  992. int
  993. sizecmd(char *arg)
  994. {
  995. Dir *d;
  996. int rv;
  997. if(arg == 0)
  998. return reply("501 Size command requires pathname");
  999. arg = abspath(arg);
  1000. d = dirstat(arg);
  1001. if(d == nil)
  1002. return reply("501 %r accessing %s", arg);
  1003. rv = reply("213 %lld", d->length);
  1004. free(d);
  1005. return rv;
  1006. }
  1007. /*
  1008. * return the modify time of the file
  1009. */
  1010. int
  1011. mdtmcmd(char *arg)
  1012. {
  1013. Dir *d;
  1014. Tm *t;
  1015. int rv;
  1016. if(arg == 0)
  1017. return reply("501 Mdtm command requires pathname");
  1018. if(arg == 0)
  1019. return reply("550 Permission denied");
  1020. d = dirstat(arg);
  1021. if(d == nil)
  1022. return reply("501 %r accessing %s", arg);
  1023. t = gmtime(d->mtime);
  1024. rv = reply("213 %4.4d%2.2d%2.2d%2.2d%2.2d%2.2d",
  1025. t->year+1900, t->mon+1, t->mday,
  1026. t->hour, t->min, t->sec);
  1027. free(d);
  1028. return rv;
  1029. }
  1030. /*
  1031. * set an offset to start reading a file from
  1032. * only lasts for one command
  1033. */
  1034. int
  1035. restartcmd(char *arg)
  1036. {
  1037. if(arg == 0)
  1038. return reply("501 Restart command requires offset");
  1039. offset = atoll(arg);
  1040. if(offset < 0){
  1041. offset = 0;
  1042. return reply("501 Bad offset");
  1043. }
  1044. return reply("350 Restarting at %lld. Send STORE or RETRIEVE", offset);
  1045. }
  1046. /*
  1047. * send a file to the user
  1048. */
  1049. int
  1050. crlfwrite(int fd, char *p, int n)
  1051. {
  1052. char *ep, *np;
  1053. char buf[2*Nbuf];
  1054. for(np = buf, ep = p + n; p < ep; p++){
  1055. if(*p == '\n')
  1056. *np++ = '\r';
  1057. *np++ = *p;
  1058. }
  1059. if(write(fd, buf, np - buf) == np - buf)
  1060. return n;
  1061. else
  1062. return -1;
  1063. }
  1064. void
  1065. retrievedir(char *arg)
  1066. {
  1067. int n;
  1068. char *p;
  1069. String *file;
  1070. if(type != Timage){
  1071. reply("550 This file requires type binary/image");
  1072. return;
  1073. }
  1074. file = s_copy(arg);
  1075. p = strrchr(s_to_c(file), '/');
  1076. if(p != s_to_c(file)){
  1077. *p++ = 0;
  1078. chdir(s_to_c(file));
  1079. } else {
  1080. chdir("/");
  1081. p = s_to_c(file)+1;
  1082. }
  1083. n = transfer("/bin/tar", "c", p, 0, 1);
  1084. if(n < 0)
  1085. logit("get %s failed", arg);
  1086. else
  1087. logit("get %s OK %d", arg, n);
  1088. s_free(file);
  1089. }
  1090. void
  1091. retrieve(char *arg, int arg2)
  1092. {
  1093. int dfd, fd, n, i, bytes;
  1094. Dir *d;
  1095. char buf[Nbuf];
  1096. char *p, *ep;
  1097. USED(arg2);
  1098. p = strchr(arg, '\r');
  1099. if(p){
  1100. logit("cr in file name", arg);
  1101. *p = 0;
  1102. }
  1103. fd = open(arg, OREAD);
  1104. if(fd == -1){
  1105. n = strlen(arg);
  1106. if(n > 4 && strcmp(arg+n-4, ".tar") == 0){
  1107. *(arg+n-4) = 0;
  1108. d = dirstat(arg);
  1109. if(d != nil){
  1110. if(d->qid.type & QTDIR){
  1111. retrievedir(arg);
  1112. free(d);
  1113. return;
  1114. }
  1115. free(d);
  1116. }
  1117. }
  1118. logit("get %s failed", arg);
  1119. reply("550 Error opening %s: %r", arg);
  1120. return;
  1121. }
  1122. if(offset != 0)
  1123. if(seek(fd, offset, 0) < 0){
  1124. reply("550 %s: seek to %lld failed", arg, offset);
  1125. close(fd);
  1126. return;
  1127. }
  1128. d = dirfstat(fd);
  1129. if(d != nil){
  1130. if(d->qid.type & QTDIR){
  1131. reply("550 %s: not a plain file.", arg);
  1132. close(fd);
  1133. free(d);
  1134. return;
  1135. }
  1136. free(d);
  1137. }
  1138. n = read(fd, buf, sizeof(buf));
  1139. if(n < 0){
  1140. logit("get %s failed", arg, mailaddr, nci->rsys);
  1141. reply("550 Error reading %s: %r", arg);
  1142. close(fd);
  1143. return;
  1144. }
  1145. if(type != Timage)
  1146. for(p = buf, ep = &buf[n]; p < ep; p++)
  1147. if(*p & 0x80){
  1148. close(fd);
  1149. reply("550 This file requires type binary/image");
  1150. return;
  1151. }
  1152. reply("150 Opening data connection for %s (%s)", arg, data);
  1153. dfd = dialdata();
  1154. if(dfd < 0){
  1155. reply("425 Error opening data connection:%r");
  1156. close(fd);
  1157. return;
  1158. }
  1159. bytes = 0;
  1160. do {
  1161. switch(type){
  1162. case Timage:
  1163. i = write(dfd, buf, n);
  1164. break;
  1165. default:
  1166. i = crlfwrite(dfd, buf, n);
  1167. break;
  1168. }
  1169. if(i != n){
  1170. close(fd);
  1171. close(dfd);
  1172. logit("get %s %r to data connection after %d", arg, bytes);
  1173. reply("550 Error writing to data connection: %r");
  1174. return;
  1175. }
  1176. bytes += n;
  1177. } while((n = read(fd, buf, sizeof(buf))) > 0);
  1178. if(n < 0)
  1179. logit("get %s %r after %d", arg, bytes);
  1180. close(fd);
  1181. close(dfd);
  1182. reply("226 Transfer complete");
  1183. logit("get %s OK %d", arg, bytes);
  1184. }
  1185. int
  1186. retrievecmd(char *arg)
  1187. {
  1188. if(arg == 0)
  1189. return reply("501 Retrieve command requires an argument");
  1190. arg = abspath(arg);
  1191. if(arg == 0)
  1192. return reply("550 Permission denied");
  1193. return asproc(retrieve, arg, 0);
  1194. }
  1195. /*
  1196. * get a file from the user
  1197. */
  1198. int
  1199. lfwrite(int fd, char *p, int n)
  1200. {
  1201. char *ep, *np;
  1202. char buf[Nbuf];
  1203. for(np = buf, ep = p + n; p < ep; p++){
  1204. if(*p != '\r')
  1205. *np++ = *p;
  1206. }
  1207. if(write(fd, buf, np - buf) == np - buf)
  1208. return n;
  1209. else
  1210. return -1;
  1211. }
  1212. void
  1213. store(char *arg, int fd)
  1214. {
  1215. int dfd, n, i;
  1216. char buf[Nbuf];
  1217. reply("150 Opening data connection for %s (%s)", arg, data);
  1218. dfd = dialdata();
  1219. if(dfd < 0){
  1220. reply("425 Error opening data connection:%r");
  1221. close(fd);
  1222. return;
  1223. }
  1224. while((n = read(dfd, buf, sizeof(buf))) > 0){
  1225. switch(type){
  1226. case Timage:
  1227. i = write(fd, buf, n);
  1228. break;
  1229. default:
  1230. i = lfwrite(fd, buf, n);
  1231. break;
  1232. }
  1233. if(i != n){
  1234. close(fd);
  1235. close(dfd);
  1236. reply("550 Error writing file");
  1237. return;
  1238. }
  1239. }
  1240. close(fd);
  1241. close(dfd);
  1242. logit("put %s OK", arg);
  1243. reply("226 Transfer complete");
  1244. }
  1245. int
  1246. storecmd(char *arg)
  1247. {
  1248. int fd, rv;
  1249. if(arg == 0)
  1250. return reply("501 Store command requires an argument");
  1251. arg = abspath(arg);
  1252. if(arg == 0)
  1253. return reply("550 Permission denied");
  1254. if(isnone && strncmp(arg, "/incoming/", sizeof("/incoming/")-1))
  1255. return reply("550 Permission denied");
  1256. if(offset){
  1257. fd = open(arg, OWRITE);
  1258. if(fd == -1)
  1259. return reply("550 Error opening %s: %r", arg);
  1260. if(seek(fd, offset, 0) == -1)
  1261. return reply("550 Error seeking %s to %d: %r",
  1262. arg, offset);
  1263. } else {
  1264. fd = create(arg, OWRITE, createperm);
  1265. if(fd == -1)
  1266. return reply("550 Error creating %s: %r", arg);
  1267. }
  1268. rv = asproc(store, arg, fd);
  1269. close(fd);
  1270. return rv;
  1271. }
  1272. int
  1273. appendcmd(char *arg)
  1274. {
  1275. int fd, rv;
  1276. if(arg == 0)
  1277. return reply("501 Append command requires an argument");
  1278. if(isnone)
  1279. return reply("550 Permission denied");
  1280. arg = abspath(arg);
  1281. if(arg == 0)
  1282. return reply("550 Error creating %s: Permission denied", arg);
  1283. fd = open(arg, OWRITE);
  1284. if(fd == -1){
  1285. fd = create(arg, OWRITE, createperm);
  1286. if(fd == -1)
  1287. return reply("550 Error creating %s: %r", arg);
  1288. }
  1289. seek(fd, 0, 2);
  1290. rv = asproc(store, arg, fd);
  1291. close(fd);
  1292. return rv;
  1293. }
  1294. int
  1295. storeucmd(char *arg)
  1296. {
  1297. int fd, rv;
  1298. char name[Maxpath];
  1299. USED(arg);
  1300. if(isnone)
  1301. return reply("550 Permission denied");
  1302. strncpy(name, "ftpXXXXXXXXXXX", sizeof name);
  1303. mktemp(name);
  1304. fd = create(name, OWRITE, createperm);
  1305. if(fd == -1)
  1306. return reply("550 Error creating %s: %r", name);
  1307. rv = asproc(store, name, fd);
  1308. close(fd);
  1309. return rv;
  1310. }
  1311. int
  1312. mkdircmd(char *name)
  1313. {
  1314. int fd;
  1315. if(name == 0)
  1316. return reply("501 Mkdir command requires an argument");
  1317. if(isnone)
  1318. return reply("550 Permission denied");
  1319. name = abspath(name);
  1320. if(name == 0)
  1321. return reply("550 Permission denied");
  1322. fd = create(name, OREAD, DMDIR|0775);
  1323. if(fd < 0)
  1324. return reply("550 Can't create %s: %r", name);
  1325. close(fd);
  1326. return reply("226 %s created", name);
  1327. }
  1328. int
  1329. delcmd(char *name)
  1330. {
  1331. if(name == 0)
  1332. return reply("501 Rmdir/delete command requires an argument");
  1333. if(isnone)
  1334. return reply("550 Permission denied");
  1335. name = abspath(name);
  1336. if(name == 0)
  1337. return reply("550 Permission denied");
  1338. if(remove(name) < 0)
  1339. return reply("550 Can't remove %s: %r", name);
  1340. else
  1341. return reply("226 %s removed", name);
  1342. }
  1343. /*
  1344. * kill off the last transfer (if the process still exists)
  1345. */
  1346. int
  1347. abortcmd(char *arg)
  1348. {
  1349. USED(arg);
  1350. logit("abort pid %d", pid);
  1351. if(pid){
  1352. if(postnote(PNPROC, pid, "kill") == 0)
  1353. reply("426 Command aborted");
  1354. else
  1355. logit("postnote pid %d %r", pid);
  1356. }
  1357. return reply("226 Abort processed");
  1358. }
  1359. int
  1360. systemcmd(char *arg)
  1361. {
  1362. USED(arg);
  1363. return reply("215 UNIX Type: L8 Version: Plan 9");
  1364. }
  1365. int
  1366. helpcmd(char *arg)
  1367. {
  1368. int i;
  1369. char buf[80];
  1370. char *p, *e;
  1371. USED(arg);
  1372. reply("214- the following commands are implemented:");
  1373. p = buf;
  1374. e = buf+sizeof buf;
  1375. for(i = 0; cmdtab[i].name; i++){
  1376. if((i%8) == 0){
  1377. reply("214-%s", buf);
  1378. p = buf;
  1379. }
  1380. p = seprint(p, e, " %-5.5s", cmdtab[i].name);
  1381. }
  1382. if(p != buf)
  1383. reply("214-%s", buf);
  1384. reply("214 ");
  1385. return 0;
  1386. }
  1387. /*
  1388. * renaming a file takes two commands
  1389. */
  1390. static String *filepath;
  1391. int
  1392. rnfrcmd(char *from)
  1393. {
  1394. if(isnone)
  1395. return reply("550 Permission denied");
  1396. if(from == 0)
  1397. return reply("501 Rename command requires an argument");
  1398. from = abspath(from);
  1399. if(from == 0)
  1400. return reply("550 Permission denied");
  1401. if(filepath == nil)
  1402. filepath = s_copy(from);
  1403. else{
  1404. s_reset(filepath);
  1405. s_append(filepath, from);
  1406. }
  1407. return reply("350 Rename %s to ...", s_to_c(filepath));
  1408. }
  1409. int
  1410. rntocmd(char *to)
  1411. {
  1412. int r;
  1413. Dir nd;
  1414. char *fp, *tp;
  1415. if(isnone)
  1416. return reply("550 Permission denied");
  1417. if(to == 0)
  1418. return reply("501 Rename command requires an argument");
  1419. to = abspath(to);
  1420. if(to == 0)
  1421. return reply("550 Permission denied");
  1422. if(filepath == nil || *(s_to_c(filepath)) == 0)
  1423. return reply("503 Rnto must be preceeded by an rnfr");
  1424. tp = strrchr(to, '/');
  1425. fp = strrchr(s_to_c(filepath), '/');
  1426. if((tp && fp == 0) || (fp && tp == 0)
  1427. || (fp && tp && (fp-s_to_c(filepath) != tp-to || memcmp(s_to_c(filepath), to, tp-to))))
  1428. return reply("550 Rename can't change directory");
  1429. if(tp)
  1430. to = tp+1;
  1431. nulldir(&nd);
  1432. nd.name = to;
  1433. if(dirwstat(s_to_c(filepath), &nd) < 0)
  1434. r = reply("550 Can't rename %s to %s: %r\n", s_to_c(filepath), to);
  1435. else
  1436. r = reply("250 %s now %s", s_to_c(filepath), to);
  1437. s_reset(filepath);
  1438. return r;
  1439. }
  1440. /*
  1441. * to dial out we need the network file system in our
  1442. * name space.
  1443. */
  1444. int
  1445. dialdata(void)
  1446. {
  1447. int fd, cfd;
  1448. char ldir[40];
  1449. char err[Maxerr];
  1450. if(mountnet() < 0)
  1451. return -1;
  1452. if(!passive.inuse){
  1453. fd = dial(data, "20", 0, 0);
  1454. errstr(err, sizeof err);
  1455. } else {
  1456. alarm(5*60*1000);
  1457. cfd = listen(passive.adir, ldir);
  1458. alarm(0);
  1459. errstr(err, sizeof err);
  1460. if(cfd < 0)
  1461. return -1;
  1462. fd = accept(cfd, ldir);
  1463. errstr(err, sizeof err);
  1464. close(cfd);
  1465. }
  1466. if(fd < 0)
  1467. logit("can't dial %s: %s", data, err);
  1468. unmountnet();
  1469. werrstr(err, sizeof err);
  1470. return fd;
  1471. }
  1472. int
  1473. postnote(int group, int pid, char *note)
  1474. {
  1475. char file[128];
  1476. int f, r;
  1477. /*
  1478. * Use #p because /proc may not be in the namespace.
  1479. */
  1480. switch(group) {
  1481. case PNPROC:
  1482. sprint(file, "#p/%d/note", pid);
  1483. break;
  1484. case PNGROUP:
  1485. sprint(file, "#p/%d/notepg", pid);
  1486. break;
  1487. default:
  1488. return -1;
  1489. }
  1490. f = open(file, OWRITE);
  1491. if(f < 0)
  1492. return -1;
  1493. r = strlen(note);
  1494. if(write(f, note, r) != r) {
  1495. close(f);
  1496. return -1;
  1497. }
  1498. close(f);
  1499. return 0;
  1500. }
  1501. /*
  1502. * to circumscribe the accessible files we have to eliminate ..'s
  1503. * and resolve all names from the root. We also remove any /bin/rc
  1504. * special characters to avoid later problems with executed commands.
  1505. */
  1506. char *special = "`;| ";
  1507. char*
  1508. abspath(char *origpath)
  1509. {
  1510. char *p, *sp, *path;
  1511. static String *rpath;
  1512. if(rpath == nil)
  1513. rpath = s_new();
  1514. else
  1515. s_reset(rpath);
  1516. if(origpath == nil)
  1517. s_append(rpath, curdir);
  1518. else{
  1519. if(*origpath != '/'){
  1520. s_append(rpath, curdir);
  1521. s_append(rpath, "/");
  1522. }
  1523. s_append(rpath, origpath);
  1524. }
  1525. path = s_to_c(rpath);
  1526. for(sp = special; *sp; sp++){
  1527. p = strchr(path, *sp);
  1528. if(p)
  1529. *p = 0;
  1530. }
  1531. cleanname(s_to_c(rpath));
  1532. rpath->ptr = rpath->base+strlen(rpath->base);
  1533. if(!accessok(s_to_c(rpath)))
  1534. return nil;
  1535. return s_to_c(rpath);
  1536. }
  1537. typedef struct Path Path;
  1538. struct Path {
  1539. Path *next;
  1540. String *path;
  1541. int inuse;
  1542. int ok;
  1543. };
  1544. enum
  1545. {
  1546. Maxlevel = 16,
  1547. Maxperlevel= 8,
  1548. };
  1549. Path *pathlevel[Maxlevel];
  1550. Path*
  1551. unlinkpath(char *path, int level)
  1552. {
  1553. String *s;
  1554. Path **l, *p;
  1555. int n;
  1556. n = 0;
  1557. for(l = &pathlevel[level]; *l; l = &(*l)->next){
  1558. p = *l;
  1559. /* hit */
  1560. if(strcmp(s_to_c(p->path), path) == 0){
  1561. *l = p->next;
  1562. p->next = nil;
  1563. return p;
  1564. }
  1565. /* reuse */
  1566. if(++n >= Maxperlevel){
  1567. *l = p->next;
  1568. s = p->path;
  1569. s_reset(p->path);
  1570. memset(p, 0, sizeof *p);
  1571. p->path = s_append(s, path);
  1572. return p;
  1573. }
  1574. }
  1575. /* allocate */
  1576. p = mallocz(sizeof *p, 1);
  1577. p->path = s_copy(path);
  1578. return p;
  1579. }
  1580. void
  1581. linkpath(Path *p, int level)
  1582. {
  1583. p->next = pathlevel[level];
  1584. pathlevel[level] = p;
  1585. p->inuse = 1;
  1586. }
  1587. void
  1588. addpath(Path *p, int level, int ok)
  1589. {
  1590. p->ok = ok;
  1591. p->next = pathlevel[level];
  1592. pathlevel[level] = p;
  1593. }
  1594. int
  1595. _accessok(String *s, int level)
  1596. {
  1597. Path *p;
  1598. char *cp;
  1599. int lvl, offset;
  1600. static char httplogin[] = "/.httplogin";
  1601. if(level < 0)
  1602. return 1;
  1603. lvl = level;
  1604. if(lvl >= Maxlevel)
  1605. lvl = Maxlevel - 1;
  1606. p = unlinkpath(s_to_c(s), lvl);
  1607. if(p->inuse){
  1608. /* move to front */
  1609. linkpath(p, lvl);
  1610. return p->ok;
  1611. }
  1612. cp = strrchr(s_to_c(s), '/');
  1613. if(cp == nil)
  1614. offset = 0;
  1615. else
  1616. offset = cp - s_to_c(s);
  1617. s_append(s, httplogin);
  1618. if(access(s_to_c(s), AEXIST) == 0){
  1619. addpath(p, lvl, 0);
  1620. return 0;
  1621. }
  1622. /*
  1623. * There's no way to shorten a String without
  1624. * knowing the implementation.
  1625. */
  1626. s->ptr = s->base+offset;
  1627. s_terminate(s);
  1628. addpath(p, lvl, _accessok(s, level-1));
  1629. return p->ok;
  1630. }
  1631. /*
  1632. * check for a subdirectory containing .httplogin
  1633. * at each level of the path.
  1634. */
  1635. int
  1636. accessok(char *path)
  1637. {
  1638. int level, r;
  1639. char *p;
  1640. String *npath;
  1641. npath = s_copy(path);
  1642. p = s_to_c(npath)+1;
  1643. for(level = 1; level < Maxlevel; level++){
  1644. p = strchr(p, '/');
  1645. if(p == nil)
  1646. break;
  1647. p++;
  1648. }
  1649. r = _accessok(npath, level-1);
  1650. s_free(npath);
  1651. return r;
  1652. }