HardenedBSD src tree https://hardenedbsd.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2801 lines
57 KiB

  1. /* $NetBSD: cmds.c,v 1.17 2010/01/12 06:55:47 lukem Exp $ */
  2. /* from NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp */
  3. /*-
  4. * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
  5. * All rights reserved.
  6. *
  7. * This code is derived from software contributed to The NetBSD Foundation
  8. * by Luke Mewburn.
  9. *
  10. * This code is derived from software contributed to The NetBSD Foundation
  11. * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
  12. * NASA Ames Research Center.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. * 1. Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright
  20. * notice, this list of conditions and the following disclaimer in the
  21. * documentation and/or other materials provided with the distribution.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  24. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  25. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  26. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  27. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  31. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. /*
  36. * Copyright (c) 1985, 1989, 1993, 1994
  37. * The Regents of the University of California. All rights reserved.
  38. *
  39. * Redistribution and use in source and binary forms, with or without
  40. * modification, are permitted provided that the following conditions
  41. * are met:
  42. * 1. Redistributions of source code must retain the above copyright
  43. * notice, this list of conditions and the following disclaimer.
  44. * 2. Redistributions in binary form must reproduce the above copyright
  45. * notice, this list of conditions and the following disclaimer in the
  46. * documentation and/or other materials provided with the distribution.
  47. * 3. Neither the name of the University nor the names of its contributors
  48. * may be used to endorse or promote products derived from this software
  49. * without specific prior written permission.
  50. *
  51. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  52. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  53. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  54. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  55. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  56. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  57. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  58. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  59. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  60. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  61. * SUCH DAMAGE.
  62. */
  63. /*
  64. * Copyright (C) 1997 and 1998 WIDE Project.
  65. * All rights reserved.
  66. *
  67. * Redistribution and use in source and binary forms, with or without
  68. * modification, are permitted provided that the following conditions
  69. * are met:
  70. * 1. Redistributions of source code must retain the above copyright
  71. * notice, this list of conditions and the following disclaimer.
  72. * 2. Redistributions in binary form must reproduce the above copyright
  73. * notice, this list of conditions and the following disclaimer in the
  74. * documentation and/or other materials provided with the distribution.
  75. * 3. Neither the name of the project nor the names of its contributors
  76. * may be used to endorse or promote products derived from this software
  77. * without specific prior written permission.
  78. *
  79. * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  80. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  81. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  82. * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  83. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  84. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  85. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  86. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  87. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  88. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  89. * SUCH DAMAGE.
  90. */
  91. #include "tnftp.h"
  92. #if 0 /* tnftp */
  93. #include <sys/cdefs.h>
  94. #ifndef lint
  95. #if 0
  96. static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
  97. #else
  98. __RCSID(" NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp ");
  99. #endif
  100. #endif /* not lint */
  101. /*
  102. * FTP User Program -- Command Routines.
  103. */
  104. #include <sys/types.h>
  105. #include <sys/socket.h>
  106. #include <sys/stat.h>
  107. #include <sys/wait.h>
  108. #include <arpa/ftp.h>
  109. #include <ctype.h>
  110. #include <err.h>
  111. #include <glob.h>
  112. #include <limits.h>
  113. #include <netdb.h>
  114. #include <paths.h>
  115. #include <stddef.h>
  116. #include <stdio.h>
  117. #include <stdlib.h>
  118. #include <string.h>
  119. #include <time.h>
  120. #include <unistd.h>
  121. #endif /* tnftp */
  122. #include "ftp_var.h"
  123. #include "version.h"
  124. static struct types {
  125. const char *t_name;
  126. const char *t_mode;
  127. int t_type;
  128. const char *t_arg;
  129. } types[] = {
  130. { "ascii", "A", TYPE_A, 0 },
  131. { "binary", "I", TYPE_I, 0 },
  132. { "image", "I", TYPE_I, 0 },
  133. { "ebcdic", "E", TYPE_E, 0 },
  134. { "tenex", "L", TYPE_L, bytename },
  135. { NULL, NULL, 0, NULL }
  136. };
  137. static sigjmp_buf jabort;
  138. static int confirm(const char *, const char *);
  139. static void mintr(int);
  140. static void mabort(const char *);
  141. static void set_type(const char *);
  142. static const char *doprocess(char *, size_t, const char *, int, int, int);
  143. static const char *domap(char *, size_t, const char *);
  144. static const char *docase(char *, size_t, const char *);
  145. static const char *dotrans(char *, size_t, const char *);
  146. /*
  147. * Confirm if "cmd" is to be performed upon "file".
  148. * If "file" is NULL, generate a "Continue with" prompt instead.
  149. */
  150. static int
  151. confirm(const char *cmd, const char *file)
  152. {
  153. const char *errormsg;
  154. char cline[BUFSIZ];
  155. const char *promptleft, *promptright;
  156. if (!interactive || confirmrest)
  157. return (1);
  158. if (file == NULL) {
  159. promptleft = "Continue with";
  160. promptright = cmd;
  161. } else {
  162. promptleft = cmd;
  163. promptright = file;
  164. }
  165. while (1) {
  166. fprintf(ttyout, "%s %s [anpqy?]? ", promptleft, promptright);
  167. (void)fflush(ttyout);
  168. if (get_line(stdin, cline, sizeof(cline), &errormsg) < 0) {
  169. mflag = 0;
  170. fprintf(ttyout, "%s; %s aborted\n", errormsg, cmd);
  171. return (0);
  172. }
  173. switch (tolower((unsigned char)*cline)) {
  174. case 'a':
  175. confirmrest = 1;
  176. fprintf(ttyout,
  177. "Prompting off for duration of %s.\n", cmd);
  178. break;
  179. case 'p':
  180. interactive = 0;
  181. fputs("Interactive mode: off.\n", ttyout);
  182. break;
  183. case 'q':
  184. mflag = 0;
  185. fprintf(ttyout, "%s aborted.\n", cmd);
  186. /* FALLTHROUGH */
  187. case 'n':
  188. return (0);
  189. case '?':
  190. fprintf(ttyout,
  191. " confirmation options:\n"
  192. "\ta answer `yes' for the duration of %s\n"
  193. "\tn answer `no' for this file\n"
  194. "\tp turn off `prompt' mode\n"
  195. "\tq stop the current %s\n"
  196. "\ty answer `yes' for this file\n"
  197. "\t? this help list\n",
  198. cmd, cmd);
  199. continue; /* back to while(1) */
  200. }
  201. return (1);
  202. }
  203. /* NOTREACHED */
  204. }
  205. /*
  206. * Set transfer type.
  207. */
  208. void
  209. settype(int argc, char *argv[])
  210. {
  211. struct types *p;
  212. if (argc == 0 || argc > 2) {
  213. const char *sep;
  214. UPRINTF("usage: %s [", argv[0]);
  215. sep = " ";
  216. for (p = types; p->t_name; p++) {
  217. fprintf(ttyout, "%s%s", sep, p->t_name);
  218. sep = " | ";
  219. }
  220. fputs(" ]\n", ttyout);
  221. code = -1;
  222. return;
  223. }
  224. if (argc < 2) {
  225. fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
  226. code = 0;
  227. return;
  228. }
  229. set_type(argv[1]);
  230. }
  231. void
  232. set_type(const char *ttype)
  233. {
  234. struct types *p;
  235. int comret;
  236. for (p = types; p->t_name; p++)
  237. if (strcmp(ttype, p->t_name) == 0)
  238. break;
  239. if (p->t_name == 0) {
  240. fprintf(ttyout, "%s: unknown mode.\n", ttype);
  241. code = -1;
  242. return;
  243. }
  244. if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
  245. comret = command("TYPE %s %s", p->t_mode, p->t_arg);
  246. else
  247. comret = command("TYPE %s", p->t_mode);
  248. if (comret == COMPLETE) {
  249. (void)strlcpy(typename, p->t_name, sizeof(typename));
  250. curtype = type = p->t_type;
  251. }
  252. }
  253. /*
  254. * Internal form of settype; changes current type in use with server
  255. * without changing our notion of the type for data transfers.
  256. * Used to change to and from ascii for listings.
  257. */
  258. void
  259. changetype(int newtype, int show)
  260. {
  261. struct types *p;
  262. int comret, oldverbose = verbose;
  263. if (newtype == 0)
  264. newtype = TYPE_I;
  265. if (newtype == curtype)
  266. return;
  267. if (ftp_debug == 0 && show == 0)
  268. verbose = 0;
  269. for (p = types; p->t_name; p++)
  270. if (newtype == p->t_type)
  271. break;
  272. if (p->t_name == 0) {
  273. errx(1, "changetype: unknown type %d", newtype);
  274. }
  275. if (newtype == TYPE_L && bytename[0] != '\0')
  276. comret = command("TYPE %s %s", p->t_mode, bytename);
  277. else
  278. comret = command("TYPE %s", p->t_mode);
  279. if (comret == COMPLETE)
  280. curtype = newtype;
  281. verbose = oldverbose;
  282. }
  283. /*
  284. * Set binary transfer type.
  285. */
  286. /*VARARGS*/
  287. void
  288. setbinary(int argc, char *argv[])
  289. {
  290. if (argc == 0) {
  291. UPRINTF("usage: %s\n", argv[0]);
  292. code = -1;
  293. return;
  294. }
  295. set_type("binary");
  296. }
  297. /*
  298. * Set ascii transfer type.
  299. */
  300. /*VARARGS*/
  301. void
  302. setascii(int argc, char *argv[])
  303. {
  304. if (argc == 0) {
  305. UPRINTF("usage: %s\n", argv[0]);
  306. code = -1;
  307. return;
  308. }
  309. set_type("ascii");
  310. }
  311. /*
  312. * Set tenex transfer type.
  313. */
  314. /*VARARGS*/
  315. void
  316. settenex(int argc, char *argv[])
  317. {
  318. if (argc == 0) {
  319. UPRINTF("usage: %s\n", argv[0]);
  320. code = -1;
  321. return;
  322. }
  323. set_type("tenex");
  324. }
  325. /*
  326. * Set file transfer mode.
  327. */
  328. /*ARGSUSED*/
  329. void
  330. setftmode(int argc, char *argv[])
  331. {
  332. if (argc != 2) {
  333. UPRINTF("usage: %s mode-name\n", argv[0]);
  334. code = -1;
  335. return;
  336. }
  337. fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
  338. code = -1;
  339. }
  340. /*
  341. * Set file transfer format.
  342. */
  343. /*ARGSUSED*/
  344. void
  345. setform(int argc, char *argv[])
  346. {
  347. if (argc != 2) {
  348. UPRINTF("usage: %s format\n", argv[0]);
  349. code = -1;
  350. return;
  351. }
  352. fprintf(ttyout, "We only support %s format, sorry.\n", formname);
  353. code = -1;
  354. }
  355. /*
  356. * Set file transfer structure.
  357. */
  358. /*ARGSUSED*/
  359. void
  360. setstruct(int argc, char *argv[])
  361. {
  362. if (argc != 2) {
  363. UPRINTF("usage: %s struct-mode\n", argv[0]);
  364. code = -1;
  365. return;
  366. }
  367. fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
  368. code = -1;
  369. }
  370. /*
  371. * Send a single file.
  372. */
  373. void
  374. put(int argc, char *argv[])
  375. {
  376. char buf[MAXPATHLEN];
  377. const char *cmd;
  378. int loc = 0;
  379. char *locfile;
  380. const char *remfile;
  381. if (argc == 2) {
  382. argc++;
  383. argv[2] = argv[1];
  384. loc++;
  385. }
  386. if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file")))
  387. goto usage;
  388. if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
  389. usage:
  390. UPRINTF("usage: %s local-file [remote-file]\n", argv[0]);
  391. code = -1;
  392. return;
  393. }
  394. if ((locfile = globulize(argv[1])) == NULL) {
  395. code = -1;
  396. return;
  397. }
  398. remfile = argv[2];
  399. if (loc) /* If argv[2] is a copy of the old argv[1], update it */
  400. remfile = locfile;
  401. cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
  402. remfile = doprocess(buf, sizeof(buf), remfile,
  403. 0, loc && ntflag, loc && mapflag);
  404. sendrequest(cmd, locfile, remfile,
  405. locfile != argv[1] || remfile != argv[2]);
  406. free(locfile);
  407. }
  408. static const char *
  409. doprocess(char *dst, size_t dlen, const char *src,
  410. int casef, int transf, int mapf)
  411. {
  412. if (casef)
  413. src = docase(dst, dlen, src);
  414. if (transf)
  415. src = dotrans(dst, dlen, src);
  416. if (mapf)
  417. src = domap(dst, dlen, src);
  418. return src;
  419. }
  420. /*
  421. * Send multiple files.
  422. */
  423. void
  424. mput(int argc, char *argv[])
  425. {
  426. int i;
  427. sigfunc oldintr;
  428. int ointer;
  429. const char *tp;
  430. if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) {
  431. UPRINTF("usage: %s local-files\n", argv[0]);
  432. code = -1;
  433. return;
  434. }
  435. mflag = 1;
  436. oldintr = xsignal(SIGINT, mintr);
  437. if (sigsetjmp(jabort, 1))
  438. mabort(argv[0]);
  439. if (proxy) {
  440. char *cp;
  441. while ((cp = remglob(argv, 0, NULL)) != NULL) {
  442. if (*cp == '\0' || !connected) {
  443. mflag = 0;
  444. continue;
  445. }
  446. if (mflag && confirm(argv[0], cp)) {
  447. char buf[MAXPATHLEN];
  448. tp = doprocess(buf, sizeof(buf), cp,
  449. mcase, ntflag, mapflag);
  450. sendrequest((sunique) ? "STOU" : "STOR",
  451. cp, tp, cp != tp || !interactive);
  452. if (!mflag && fromatty) {
  453. ointer = interactive;
  454. interactive = 1;
  455. if (confirm(argv[0], NULL)) {
  456. mflag++;
  457. }
  458. interactive = ointer;
  459. }
  460. }
  461. }
  462. goto cleanupmput;
  463. }
  464. for (i = 1; i < argc && connected; i++) {
  465. char **cpp;
  466. glob_t gl;
  467. int flags;
  468. if (!doglob) {
  469. if (mflag && confirm(argv[0], argv[i])) {
  470. char buf[MAXPATHLEN];
  471. tp = doprocess(buf, sizeof(buf), argv[i],
  472. 0, ntflag, mapflag);
  473. sendrequest((sunique) ? "STOU" : "STOR",
  474. argv[i], tp, tp != argv[i] || !interactive);
  475. if (!mflag && fromatty) {
  476. ointer = interactive;
  477. interactive = 1;
  478. if (confirm(argv[0], NULL)) {
  479. mflag++;
  480. }
  481. interactive = ointer;
  482. }
  483. }
  484. continue;
  485. }
  486. memset(&gl, 0, sizeof(gl));
  487. flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
  488. if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
  489. warnx("Glob pattern `%s' not found", argv[i]);
  490. globfree(&gl);
  491. continue;
  492. }
  493. for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected;
  494. cpp++) {
  495. if (mflag && confirm(argv[0], *cpp)) {
  496. char buf[MAXPATHLEN];
  497. tp = *cpp;
  498. tp = doprocess(buf, sizeof(buf), *cpp,
  499. 0, ntflag, mapflag);
  500. sendrequest((sunique) ? "STOU" : "STOR",
  501. *cpp, tp, *cpp != tp || !interactive);
  502. if (!mflag && fromatty) {
  503. ointer = interactive;
  504. interactive = 1;
  505. if (confirm(argv[0], NULL)) {
  506. mflag++;
  507. }
  508. interactive = ointer;
  509. }
  510. }
  511. }
  512. globfree(&gl);
  513. }
  514. cleanupmput:
  515. (void)xsignal(SIGINT, oldintr);
  516. mflag = 0;
  517. }
  518. void
  519. reget(int argc, char *argv[])
  520. {
  521. (void)getit(argc, argv, 1, "r+");
  522. }
  523. void
  524. get(int argc, char *argv[])
  525. {
  526. (void)getit(argc, argv, 0, restart_point ? "r+" : "w" );
  527. }
  528. /*
  529. * Receive one file.
  530. * If restartit is 1, restart the xfer always.
  531. * If restartit is -1, restart the xfer only if the remote file is newer.
  532. */
  533. int
  534. getit(int argc, char *argv[], int restartit, const char *gmode)
  535. {
  536. int loc, rval;
  537. char *remfile, *olocfile;
  538. const char *locfile;
  539. char buf[MAXPATHLEN];
  540. loc = rval = 0;
  541. if (argc == 2) {
  542. argc++;
  543. argv[2] = argv[1];
  544. loc++;
  545. }
  546. if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file")))
  547. goto usage;
  548. if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
  549. usage:
  550. UPRINTF("usage: %s remote-file [local-file]\n", argv[0]);
  551. code = -1;
  552. return (0);
  553. }
  554. remfile = argv[1];
  555. if ((olocfile = globulize(argv[2])) == NULL) {
  556. code = -1;
  557. return (0);
  558. }
  559. locfile = doprocess(buf, sizeof(buf), olocfile,
  560. loc && mcase, loc && ntflag, loc && mapflag);
  561. if (restartit) {
  562. struct stat stbuf;
  563. int ret;
  564. if (! features[FEAT_REST_STREAM]) {
  565. fprintf(ttyout,
  566. "Restart is not supported by the remote server.\n");
  567. return (0);
  568. }
  569. ret = stat(locfile, &stbuf);
  570. if (restartit == 1) {
  571. if (ret < 0) {
  572. warn("Can't stat `%s'", locfile);
  573. goto freegetit;
  574. }
  575. restart_point = stbuf.st_size;
  576. } else {
  577. if (ret == 0) {
  578. time_t mtime;
  579. mtime = remotemodtime(argv[1], 0);
  580. if (mtime == -1)
  581. goto freegetit;
  582. if (stbuf.st_mtime >= mtime) {
  583. rval = 1;
  584. goto freegetit;
  585. }
  586. }
  587. }
  588. }
  589. recvrequest("RETR", locfile, remfile, gmode,
  590. remfile != argv[1] || locfile != argv[2], loc);
  591. restart_point = 0;
  592. freegetit:
  593. (void)free(olocfile);
  594. return (rval);
  595. }
  596. /* ARGSUSED */
  597. static void
  598. mintr(int signo)
  599. {
  600. alarmtimer(0);
  601. if (fromatty)
  602. write(fileno(ttyout), "\n", 1);
  603. siglongjmp(jabort, 1);
  604. }
  605. static void
  606. mabort(const char *cmd)
  607. {
  608. int ointer, oconf;
  609. if (mflag && fromatty) {
  610. ointer = interactive;
  611. oconf = confirmrest;
  612. interactive = 1;
  613. confirmrest = 0;
  614. if (confirm(cmd, NULL)) {
  615. interactive = ointer;
  616. confirmrest = oconf;
  617. return;
  618. }
  619. interactive = ointer;
  620. confirmrest = oconf;
  621. }
  622. mflag = 0;
  623. }
  624. /*
  625. * Get multiple files.
  626. */
  627. void
  628. mget(int argc, char *argv[])
  629. {
  630. sigfunc oldintr;
  631. int ointer;
  632. char *cp;
  633. const char *tp;
  634. int volatile restartit;
  635. if (argc == 0 ||
  636. (argc == 1 && !another(&argc, &argv, "remote-files"))) {
  637. UPRINTF("usage: %s remote-files\n", argv[0]);
  638. code = -1;
  639. return;
  640. }
  641. mflag = 1;
  642. restart_point = 0;
  643. restartit = 0;
  644. if (strcmp(argv[0], "mreget") == 0) {
  645. if (! features[FEAT_REST_STREAM]) {
  646. fprintf(ttyout,
  647. "Restart is not supported by the remote server.\n");
  648. return;
  649. }
  650. restartit = 1;
  651. }
  652. oldintr = xsignal(SIGINT, mintr);
  653. if (sigsetjmp(jabort, 1))
  654. mabort(argv[0]);
  655. while ((cp = remglob(argv, proxy, NULL)) != NULL) {
  656. char buf[MAXPATHLEN];
  657. if (*cp == '\0' || !connected) {
  658. mflag = 0;
  659. continue;
  660. }
  661. if (! mflag)
  662. continue;
  663. if (! fileindir(cp, localcwd)) {
  664. fprintf(ttyout, "Skipping non-relative filename `%s'\n",
  665. cp);
  666. continue;
  667. }
  668. if (!confirm(argv[0], cp))
  669. continue;
  670. tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag);
  671. if (restartit) {
  672. struct stat stbuf;
  673. if (stat(tp, &stbuf) == 0)
  674. restart_point = stbuf.st_size;
  675. else
  676. warn("Can't stat `%s'", tp);
  677. }
  678. recvrequest("RETR", tp, cp, restart_point ? "r+" : "w",
  679. tp != cp || !interactive, 1);
  680. restart_point = 0;
  681. if (!mflag && fromatty) {
  682. ointer = interactive;
  683. interactive = 1;
  684. if (confirm(argv[0], NULL))
  685. mflag++;
  686. interactive = ointer;
  687. }
  688. }
  689. (void)xsignal(SIGINT, oldintr);
  690. mflag = 0;
  691. }
  692. /*
  693. * Read list of filenames from a local file and get those
  694. */
  695. void
  696. fget(int argc, char *argv[])
  697. {
  698. const char *gmode;
  699. FILE *fp;
  700. char buf[MAXPATHLEN], cmdbuf[MAX_C_NAME];
  701. if (argc != 2) {
  702. UPRINTF("usage: %s localfile\n", argv[0]);
  703. code = -1;
  704. return;
  705. }
  706. fp = fopen(argv[1], "r");
  707. if (fp == NULL) {
  708. fprintf(ttyout, "Can't open source file %s\n", argv[1]);
  709. code = -1;
  710. return;
  711. }
  712. (void)strlcpy(cmdbuf, "get", sizeof(cmdbuf));
  713. argv[0] = cmdbuf;
  714. gmode = restart_point ? "r+" : "w";
  715. while (get_line(fp, buf, sizeof(buf), NULL) >= 0) {
  716. if (buf[0] == '\0')
  717. continue;
  718. argv[1] = buf;
  719. (void)getit(argc, argv, 0, gmode);
  720. }
  721. fclose(fp);
  722. }
  723. const char *
  724. onoff(int val)
  725. {
  726. return (val ? "on" : "off");
  727. }
  728. /*
  729. * Show status.
  730. */
  731. /*ARGSUSED*/
  732. void
  733. status(int argc, char *argv[])
  734. {
  735. if (argc == 0) {
  736. UPRINTF("usage: %s\n", argv[0]);
  737. code = -1;
  738. return;
  739. }
  740. #ifndef NO_STATUS
  741. if (connected)
  742. fprintf(ttyout, "Connected %sto %s.\n",
  743. connected == -1 ? "and logged in" : "", hostname);
  744. else
  745. fputs("Not connected.\n", ttyout);
  746. if (!proxy) {
  747. pswitch(1);
  748. if (connected) {
  749. fprintf(ttyout, "Connected for proxy commands to %s.\n",
  750. hostname);
  751. }
  752. else {
  753. fputs("No proxy connection.\n", ttyout);
  754. }
  755. pswitch(0);
  756. }
  757. fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
  758. *gateserver ? gateserver : "(none)", gateport);
  759. fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
  760. onoff(passivemode), onoff(activefallback));
  761. fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
  762. modename, typename, formname, structname);
  763. fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
  764. onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob));
  765. fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n",
  766. onoff(sunique), onoff(runique));
  767. fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
  768. fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase),
  769. onoff(crflag));
  770. if (ntflag) {
  771. fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
  772. }
  773. else {
  774. fputs("Ntrans: off.\n", ttyout);
  775. }
  776. if (mapflag) {
  777. fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
  778. }
  779. else {
  780. fputs("Nmap: off.\n", ttyout);
  781. }
  782. fprintf(ttyout,
  783. "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
  784. onoff(hash), mark, onoff(progress));
  785. fprintf(ttyout,
  786. "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
  787. onoff(rate_get), rate_get, rate_get_incr);
  788. fprintf(ttyout,
  789. "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
  790. onoff(rate_put), rate_put, rate_put_incr);
  791. fprintf(ttyout,
  792. "Socket buffer sizes: send %d, receive %d.\n",
  793. sndbuf_size, rcvbuf_size);
  794. fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport));
  795. fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
  796. epsv4bad ? " (disabled for this connection)" : "");
  797. fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv6: %s%s.\n", onoff(epsv6),
  798. epsv6bad ? " (disabled for this connection)" : "");
  799. fprintf(ttyout, "Command line editing: %s.\n",
  800. #ifdef NO_EDITCOMPLETE
  801. "support not compiled in"
  802. #else /* !def NO_EDITCOMPLETE */
  803. onoff(editing)
  804. #endif /* !def NO_EDITCOMPLETE */
  805. );
  806. if (macnum > 0) {
  807. int i;
  808. fputs("Macros:\n", ttyout);
  809. for (i=0; i<macnum; i++) {
  810. fprintf(ttyout, "\t%s\n", macros[i].mac_name);
  811. }
  812. }
  813. #endif /* !def NO_STATUS */
  814. fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION);
  815. code = 0;
  816. }
  817. /*
  818. * Toggle a variable
  819. */
  820. int
  821. togglevar(int argc, char *argv[], int *var, const char *mesg)
  822. {
  823. if (argc == 1) {
  824. *var = !*var;
  825. } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
  826. *var = 1;
  827. } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
  828. *var = 0;
  829. } else {
  830. UPRINTF("usage: %s [ on | off ]\n", argv[0]);
  831. return (-1);
  832. }
  833. if (mesg)
  834. fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
  835. return (*var);
  836. }
  837. /*
  838. * Set beep on cmd completed mode.
  839. */
  840. /*VARARGS*/
  841. void
  842. setbell(int argc, char *argv[])
  843. {
  844. code = togglevar(argc, argv, &bell, "Bell mode");
  845. }
  846. /*
  847. * Set command line editing
  848. */
  849. /*VARARGS*/
  850. void
  851. setedit(int argc, char *argv[])
  852. {
  853. #ifdef NO_EDITCOMPLETE
  854. if (argc == 0) {
  855. UPRINTF("usage: %s\n", argv[0]);
  856. code = -1;
  857. return;
  858. }
  859. if (verbose)
  860. fputs("Editing support not compiled in; ignoring command.\n",
  861. ttyout);
  862. #else /* !def NO_EDITCOMPLETE */
  863. code = togglevar(argc, argv, &editing, "Editing mode");
  864. controlediting();
  865. #endif /* !def NO_EDITCOMPLETE */
  866. }
  867. /*
  868. * Turn on packet tracing.
  869. */
  870. /*VARARGS*/
  871. void
  872. settrace(int argc, char *argv[])
  873. {
  874. code = togglevar(argc, argv, &trace, "Packet tracing");
  875. }
  876. /*
  877. * Toggle hash mark printing during transfers, or set hash mark bytecount.
  878. */
  879. /*VARARGS*/
  880. void
  881. sethash(int argc, char *argv[])
  882. {
  883. if (argc == 1)
  884. hash = !hash;
  885. else if (argc != 2) {
  886. UPRINTF("usage: %s [ on | off | bytecount ]\n",
  887. argv[0]);
  888. code = -1;
  889. return;
  890. } else if (strcasecmp(argv[1], "on") == 0)
  891. hash = 1;
  892. else if (strcasecmp(argv[1], "off") == 0)
  893. hash = 0;
  894. else {
  895. int nmark;
  896. nmark = strsuftoi(argv[1]);
  897. if (nmark < 1) {
  898. fprintf(ttyout, "mark: bad bytecount value `%s'.\n",
  899. argv[1]);
  900. code = -1;
  901. return;
  902. }
  903. mark = nmark;
  904. hash = 1;
  905. }
  906. fprintf(ttyout, "Hash mark printing %s", onoff(hash));
  907. if (hash)
  908. fprintf(ttyout, " (%d bytes/hash mark)", mark);
  909. fputs(".\n", ttyout);
  910. if (hash)
  911. progress = 0;
  912. code = hash;
  913. }
  914. /*
  915. * Turn on printing of server echo's.
  916. */
  917. /*VARARGS*/
  918. void
  919. setverbose(int argc, char *argv[])
  920. {
  921. code = togglevar(argc, argv, &verbose, "Verbose mode");
  922. }
  923. /*
  924. * Toggle PORT/LPRT cmd use before each data connection.
  925. */
  926. /*VARARGS*/
  927. void
  928. setport(int argc, char *argv[])
  929. {
  930. code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
  931. }
  932. /*
  933. * Toggle transfer progress bar.
  934. */
  935. /*VARARGS*/
  936. void
  937. setprogress(int argc, char *argv[])
  938. {
  939. code = togglevar(argc, argv, &progress, "Progress bar");
  940. if (progress)
  941. hash = 0;
  942. }
  943. /*
  944. * Turn on interactive prompting during mget, mput, and mdelete.
  945. */
  946. /*VARARGS*/
  947. void
  948. setprompt(int argc, char *argv[])
  949. {
  950. code = togglevar(argc, argv, &interactive, "Interactive mode");
  951. }
  952. /*
  953. * Toggle gate-ftp mode, or set gate-ftp server
  954. */
  955. /*VARARGS*/
  956. void
  957. setgate(int argc, char *argv[])
  958. {
  959. static char gsbuf[MAXHOSTNAMELEN];
  960. if (argc == 0 || argc > 3) {
  961. UPRINTF(
  962. "usage: %s [ on | off | gateserver [port] ]\n", argv[0]);
  963. code = -1;
  964. return;
  965. } else if (argc < 2) {
  966. gatemode = !gatemode;
  967. } else {
  968. if (argc == 2 && strcasecmp(argv[1], "on") == 0)
  969. gatemode = 1;
  970. else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
  971. gatemode = 0;
  972. else {
  973. if (argc == 3)
  974. gateport = ftp_strdup(argv[2]);
  975. (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf));
  976. gateserver = gsbuf;
  977. gatemode = 1;
  978. }
  979. }
  980. if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
  981. fprintf(ttyout,
  982. "Disabling gate-ftp mode - no gate-ftp server defined.\n");
  983. gatemode = 0;
  984. } else {
  985. fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
  986. onoff(gatemode), *gateserver ? gateserver : "(none)",
  987. gateport);
  988. }
  989. code = gatemode;
  990. }
  991. /*
  992. * Toggle metacharacter interpretation on local file names.
  993. */
  994. /*VARARGS*/
  995. void
  996. setglob(int argc, char *argv[])
  997. {
  998. code = togglevar(argc, argv, &doglob, "Globbing");
  999. }
  1000. /*
  1001. * Toggle preserving modification times on retrieved files.
  1002. */
  1003. /*VARARGS*/
  1004. void
  1005. setpreserve(int argc, char *argv[])
  1006. {
  1007. code = togglevar(argc, argv, &preserve, "Preserve modification times");
  1008. }
  1009. /*
  1010. * Set debugging mode on/off and/or set level of debugging.
  1011. */
  1012. /*VARARGS*/
  1013. void
  1014. setdebug(int argc, char *argv[])
  1015. {
  1016. if (argc == 0 || argc > 2) {
  1017. UPRINTF("usage: %s [ on | off | debuglevel ]\n", argv[0]);
  1018. code = -1;
  1019. return;
  1020. } else if (argc == 2) {
  1021. if (strcasecmp(argv[1], "on") == 0)
  1022. ftp_debug = 1;
  1023. else if (strcasecmp(argv[1], "off") == 0)
  1024. ftp_debug = 0;
  1025. else {
  1026. int val;
  1027. val = strsuftoi(argv[1]);
  1028. if (val < 0) {
  1029. fprintf(ttyout, "%s: bad debugging value.\n",
  1030. argv[1]);
  1031. code = -1;
  1032. return;
  1033. }
  1034. ftp_debug = val;
  1035. }
  1036. } else
  1037. ftp_debug = !ftp_debug;
  1038. if (ftp_debug)
  1039. options |= SO_DEBUG;
  1040. else
  1041. options &= ~SO_DEBUG;
  1042. fprintf(ttyout, "Debugging %s (ftp_debug=%d).\n", onoff(ftp_debug), ftp_debug);
  1043. code = ftp_debug > 0;
  1044. }
  1045. /*
  1046. * Set current working directory on remote machine.
  1047. */
  1048. void
  1049. cd(int argc, char *argv[])
  1050. {
  1051. int r;
  1052. if (argc == 0 || argc > 2 ||
  1053. (argc == 1 && !another(&argc, &argv, "remote-directory"))) {
  1054. UPRINTF("usage: %s remote-directory\n", argv[0]);
  1055. code = -1;
  1056. return;
  1057. }
  1058. r = command("CWD %s", argv[1]);
  1059. if (r == ERROR && code == 500) {
  1060. if (verbose)
  1061. fputs("CWD command not recognized, trying XCWD.\n",
  1062. ttyout);
  1063. r = command("XCWD %s", argv[1]);
  1064. }
  1065. if (r == COMPLETE) {
  1066. dirchange = 1;
  1067. updateremotecwd();
  1068. }
  1069. }
  1070. /*
  1071. * Set current working directory on local machine.
  1072. */
  1073. void
  1074. lcd(int argc, char *argv[])
  1075. {
  1076. char *locdir;
  1077. code = -1;
  1078. if (argc == 1) {
  1079. argc++;
  1080. argv[1] = localhome;
  1081. }
  1082. if (argc != 2) {
  1083. UPRINTF("usage: %s [local-directory]\n", argv[0]);
  1084. return;
  1085. }
  1086. if ((locdir = globulize(argv[1])) == NULL)
  1087. return;
  1088. if (chdir(locdir) == -1)
  1089. warn("Can't chdir `%s'", locdir);
  1090. else {
  1091. updatelocalcwd();
  1092. if (localcwd[0]) {
  1093. fprintf(ttyout, "Local directory now: %s\n", localcwd);
  1094. code = 0;
  1095. } else {
  1096. fprintf(ttyout, "Unable to determine local directory\n");
  1097. }
  1098. }
  1099. (void)free(locdir);
  1100. }
  1101. /*
  1102. * Delete a single file.
  1103. */
  1104. void
  1105. delete(int argc, char *argv[])
  1106. {
  1107. if (argc == 0 || argc > 2 ||
  1108. (argc == 1 && !another(&argc, &argv, "remote-file"))) {
  1109. UPRINTF("usage: %s remote-file\n", argv[0]);
  1110. code = -1;
  1111. return;
  1112. }
  1113. if (command("DELE %s", argv[1]) == COMPLETE)
  1114. dirchange = 1;
  1115. }
  1116. /*
  1117. * Delete multiple files.
  1118. */
  1119. void
  1120. mdelete(int argc, char *argv[])
  1121. {
  1122. sigfunc oldintr;
  1123. int ointer;
  1124. char *cp;
  1125. if (argc == 0 ||
  1126. (argc == 1 && !another(&argc, &argv, "remote-files"))) {
  1127. UPRINTF("usage: %s [remote-files]\n", argv[0]);
  1128. code = -1;
  1129. return;
  1130. }
  1131. mflag = 1;
  1132. oldintr = xsignal(SIGINT, mintr);
  1133. if (sigsetjmp(jabort, 1))
  1134. mabort(argv[0]);
  1135. while ((cp = remglob(argv, 0, NULL)) != NULL) {
  1136. if (*cp == '\0') {
  1137. mflag = 0;
  1138. continue;
  1139. }
  1140. if (mflag && confirm(argv[0], cp)) {
  1141. if (command("DELE %s", cp) == COMPLETE)
  1142. dirchange = 1;
  1143. if (!mflag && fromatty) {
  1144. ointer = interactive;
  1145. interactive = 1;
  1146. if (confirm(argv[0], NULL)) {
  1147. mflag++;
  1148. }
  1149. interactive = ointer;
  1150. }
  1151. }
  1152. }
  1153. (void)xsignal(SIGINT, oldintr);
  1154. mflag = 0;
  1155. }
  1156. /*
  1157. * Rename a remote file.
  1158. */
  1159. void
  1160. renamefile(int argc, char *argv[])
  1161. {
  1162. if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name")))
  1163. goto usage;
  1164. if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
  1165. usage:
  1166. UPRINTF("usage: %s from-name to-name\n", argv[0]);
  1167. code = -1;
  1168. return;
  1169. }
  1170. if (command("RNFR %s", argv[1]) == CONTINUE &&
  1171. command("RNTO %s", argv[2]) == COMPLETE)
  1172. dirchange = 1;
  1173. }
  1174. /*
  1175. * Get a directory listing of remote files.
  1176. * Supports being invoked as:
  1177. * cmd runs
  1178. * --- ----
  1179. * dir, ls LIST
  1180. * mlsd MLSD
  1181. * nlist NLST
  1182. * pdir, pls LIST |$PAGER
  1183. * pmlsd MLSD |$PAGER
  1184. */
  1185. void
  1186. ls(int argc, char *argv[])
  1187. {
  1188. const char *cmd;
  1189. char *remdir, *locbuf;
  1190. const char *locfile;
  1191. int pagecmd, mlsdcmd;
  1192. remdir = NULL;
  1193. locbuf = NULL;
  1194. locfile = "-";
  1195. pagecmd = mlsdcmd = 0;
  1196. /*
  1197. * the only commands that start with `p' are
  1198. * the `pager' versions.
  1199. */
  1200. if (argv[0][0] == 'p')
  1201. pagecmd = 1;
  1202. if (strcmp(argv[0] + pagecmd , "mlsd") == 0) {
  1203. if (! features[FEAT_MLST]) {
  1204. fprintf(ttyout,
  1205. "MLSD is not supported by the remote server.\n");
  1206. return;
  1207. }
  1208. mlsdcmd = 1;
  1209. }
  1210. if (argc == 0)
  1211. goto usage;
  1212. if (mlsdcmd)
  1213. cmd = "MLSD";
  1214. else if (strcmp(argv[0] + pagecmd, "nlist") == 0)
  1215. cmd = "NLST";
  1216. else
  1217. cmd = "LIST";
  1218. if (argc > 1)
  1219. remdir = argv[1];
  1220. if (argc > 2)
  1221. locfile = argv[2];
  1222. if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) {
  1223. usage:
  1224. if (pagecmd || mlsdcmd)
  1225. UPRINTF("usage: %s [remote-path]\n", argv[0]);
  1226. else
  1227. UPRINTF("usage: %s [remote-path [local-file]]\n",
  1228. argv[0]);
  1229. code = -1;
  1230. goto freels;
  1231. }
  1232. if (pagecmd) {
  1233. const char *p;
  1234. size_t len;
  1235. p = getoptionvalue("pager");
  1236. if (EMPTYSTRING(p))
  1237. p = DEFAULTPAGER;
  1238. len = strlen(p) + 2;
  1239. locbuf = ftp_malloc(len);
  1240. locbuf[0] = '|';
  1241. (void)strlcpy(locbuf + 1, p, len - 1);
  1242. locfile = locbuf;
  1243. } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') {
  1244. if ((locbuf = globulize(locfile)) == NULL ||
  1245. !confirm("output to local-file:", locbuf)) {
  1246. code = -1;
  1247. goto freels;
  1248. }
  1249. locfile = locbuf;
  1250. }
  1251. recvrequest(cmd, locfile, remdir, "w", 0, 0);
  1252. freels:
  1253. if (locbuf)
  1254. (void)free(locbuf);
  1255. }
  1256. /*
  1257. * Get a directory listing of multiple remote files.
  1258. */
  1259. void
  1260. mls(int argc, char *argv[])
  1261. {
  1262. sigfunc oldintr;
  1263. int ointer, i;
  1264. int volatile dolist;
  1265. char * volatile dest, *odest;
  1266. const char *lmode;
  1267. if (argc == 0)
  1268. goto usage;
  1269. if (argc < 2 && !another(&argc, &argv, "remote-files"))
  1270. goto usage;
  1271. if (argc < 3 && !another(&argc, &argv, "local-file")) {
  1272. usage:
  1273. UPRINTF("usage: %s remote-files local-file\n", argv[0]);
  1274. code = -1;
  1275. return;
  1276. }
  1277. odest = dest = argv[argc - 1];
  1278. argv[argc - 1] = NULL;
  1279. if (strcmp(dest, "-") && *dest != '|')
  1280. if (((dest = globulize(dest)) == NULL) ||
  1281. !confirm("output to local-file:", dest)) {
  1282. code = -1;
  1283. return;
  1284. }
  1285. dolist = strcmp(argv[0], "mls");
  1286. mflag = 1;
  1287. oldintr = xsignal(SIGINT, mintr);
  1288. if (sigsetjmp(jabort, 1))
  1289. mabort(argv[0]);
  1290. for (i = 1; mflag && i < argc-1 && connected; i++) {
  1291. lmode = (i == 1) ? "w" : "a";
  1292. recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], lmode,
  1293. 0, 0);
  1294. if (!mflag && fromatty) {
  1295. ointer = interactive;
  1296. interactive = 1;
  1297. if (confirm(argv[0], NULL)) {
  1298. mflag++;
  1299. }
  1300. interactive = ointer;
  1301. }
  1302. }
  1303. (void)xsignal(SIGINT, oldintr);
  1304. mflag = 0;
  1305. if (dest != odest) /* free up after globulize() */
  1306. free(dest);
  1307. }
  1308. /*
  1309. * Do a shell escape
  1310. */
  1311. /*ARGSUSED*/
  1312. void
  1313. shell(int argc, char *argv[])
  1314. {
  1315. pid_t pid;
  1316. sigfunc oldintr;
  1317. char shellnam[MAXPATHLEN];
  1318. const char *shellp, *namep;
  1319. int wait_status;
  1320. if (argc == 0) {
  1321. UPRINTF("usage: %s [command [args]]\n", argv[0]);
  1322. code = -1;
  1323. return;
  1324. }
  1325. oldintr = xsignal(SIGINT, SIG_IGN);
  1326. if ((pid = fork()) == 0) {
  1327. (void)closefrom(3);
  1328. (void)xsignal(SIGINT, SIG_DFL);
  1329. shellp = getenv("SHELL");
  1330. if (shellp == NULL)
  1331. shellp = _PATH_BSHELL;
  1332. namep = strrchr(shellp, '/');
  1333. if (namep == NULL)
  1334. namep = shellp;
  1335. else
  1336. namep++;
  1337. (void)strlcpy(shellnam, namep, sizeof(shellnam));
  1338. if (ftp_debug) {
  1339. fputs(shellp, ttyout);
  1340. putc('\n', ttyout);
  1341. }
  1342. if (argc > 1) {
  1343. execl(shellp, shellnam, "-c", altarg, (char *)0);
  1344. }
  1345. else {
  1346. execl(shellp, shellnam, (char *)0);
  1347. }
  1348. warn("Can't execute `%s'", shellp);
  1349. code = -1;
  1350. exit(1);
  1351. }
  1352. if (pid > 0)
  1353. while (wait(&wait_status) != pid)
  1354. ;
  1355. (void)xsignal(SIGINT, oldintr);
  1356. if (pid == -1) {
  1357. warn("Can't fork a subshell; try again later");
  1358. code = -1;
  1359. } else
  1360. code = 0;
  1361. }
  1362. /*
  1363. * Send new user information (re-login)
  1364. */
  1365. void
  1366. user(int argc, char *argv[])
  1367. {
  1368. char *password;
  1369. char emptypass[] = "";
  1370. int n, aflag = 0;
  1371. if (argc == 0)
  1372. goto usage;
  1373. if (argc < 2)
  1374. (void)another(&argc, &argv, "username");
  1375. if (argc < 2 || argc > 4) {
  1376. usage:
  1377. UPRINTF("usage: %s username [password [account]]\n",
  1378. argv[0]);
  1379. code = -1;
  1380. return;
  1381. }
  1382. n = command("USER %s", argv[1]);
  1383. if (n == CONTINUE) {
  1384. if (argc < 3) {
  1385. password = getpass("Password: ");
  1386. if (password == NULL)
  1387. password = emptypass;
  1388. } else {
  1389. password = argv[2];
  1390. }
  1391. n = command("PASS %s", password);
  1392. memset(password, 0, strlen(password));
  1393. }
  1394. if (n == CONTINUE) {
  1395. aflag++;
  1396. if (argc < 4) {
  1397. password = getpass("Account: ");
  1398. if (password == NULL)
  1399. password = emptypass;
  1400. } else {
  1401. password = argv[3];
  1402. }
  1403. n = command("ACCT %s", password);
  1404. memset(password, 0, strlen(password));
  1405. }
  1406. if (n != COMPLETE) {
  1407. fputs("Login failed.\n", ttyout);
  1408. return;
  1409. }
  1410. if (!aflag && argc == 4) {
  1411. password = argv[3];
  1412. (void)command("ACCT %s", password);
  1413. memset(password, 0, strlen(password));
  1414. }
  1415. connected = -1;
  1416. getremoteinfo();
  1417. }
  1418. /*
  1419. * Print working directory on remote machine.
  1420. */
  1421. /*VARARGS*/
  1422. void
  1423. pwd(int argc, char *argv[])
  1424. {
  1425. code = -1;
  1426. if (argc != 1) {
  1427. UPRINTF("usage: %s\n", argv[0]);
  1428. return;
  1429. }
  1430. if (! remotecwd[0])
  1431. updateremotecwd();
  1432. if (! remotecwd[0])
  1433. fprintf(ttyout, "Unable to determine remote directory\n");
  1434. else {
  1435. fprintf(ttyout, "Remote directory: %s\n", remotecwd);
  1436. code = 0;
  1437. }
  1438. }
  1439. /*
  1440. * Print working directory on local machine.
  1441. */
  1442. void
  1443. lpwd(int argc, char *argv[])
  1444. {
  1445. code = -1;
  1446. if (argc != 1) {
  1447. UPRINTF("usage: %s\n", argv[0]);
  1448. return;
  1449. }
  1450. if (! localcwd[0])
  1451. updatelocalcwd();
  1452. if (! localcwd[0])
  1453. fprintf(ttyout, "Unable to determine local directory\n");
  1454. else {
  1455. fprintf(ttyout, "Local directory: %s\n", localcwd);
  1456. code = 0;
  1457. }
  1458. }
  1459. /*
  1460. * Make a directory.
  1461. */
  1462. void
  1463. makedir(int argc, char *argv[])
  1464. {
  1465. int r;
  1466. if (argc == 0 || argc > 2 ||
  1467. (argc == 1 && !another(&argc, &argv, "directory-name"))) {
  1468. UPRINTF("usage: %s directory-name\n", argv[0]);
  1469. code = -1;
  1470. return;
  1471. }
  1472. r = command("MKD %s", argv[1]);
  1473. if (r == ERROR && code == 500) {
  1474. if (verbose)
  1475. fputs("MKD command not recognized, trying XMKD.\n",
  1476. ttyout);
  1477. r = command("XMKD %s", argv[1]);
  1478. }
  1479. if (r == COMPLETE)
  1480. dirchange = 1;
  1481. }
  1482. /*
  1483. * Remove a directory.
  1484. */
  1485. void
  1486. removedir(int argc, char *argv[])
  1487. {
  1488. int r;
  1489. if (argc == 0 || argc > 2 ||
  1490. (argc == 1 && !another(&argc, &argv, "directory-name"))) {
  1491. UPRINTF("usage: %s directory-name\n", argv[0]);
  1492. code = -1;
  1493. return;
  1494. }
  1495. r = command("RMD %s", argv[1]);
  1496. if (r == ERROR && code == 500) {
  1497. if (verbose)
  1498. fputs("RMD command not recognized, trying XRMD.\n",
  1499. ttyout);
  1500. r = command("XRMD %s", argv[1]);
  1501. }
  1502. if (r == COMPLETE)
  1503. dirchange = 1;
  1504. }
  1505. /*
  1506. * Send a line, verbatim, to the remote machine.
  1507. */
  1508. void
  1509. quote(int argc, char *argv[])
  1510. {
  1511. if (argc == 0 ||
  1512. (argc == 1 && !another(&argc, &argv, "command line to send"))) {
  1513. UPRINTF("usage: %s line-to-send\n", argv[0]);
  1514. code = -1;
  1515. return;
  1516. }
  1517. quote1("", argc, argv);
  1518. }
  1519. /*
  1520. * Send a SITE command to the remote machine. The line
  1521. * is sent verbatim to the remote machine, except that the
  1522. * word "SITE" is added at the front.
  1523. */
  1524. void
  1525. site(int argc, char *argv[])
  1526. {
  1527. if (argc == 0 ||
  1528. (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){
  1529. UPRINTF("usage: %s line-to-send\n", argv[0]);
  1530. code = -1;
  1531. return;
  1532. }
  1533. quote1("SITE ", argc, argv);
  1534. }
  1535. /*
  1536. * Turn argv[1..argc) into a space-separated string, then prepend initial text.
  1537. * Send the result as a one-line command and get response.
  1538. */
  1539. void
  1540. quote1(const char *initial, int argc, char *argv[])
  1541. {
  1542. int i;
  1543. char buf[BUFSIZ]; /* must be >= sizeof(line) */
  1544. (void)strlcpy(buf, initial, sizeof(buf));
  1545. for (i = 1; i < argc; i++) {
  1546. (void)strlcat(buf, argv[i], sizeof(buf));
  1547. if (i < (argc - 1))
  1548. (void)strlcat(buf, " ", sizeof(buf));
  1549. }
  1550. if (command("%s", buf) == PRELIM) {
  1551. while (getreply(0) == PRELIM)
  1552. continue;
  1553. }
  1554. dirchange = 1;
  1555. }
  1556. void
  1557. do_chmod(int argc, char *argv[])
  1558. {
  1559. if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode")))
  1560. goto usage;
  1561. if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
  1562. usage:
  1563. UPRINTF("usage: %s mode remote-file\n", argv[0]);
  1564. code = -1;
  1565. return;
  1566. }
  1567. (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
  1568. }
  1569. #define COMMAND_1ARG(argc, argv, cmd) \
  1570. if (argc == 1) \
  1571. command(cmd); \
  1572. else \
  1573. command(cmd " %s", argv[1])
  1574. void
  1575. do_umask(int argc, char *argv[])
  1576. {
  1577. int oldverbose = verbose;
  1578. if (argc == 0) {
  1579. UPRINTF("usage: %s [umask]\n", argv[0]);
  1580. code = -1;
  1581. return;
  1582. }
  1583. verbose = 1;
  1584. COMMAND_1ARG(argc, argv, "SITE UMASK");
  1585. verbose = oldverbose;
  1586. }
  1587. void
  1588. idlecmd(int argc, char *argv[])
  1589. {
  1590. int oldverbose = verbose;
  1591. if (argc < 1 || argc > 2) {
  1592. UPRINTF("usage: %s [seconds]\n", argv[0]);
  1593. code = -1;
  1594. return;
  1595. }
  1596. verbose = 1;
  1597. COMMAND_1ARG(argc, argv, "SITE IDLE");
  1598. verbose = oldverbose;
  1599. }
  1600. /*
  1601. * Ask the other side for help.
  1602. */
  1603. void
  1604. rmthelp(int argc, char *argv[])
  1605. {
  1606. int oldverbose = verbose;
  1607. if (argc == 0) {
  1608. UPRINTF("usage: %s\n", argv[0]);
  1609. code = -1;
  1610. return;
  1611. }
  1612. verbose = 1;
  1613. COMMAND_1ARG(argc, argv, "HELP");
  1614. verbose = oldverbose;
  1615. }
  1616. /*
  1617. * Terminate session and exit.
  1618. * May be called with 0, NULL.
  1619. */
  1620. /*VARARGS*/
  1621. void
  1622. quit(int argc, char *argv[])
  1623. {
  1624. /* this may be called with argc == 0, argv == NULL */
  1625. if (argc == 0 && argv != NULL) {
  1626. UPRINTF("usage: %s\n", argv[0]);
  1627. code = -1;
  1628. return;
  1629. }
  1630. if (connected)
  1631. disconnect(0, NULL);
  1632. pswitch(1);
  1633. if (connected)
  1634. disconnect(0, NULL);
  1635. exit(0);
  1636. }
  1637. /*
  1638. * Terminate session, but don't exit.
  1639. * May be called with 0, NULL.
  1640. */
  1641. void
  1642. disconnect(int argc, char *argv[])
  1643. {
  1644. /* this may be called with argc == 0, argv == NULL */
  1645. if (argc == 0 && argv != NULL) {
  1646. UPRINTF("usage: %s\n", argv[0]);
  1647. code = -1;
  1648. return;
  1649. }
  1650. if (!connected)
  1651. return;
  1652. (void)command("QUIT");
  1653. cleanuppeer();
  1654. }
  1655. void
  1656. account(int argc, char *argv[])
  1657. {
  1658. char *ap;
  1659. char emptypass[] = "";
  1660. if (argc == 0 || argc > 2) {
  1661. UPRINTF("usage: %s [password]\n", argv[0]);
  1662. code = -1;
  1663. return;
  1664. }
  1665. else if (argc == 2)
  1666. ap = argv[1];
  1667. else {
  1668. ap = getpass("Account:");
  1669. if (ap == NULL)
  1670. ap = emptypass;
  1671. }
  1672. (void)command("ACCT %s", ap);
  1673. memset(ap, 0, strlen(ap));
  1674. }
  1675. sigjmp_buf abortprox;
  1676. void
  1677. proxabort(int notused)
  1678. {
  1679. sigint_raised = 1;
  1680. alarmtimer(0);
  1681. if (!proxy) {
  1682. pswitch(1);
  1683. }
  1684. if (connected) {
  1685. proxflag = 1;
  1686. }
  1687. else {
  1688. proxflag = 0;
  1689. }
  1690. pswitch(0);
  1691. siglongjmp(abortprox, 1);
  1692. }
  1693. void
  1694. doproxy(int argc, char *argv[])
  1695. {
  1696. struct cmd *c;
  1697. int cmdpos;
  1698. sigfunc oldintr;
  1699. char cmdbuf[MAX_C_NAME];
  1700. if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) {
  1701. UPRINTF("usage: %s command\n", argv[0]);
  1702. code = -1;
  1703. return;
  1704. }
  1705. c = getcmd(argv[1]);
  1706. if (c == (struct cmd *) -1) {
  1707. fputs("?Ambiguous command.\n", ttyout);
  1708. code = -1;
  1709. return;
  1710. }
  1711. if (c == 0) {
  1712. fputs("?Invalid command.\n", ttyout);
  1713. code = -1;
  1714. return;
  1715. }
  1716. if (!c->c_proxy) {
  1717. fputs("?Invalid proxy command.\n", ttyout);
  1718. code = -1;
  1719. return;
  1720. }
  1721. if (sigsetjmp(abortprox, 1)) {
  1722. code = -1;
  1723. return;
  1724. }
  1725. oldintr = xsignal(SIGINT, proxabort);
  1726. pswitch(1);
  1727. if (c->c_conn && !connected) {
  1728. fputs("Not connected.\n", ttyout);
  1729. pswitch(0);
  1730. (void)xsignal(SIGINT, oldintr);
  1731. code = -1;
  1732. return;
  1733. }
  1734. cmdpos = strcspn(line, " \t");
  1735. if (cmdpos > 0) /* remove leading "proxy " from input buffer */
  1736. memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
  1737. (void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf));
  1738. argv[1] = cmdbuf;
  1739. (*c->c_handler)(argc-1, argv+1);
  1740. if (connected) {
  1741. proxflag = 1;
  1742. }
  1743. else {
  1744. proxflag = 0;
  1745. }
  1746. pswitch(0);
  1747. (void)xsignal(SIGINT, oldintr);
  1748. }
  1749. void
  1750. setcase(int argc, char *argv[])
  1751. {
  1752. code = togglevar(argc, argv, &mcase, "Case mapping");
  1753. }
  1754. /*
  1755. * convert the given name to lower case if it's all upper case, into
  1756. * a static buffer which is returned to the caller
  1757. */
  1758. static const char *
  1759. docase(char *dst, size_t dlen, const char *src)
  1760. {
  1761. size_t i;
  1762. int dochange = 1;
  1763. for (i = 0; src[i] != '\0' && i < dlen - 1; i++) {
  1764. dst[i] = src[i];
  1765. if (islower((unsigned char)dst[i]))
  1766. dochange = 0;
  1767. }
  1768. dst[i] = '\0';
  1769. if (dochange) {
  1770. for (i = 0; dst[i] != '\0'; i++)
  1771. if (isupper((unsigned char)dst[i]))
  1772. dst[i] = tolower((unsigned char)dst[i]);
  1773. }
  1774. return dst;
  1775. }
  1776. void
  1777. setcr(int argc, char *argv[])
  1778. {
  1779. code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
  1780. }
  1781. void
  1782. setntrans(int argc, char *argv[])
  1783. {
  1784. if (argc == 0 || argc > 3) {
  1785. UPRINTF("usage: %s [inchars [outchars]]\n", argv[0]);
  1786. code = -1;
  1787. return;
  1788. }
  1789. if (argc == 1) {
  1790. ntflag = 0;
  1791. fputs("Ntrans off.\n", ttyout);
  1792. code = ntflag;
  1793. return;
  1794. }
  1795. ntflag++;
  1796. code = ntflag;
  1797. (void)strlcpy(ntin, argv[1], sizeof(ntin));
  1798. if (argc == 2) {
  1799. ntout[0] = '\0';
  1800. return;
  1801. }
  1802. (void)strlcpy(ntout, argv[2], sizeof(ntout));
  1803. }
  1804. static const char *
  1805. dotrans(char *dst, size_t dlen, const char *src)
  1806. {
  1807. const char *cp1;
  1808. char *cp2 = dst;
  1809. size_t i, ostop;
  1810. for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
  1811. continue;
  1812. for (cp1 = src; *cp1; cp1++) {
  1813. int found = 0;
  1814. for (i = 0; *(ntin + i) && i < 16; i++) {
  1815. if (*cp1 == *(ntin + i)) {
  1816. found++;
  1817. if (i < ostop) {
  1818. *cp2++ = *(ntout + i);
  1819. if (cp2 - dst >= (ptrdiff_t)(dlen - 1))
  1820. goto out;
  1821. }
  1822. break;
  1823. }
  1824. }
  1825. if (!found) {
  1826. *cp2++ = *cp1;
  1827. }
  1828. }
  1829. out:
  1830. *cp2 = '\0';
  1831. return dst;
  1832. }
  1833. void
  1834. setnmap(int argc, char *argv[])
  1835. {
  1836. char *cp;
  1837. if (argc == 1) {
  1838. mapflag = 0;
  1839. fputs("Nmap off.\n", ttyout);
  1840. code = mapflag;
  1841. return;
  1842. }
  1843. if (argc == 0 ||
  1844. (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
  1845. UPRINTF("usage: %s [mapin mapout]\n", argv[0]);
  1846. code = -1;
  1847. return;
  1848. }
  1849. mapflag = 1;
  1850. code = 1;
  1851. cp = strchr(altarg, ' ');
  1852. if (proxy) {
  1853. while(*++cp == ' ')
  1854. continue;
  1855. altarg = cp;
  1856. cp = strchr(altarg, ' ');
  1857. }
  1858. *cp = '\0';
  1859. (void)strlcpy(mapin, altarg, MAXPATHLEN);
  1860. while (*++cp == ' ')
  1861. continue;
  1862. (void)strlcpy(mapout, cp, MAXPATHLEN);
  1863. }
  1864. static const char *
  1865. domap(char *dst, size_t dlen, const char *src)
  1866. {
  1867. const char *cp1 = src;
  1868. char *cp2 = mapin;
  1869. const char *tp[9], *te[9];
  1870. int i, toks[9], toknum = 0, match = 1;
  1871. for (i=0; i < 9; ++i) {
  1872. toks[i] = 0;
  1873. }
  1874. while (match && *cp1 && *cp2) {
  1875. switch (*cp2) {
  1876. case '\\':
  1877. if (*++cp2 != *cp1) {
  1878. match = 0;
  1879. }
  1880. break;
  1881. case '$':
  1882. if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
  1883. if (*cp1 != *(++cp2+1)) {
  1884. toks[toknum = *cp2 - '1']++;
  1885. tp[toknum] = cp1;
  1886. while (*++cp1 && *(cp2+1)
  1887. != *cp1);
  1888. te[toknum] = cp1;
  1889. }
  1890. cp2++;
  1891. break;
  1892. }
  1893. /* FALLTHROUGH */
  1894. default:
  1895. if (*cp2 != *cp1) {
  1896. match = 0;
  1897. }
  1898. break;
  1899. }
  1900. if (match && *cp1) {
  1901. cp1++;
  1902. }
  1903. if (match && *cp2) {
  1904. cp2++;
  1905. }
  1906. }
  1907. if (!match && *cp1) /* last token mismatch */
  1908. {
  1909. toks[toknum] = 0;
  1910. }
  1911. cp2 = dst;
  1912. *cp2 = '\0';
  1913. cp1 = mapout;
  1914. while (*cp1) {
  1915. match = 0;
  1916. switch (*cp1) {
  1917. case '\\':
  1918. if (*(cp1 + 1)) {
  1919. *cp2++ = *++cp1;
  1920. }
  1921. break;
  1922. case '[':
  1923. LOOP:
  1924. if (*++cp1 == '$' &&
  1925. isdigit((unsigned char)*(cp1+1))) {
  1926. if (*++cp1 == '0') {
  1927. const char *cp3 = src;
  1928. while (*cp3) {
  1929. *cp2++ = *cp3++;
  1930. }
  1931. match = 1;
  1932. }
  1933. else if (toks[toknum = *cp1 - '1']) {
  1934. const char *cp3 = tp[toknum];
  1935. while (cp3 != te[toknum]) {
  1936. *cp2++ = *cp3++;
  1937. }
  1938. match = 1;
  1939. }
  1940. }
  1941. else {
  1942. while (*cp1 && *cp1 != ',' &&
  1943. *cp1 != ']') {
  1944. if (*cp1 == '\\') {
  1945. cp1++;
  1946. }
  1947. else if (*cp1 == '$' &&
  1948. isdigit((unsigned char)*(cp1+1))) {
  1949. if (*++cp1 == '0') {
  1950. const char *cp3 = src;
  1951. while (*cp3) {
  1952. *cp2++ = *cp3++;
  1953. }
  1954. }
  1955. else if (toks[toknum =
  1956. *cp1 - '1']) {
  1957. const char *cp3=tp[toknum];
  1958. while (cp3 !=
  1959. te[toknum]) {
  1960. *cp2++ = *cp3++;
  1961. }
  1962. }
  1963. }
  1964. else if (*cp1) {
  1965. *cp2++ = *cp1++;
  1966. }
  1967. }
  1968. if (!*cp1) {
  1969. fputs(
  1970. "nmap: unbalanced brackets.\n",
  1971. ttyout);
  1972. return (src);
  1973. }
  1974. match = 1;
  1975. cp1--;
  1976. }
  1977. if (match) {
  1978. while (*++cp1 && *cp1 != ']') {
  1979. if (*cp1 == '\\' && *(cp1 + 1)) {
  1980. cp1++;
  1981. }
  1982. }
  1983. if (!*cp1) {
  1984. fputs(
  1985. "nmap: unbalanced brackets.\n",
  1986. ttyout);
  1987. return (src);
  1988. }
  1989. break;
  1990. }
  1991. switch (*++cp1) {
  1992. case ',':
  1993. goto LOOP;
  1994. case ']':
  1995. break;
  1996. default:
  1997. cp1--;
  1998. goto LOOP;
  1999. }
  2000. break;
  2001. case '$':
  2002. if (isdigit((unsigned char)*(cp1 + 1))) {
  2003. if (*++cp1 == '0') {
  2004. const char *cp3 = src;
  2005. while (*cp3) {
  2006. *cp2++ = *cp3++;
  2007. }
  2008. }
  2009. else if (toks[toknum = *cp1 - '1']) {
  2010. const char *cp3 = tp[toknum];
  2011. while (cp3 != te[toknum]) {
  2012. *cp2++ = *cp3++;
  2013. }
  2014. }
  2015. break;
  2016. }
  2017. /* intentional drop through */
  2018. default:
  2019. *cp2++ = *cp1;
  2020. break;
  2021. }
  2022. cp1++;
  2023. }
  2024. *cp2 = '\0';
  2025. return *dst ? dst : src;
  2026. }
  2027. void
  2028. setpassive(int argc, char *argv[])
  2029. {
  2030. if (argc == 1) {
  2031. passivemode = !passivemode;
  2032. activefallback = passivemode;
  2033. } else if (argc != 2) {
  2034. passiveusage:
  2035. UPRINTF("usage: %s [ on | off | auto ]\n", argv[0]);
  2036. code = -1;
  2037. return;
  2038. } else if (strcasecmp(argv[1], "on") == 0) {
  2039. passivemode = 1;
  2040. activefallback = 0;
  2041. } else if (strcasecmp(argv[1], "off") == 0) {
  2042. passivemode = 0;
  2043. activefallback = 0;
  2044. } else if (strcasecmp(argv[1], "auto") == 0) {
  2045. passivemode = 1;
  2046. activefallback = 1;
  2047. } else
  2048. goto passiveusage;
  2049. fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
  2050. onoff(passivemode), onoff(activefallback));
  2051. code = passivemode;
  2052. }
  2053. void
  2054. setepsv4(int argc, char *argv[])
  2055. {
  2056. code = togglevar(argc, argv, &epsv4,
  2057. verbose ? "EPSV/EPRT on IPv4" : NULL);
  2058. epsv4bad = 0;
  2059. }
  2060. void
  2061. setepsv6(int argc, char *argv[])
  2062. {
  2063. code = togglevar(argc, argv, &epsv6,
  2064. verbose ? "EPSV/EPRT on IPv6" : NULL);
  2065. epsv6bad = 0;
  2066. }
  2067. void
  2068. setepsv(int argc, char*argv[])
  2069. {
  2070. setepsv4(argc,argv);
  2071. setepsv6(argc,argv);
  2072. }
  2073. void
  2074. setsunique(int argc, char *argv[])
  2075. {
  2076. code = togglevar(argc, argv, &sunique, "Store unique");
  2077. }
  2078. void
  2079. setrunique(int argc, char *argv[])
  2080. {
  2081. code = togglevar(argc, argv, &runique, "Receive unique");
  2082. }
  2083. int
  2084. parserate(int argc, char *argv[], int cmdlineopt)
  2085. {
  2086. int dir, max, incr, showonly;
  2087. sigfunc oldusr1, oldusr2;
  2088. if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) {
  2089. usage:
  2090. if (cmdlineopt)
  2091. UPRINTF(
  2092. "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n",
  2093. argv[0]);
  2094. else
  2095. UPRINTF(
  2096. "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n",
  2097. argv[0]);
  2098. return -1;
  2099. }
  2100. dir = max = incr = showonly = 0;
  2101. #define RATE_GET 1
  2102. #define RATE_PUT 2
  2103. #define RATE_ALL (RATE_GET | RATE_PUT)
  2104. if (strcasecmp(argv[1], "all") == 0)
  2105. dir = RATE_ALL;
  2106. else if (strcasecmp(argv[1], "get") == 0)
  2107. dir = RATE_GET;
  2108. else if (strcasecmp(argv[1], "put") == 0)
  2109. dir = RATE_PUT;
  2110. else
  2111. goto usage;
  2112. if (argc >= 3) {
  2113. if ((max = strsuftoi(argv[2])) < 0)
  2114. goto usage;
  2115. } else
  2116. showonly = 1;
  2117. if (argc == 4) {
  2118. if ((incr = strsuftoi(argv[3])) <= 0)
  2119. goto usage;
  2120. } else
  2121. incr = DEFAULTINCR;
  2122. oldusr1 = xsignal(SIGUSR1, SIG_IGN);
  2123. oldusr2 = xsignal(SIGUSR2, SIG_IGN);
  2124. if (dir & RATE_GET) {
  2125. if (!showonly) {
  2126. rate_get = max;
  2127. rate_get_incr = incr;
  2128. }
  2129. if (!cmdlineopt || verbose)
  2130. fprintf(ttyout,
  2131. "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
  2132. onoff(rate_get), rate_get, rate_get_incr);
  2133. }
  2134. if (dir & RATE_PUT) {
  2135. if (!showonly) {
  2136. rate_put = max;
  2137. rate_put_incr = incr;
  2138. }
  2139. if (!cmdlineopt || verbose)
  2140. fprintf(ttyout,
  2141. "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
  2142. onoff(rate_put), rate_put, rate_put_incr);
  2143. }
  2144. (void)xsignal(SIGUSR1, oldusr1);
  2145. (void)xsignal(SIGUSR2, oldusr2);
  2146. return 0;
  2147. }
  2148. void
  2149. setrate(int argc, char *argv[])
  2150. {
  2151. code = parserate(argc, argv, 0);
  2152. }
  2153. /* change directory to parent directory */
  2154. void
  2155. cdup(int argc, char *argv[])
  2156. {
  2157. int r;
  2158. if (argc == 0) {
  2159. UPRINTF("usage: %s\n", argv[0]);
  2160. code = -1;
  2161. return;
  2162. }
  2163. r = command("CDUP");
  2164. if (r == ERROR && code == 500) {
  2165. if (verbose)
  2166. fputs("CDUP command not recognized, trying XCUP.\n",
  2167. ttyout);
  2168. r = command("XCUP");
  2169. }
  2170. if (r == COMPLETE) {
  2171. dirchange = 1;
  2172. updateremotecwd();
  2173. }
  2174. }
  2175. /*
  2176. * Restart transfer at specific point
  2177. */
  2178. void
  2179. restart(int argc, char *argv[])
  2180. {
  2181. if (argc == 0 || argc > 2) {
  2182. UPRINTF("usage: %s [restart-point]\n", argv[0]);
  2183. code = -1;
  2184. return;
  2185. }
  2186. if (! features[FEAT_REST_STREAM]) {
  2187. fprintf(ttyout,
  2188. "Restart is not supported by the remote server.\n");
  2189. return;
  2190. }
  2191. if (argc == 2) {
  2192. off_t rp;
  2193. char *ep;
  2194. rp = STRTOLL(argv[1], &ep, 10);
  2195. if (rp < 0 || *ep != '\0')
  2196. fprintf(ttyout, "restart: Invalid offset `%s'\n",
  2197. argv[1]);
  2198. else
  2199. restart_point = rp;
  2200. }
  2201. if (restart_point == 0)
  2202. fputs("No restart point defined.\n", ttyout);
  2203. else
  2204. fprintf(ttyout,
  2205. "Restarting at " LLF " for next get, put or append\n",
  2206. (LLT)restart_point);
  2207. }
  2208. /*
  2209. * Show remote system type
  2210. */
  2211. void
  2212. syst(int argc, char *argv[])
  2213. {
  2214. int oldverbose = verbose;
  2215. if (argc == 0) {
  2216. UPRINTF("usage: %s\n", argv[0]);
  2217. code = -1;
  2218. return;
  2219. }
  2220. verbose = 1; /* If we aren't verbose, this doesn't do anything! */
  2221. (void)command("SYST");
  2222. verbose = oldverbose;
  2223. }
  2224. void
  2225. macdef(int argc, char *argv[])
  2226. {
  2227. char *tmp;
  2228. int c;
  2229. if (argc == 0)
  2230. goto usage;
  2231. if (macnum == 16) {
  2232. fputs("Limit of 16 macros have already been defined.\n",
  2233. ttyout);
  2234. code = -1;
  2235. return;
  2236. }
  2237. if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
  2238. usage:
  2239. UPRINTF("usage: %s macro_name\n", argv[0]);
  2240. code = -1;
  2241. return;
  2242. }
  2243. if (interactive)
  2244. fputs(
  2245. "Enter macro line by line, terminating it with a null line.\n",
  2246. ttyout);
  2247. (void)strlcpy(macros[macnum].mac_name, argv[1],
  2248. sizeof(macros[macnum].mac_name));
  2249. if (macnum == 0)
  2250. macros[macnum].mac_start = macbuf;
  2251. else
  2252. macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  2253. tmp = macros[macnum].mac_start;
  2254. while (tmp != macbuf+4096) {
  2255. if ((c = getchar()) == EOF) {
  2256. fputs("macdef: end of file encountered.\n", ttyout);
  2257. code = -1;
  2258. return;
  2259. }
  2260. if ((*tmp = c) == '\n') {
  2261. if (tmp == macros[macnum].mac_start) {
  2262. macros[macnum++].mac_end = tmp;
  2263. code = 0;
  2264. return;
  2265. }
  2266. if (*(tmp-1) == '\0') {
  2267. macros[macnum++].mac_end = tmp - 1;
  2268. code = 0;
  2269. return;
  2270. }
  2271. *tmp = '\0';
  2272. }
  2273. tmp++;
  2274. }
  2275. while (1) {
  2276. while ((c = getchar()) != '\n' && c != EOF)
  2277. /* LOOP */;
  2278. if (c == EOF || getchar() == '\n') {
  2279. fputs("Macro not defined - 4K buffer exceeded.\n",
  2280. ttyout);
  2281. code = -1;
  2282. return;
  2283. }
  2284. }
  2285. }
  2286. /*
  2287. * Get size of file on remote machine
  2288. */
  2289. void
  2290. sizecmd(int argc, char *argv[])
  2291. {
  2292. off_t size;
  2293. if (argc == 0 || argc > 2 ||
  2294. (argc == 1 && !another(&argc, &argv, "remote-file"))) {
  2295. UPRINTF("usage: %s remote-file\n", argv[0]);
  2296. code = -1;
  2297. return;
  2298. }
  2299. size = remotesize(argv[1], 1);
  2300. if (size != -1)
  2301. fprintf(ttyout,
  2302. "%s\t" LLF "\n", argv[1], (LLT)size);
  2303. code = (size > 0);
  2304. }
  2305. /*
  2306. * Get last modification time of file on remote machine
  2307. */
  2308. void
  2309. modtime(int argc, char *argv[])
  2310. {
  2311. time_t mtime;
  2312. if (argc == 0 || argc > 2 ||
  2313. (argc == 1 && !another(&argc, &argv, "remote-file"))) {
  2314. UPRINTF("usage: %s remote-file\n", argv[0]);
  2315. code = -1;
  2316. return;
  2317. }
  2318. mtime = remotemodtime(argv[1], 1);
  2319. if (mtime != -1)
  2320. fprintf(ttyout, "%s\t%s", argv[1],
  2321. rfc2822time(localtime(&mtime)));
  2322. code = (mtime > 0);
  2323. }
  2324. /*
  2325. * Show status on remote machine
  2326. */
  2327. void
  2328. rmtstatus(int argc, char *argv[])
  2329. {
  2330. if (argc == 0) {
  2331. UPRINTF("usage: %s [remote-file]\n", argv[0]);
  2332. code = -1;
  2333. return;
  2334. }
  2335. COMMAND_1ARG(argc, argv, "STAT");
  2336. }
  2337. /*
  2338. * Get file if modtime is more recent than current file
  2339. */
  2340. void
  2341. newer(int argc, char *argv[])
  2342. {
  2343. if (getit(argc, argv, -1, "w"))
  2344. fprintf(ttyout,
  2345. "Local file \"%s\" is newer than remote file \"%s\".\n",
  2346. argv[2], argv[1]);
  2347. }
  2348. /*
  2349. * Display one local file through $PAGER.
  2350. */
  2351. void
  2352. lpage(int argc, char *argv[])
  2353. {
  2354. size_t len;
  2355. const char *p;
  2356. char *pager, *locfile;
  2357. if (argc == 0 || argc > 2 ||
  2358. (argc == 1 && !another(&argc, &argv, "local-file"))) {
  2359. UPRINTF("usage: %s local-file\n", argv[0]);
  2360. code = -1;
  2361. return;
  2362. }
  2363. if ((locfile = globulize(argv[1])) == NULL) {
  2364. code = -1;
  2365. return;
  2366. }
  2367. p = getoptionvalue("pager");
  2368. if (EMPTYSTRING(p))
  2369. p = DEFAULTPAGER;
  2370. len = strlen(p) + strlen(locfile) + 2;
  2371. pager = ftp_malloc(len);
  2372. (void)strlcpy(pager, p, len);
  2373. (void)strlcat(pager, " ", len);
  2374. (void)strlcat(pager, locfile, len);
  2375. system(pager);
  2376. code = 0;
  2377. (void)free(pager);
  2378. (void)free(locfile);
  2379. }
  2380. /*
  2381. * Display one remote file through $PAGER.
  2382. */
  2383. void
  2384. page(int argc, char *argv[])
  2385. {
  2386. int ohash, orestart_point, overbose;
  2387. size_t len;
  2388. const char *p;
  2389. char *pager;
  2390. if (argc == 0 || argc > 2 ||
  2391. (argc == 1 && !another(&argc, &argv, "remote-file"))) {
  2392. UPRINTF("usage: %s remote-file\n", argv[0]);
  2393. code = -1;
  2394. return;
  2395. }
  2396. p = getoptionvalue("pager");
  2397. if (EMPTYSTRING(p))
  2398. p = DEFAULTPAGER;
  2399. len = strlen(p) + 2;
  2400. pager = ftp_malloc(len);
  2401. pager[0] = '|';
  2402. (void)strlcpy(pager + 1, p, len - 1);
  2403. ohash = hash;
  2404. orestart_point = restart_point;
  2405. overbose = verbose;
  2406. hash = restart_point = verbose = 0;
  2407. recvrequest("RETR", pager, argv[1], "r+", 1, 0);
  2408. hash = ohash;
  2409. restart_point = orestart_point;
  2410. verbose = overbose;
  2411. (void)free(pager);
  2412. }
  2413. /*
  2414. * Set the socket send or receive buffer size.
  2415. */
  2416. void
  2417. setxferbuf(int argc, char *argv[])
  2418. {
  2419. int size, dir;
  2420. if (argc != 2) {
  2421. usage:
  2422. UPRINTF("usage: %s size\n", argv[0]);
  2423. code = -1;
  2424. return;
  2425. }
  2426. if (strcasecmp(argv[0], "sndbuf") == 0)
  2427. dir = RATE_PUT;
  2428. else if (strcasecmp(argv[0], "rcvbuf") == 0)
  2429. dir = RATE_GET;
  2430. else if (strcasecmp(argv[0], "xferbuf") == 0)
  2431. dir = RATE_ALL;
  2432. else
  2433. goto usage;
  2434. if ((size = strsuftoi(argv[1])) == -1)
  2435. goto usage;
  2436. if (size == 0) {
  2437. fprintf(ttyout, "%s: size must be positive.\n", argv[0]);
  2438. goto usage;
  2439. }
  2440. if (dir & RATE_PUT) {
  2441. sndbuf_size = size;
  2442. auto_sndbuf = 0;
  2443. }
  2444. if (dir & RATE_GET) {
  2445. rcvbuf_size = size;
  2446. auto_rcvbuf = 0;
  2447. }
  2448. fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n",
  2449. sndbuf_size, rcvbuf_size);
  2450. code = 0;
  2451. }
  2452. /*
  2453. * Set or display options (defaults are provided by various env vars)
  2454. */
  2455. void
  2456. setoption(int argc, char *argv[])
  2457. {
  2458. struct option *o;
  2459. code = -1;
  2460. if (argc == 0 || (argc != 1 && argc != 3)) {
  2461. UPRINTF("usage: %s [option value]\n", argv[0]);
  2462. return;
  2463. }
  2464. #define OPTIONINDENT ((int) sizeof("http_proxy"))
  2465. if (argc == 1) {
  2466. for (o = optiontab; o->name != NULL; o++) {
  2467. fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT,
  2468. o->name, o->value ? o->value : "");
  2469. }
  2470. } else {
  2471. set_option(argv[1], argv[2], 1);
  2472. }
  2473. code = 0;
  2474. }
  2475. void
  2476. set_option(const char * option, const char * value, int doverbose)
  2477. {
  2478. struct option *o;
  2479. o = getoption(option);
  2480. if (o == NULL) {
  2481. fprintf(ttyout, "No such option `%s'.\n", option);
  2482. return;
  2483. }
  2484. FREEPTR(o->value);
  2485. o->value = ftp_strdup(value);
  2486. if (verbose && doverbose)
  2487. fprintf(ttyout, "Setting `%s' to `%s'.\n",
  2488. o->name, o->value);
  2489. }
  2490. /*
  2491. * Unset an option
  2492. */
  2493. void
  2494. unsetoption(int argc, char *argv[])
  2495. {
  2496. struct option *o;
  2497. code = -1;
  2498. if (argc == 0 || argc != 2) {
  2499. UPRINTF("usage: %s option\n", argv[0]);
  2500. return;
  2501. }
  2502. o = getoption(argv[1]);
  2503. if (o == NULL) {
  2504. fprintf(ttyout, "No such option `%s'.\n", argv[1]);
  2505. return;
  2506. }
  2507. FREEPTR(o->value);
  2508. fprintf(ttyout, "Unsetting `%s'.\n", o->name);
  2509. code = 0;
  2510. }
  2511. /*
  2512. * Display features supported by the remote host.
  2513. */
  2514. void
  2515. feat(int argc, char *argv[])
  2516. {
  2517. int oldverbose = verbose;
  2518. if (argc == 0) {
  2519. UPRINTF("usage: %s\n", argv[0]);
  2520. code = -1;
  2521. return;
  2522. }
  2523. if (! features[FEAT_FEAT]) {
  2524. fprintf(ttyout,
  2525. "FEAT is not supported by the remote server.\n");
  2526. return;
  2527. }
  2528. verbose = 1; /* If we aren't verbose, this doesn't do anything! */
  2529. (void)command("FEAT");
  2530. verbose = oldverbose;
  2531. }
  2532. void
  2533. mlst(int argc, char *argv[])
  2534. {
  2535. int oldverbose = verbose;
  2536. if (argc < 1 || argc > 2) {
  2537. UPRINTF("usage: %s [remote-path]\n", argv[0]);
  2538. code = -1;
  2539. return;
  2540. }
  2541. if (! features[FEAT_MLST]) {
  2542. fprintf(ttyout,
  2543. "MLST is not supported by the remote server.\n");
  2544. return;
  2545. }
  2546. verbose = 1; /* If we aren't verbose, this doesn't do anything! */
  2547. COMMAND_1ARG(argc, argv, "MLST");
  2548. verbose = oldverbose;
  2549. }
  2550. void
  2551. opts(int argc, char *argv[])
  2552. {
  2553. int oldverbose = verbose;
  2554. if (argc < 2 || argc > 3) {
  2555. UPRINTF("usage: %s command [options]\n", argv[0]);
  2556. code = -1;
  2557. return;
  2558. }
  2559. if (! features[FEAT_FEAT]) {
  2560. fprintf(ttyout,
  2561. "OPTS is not supported by the remote server.\n");
  2562. return;
  2563. }
  2564. verbose = 1; /* If we aren't verbose, this doesn't do anything! */
  2565. if (argc == 2)
  2566. command("OPTS %s", argv[1]);
  2567. else
  2568. command("OPTS %s %s", argv[1], argv[2]);
  2569. verbose = oldverbose;
  2570. }