ftpd.c 34 KB

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