summaryrefslogtreecommitdiff
path: root/sftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp.c')
-rw-r--r--sftp.c141
1 files changed, 82 insertions, 59 deletions
diff --git a/sftp.c b/sftp.c
index 229f12987..ab667f5a5 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp.c,v 1.125 2010/06/18 00:58:39 djm Exp $ */ 1/* $OpenBSD: sftp.c,v 1.132 2010/12/04 00:18:01 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -132,6 +132,7 @@ extern char *__progname;
132#define I_GET 5 132#define I_GET 5
133#define I_HELP 6 133#define I_HELP 6
134#define I_LCHDIR 7 134#define I_LCHDIR 7
135#define I_LINK 25
135#define I_LLS 8 136#define I_LLS 8
136#define I_LMKDIR 9 137#define I_LMKDIR 9
137#define I_LPWD 10 138#define I_LPWD 10
@@ -176,7 +177,7 @@ static const struct CMD cmds[] = {
176 { "lchdir", I_LCHDIR, LOCAL }, 177 { "lchdir", I_LCHDIR, LOCAL },
177 { "lls", I_LLS, LOCAL }, 178 { "lls", I_LLS, LOCAL },
178 { "lmkdir", I_LMKDIR, LOCAL }, 179 { "lmkdir", I_LMKDIR, LOCAL },
179 { "ln", I_SYMLINK, REMOTE }, 180 { "ln", I_LINK, REMOTE },
180 { "lpwd", I_LPWD, LOCAL }, 181 { "lpwd", I_LPWD, LOCAL },
181 { "ls", I_LS, REMOTE }, 182 { "ls", I_LS, REMOTE },
182 { "lumask", I_LUMASK, NOARGS }, 183 { "lumask", I_LUMASK, NOARGS },
@@ -240,7 +241,7 @@ help(void)
240 "lcd path Change local directory to 'path'\n" 241 "lcd path Change local directory to 'path'\n"
241 "lls [ls-options [path]] Display local directory listing\n" 242 "lls [ls-options [path]] Display local directory listing\n"
242 "lmkdir path Create local directory\n" 243 "lmkdir path Create local directory\n"
243 "ln oldpath newpath Symlink remote file\n" 244 "ln [-s] oldpath newpath Link remote file (-s for symlink)\n"
244 "lpwd Print local working directory\n" 245 "lpwd Print local working directory\n"
245 "ls [-1afhlnrSt] [path] Display remote directory listing\n" 246 "ls [-1afhlnrSt] [path] Display remote directory listing\n"
246 "lumask umask Set local umask to 'umask'\n" 247 "lumask umask Set local umask to 'umask'\n"
@@ -269,7 +270,7 @@ local_do_shell(const char *args)
269 if (!*args) 270 if (!*args)
270 args = NULL; 271 args = NULL;
271 272
272 if ((shell = getenv("SHELL")) == NULL) 273 if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
273 shell = _PATH_BSHELL; 274 shell = _PATH_BSHELL;
274 275
275 if ((pid = fork()) == -1) 276 if ((pid = fork()) == -1)
@@ -377,6 +378,30 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag,
377} 378}
378 379
379static int 380static int
381parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
382{
383 extern int opterr, optind, optopt, optreset;
384 int ch;
385
386 optind = optreset = 1;
387 opterr = 0;
388
389 *sflag = 0;
390 while ((ch = getopt(argc, argv, "s")) != -1) {
391 switch (ch) {
392 case 's':
393 *sflag = 1;
394 break;
395 default:
396 error("%s: Invalid flag -%c", cmd, optopt);
397 return -1;
398 }
399 }
400
401 return optind;
402}
403
404static int
380parse_ls_flags(char **argv, int argc, int *lflag) 405parse_ls_flags(char **argv, int argc, int *lflag)
381{ 406{
382 extern int opterr, optind, optopt, optreset; 407 extern int opterr, optind, optopt, optreset;
@@ -758,18 +783,22 @@ static int
758do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, 783do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
759 int lflag) 784 int lflag)
760{ 785{
761 glob_t g;
762 u_int i, c = 1, colspace = 0, columns = 1;
763 Attrib *a = NULL; 786 Attrib *a = NULL;
787 char *fname, *lname;
788 glob_t g;
789 int err;
790 struct winsize ws;
791 u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80;
764 792
765 memset(&g, 0, sizeof(g)); 793 memset(&g, 0, sizeof(g));
766 794
767 if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, 795 if (remote_glob(conn, path,
768 NULL, &g) || (g.gl_pathc && !g.gl_matchc)) { 796 GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT, NULL, &g) ||
797 (g.gl_pathc && !g.gl_matchc)) {
769 if (g.gl_pathc) 798 if (g.gl_pathc)
770 globfree(&g); 799 globfree(&g);
771 error("Can't ls: \"%s\" not found", path); 800 error("Can't ls: \"%s\" not found", path);
772 return (-1); 801 return -1;
773 } 802 }
774 803
775 if (interrupted) 804 if (interrupted)
@@ -779,59 +808,35 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
779 * If the glob returns a single match and it is a directory, 808 * If the glob returns a single match and it is a directory,
780 * then just list its contents. 809 * then just list its contents.
781 */ 810 */
782 if (g.gl_matchc == 1) { 811 if (g.gl_matchc == 1 && g.gl_statv[0] != NULL &&
783 if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) { 812 S_ISDIR(g.gl_statv[0]->st_mode)) {
784 globfree(&g); 813 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
785 return (-1); 814 globfree(&g);
786 } 815 return err;
787 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
788 S_ISDIR(a->perm)) {
789 int err;
790
791 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
792 globfree(&g);
793 return (err);
794 }
795 } 816 }
796 817
797 if (!(lflag & LS_SHORT_VIEW)) { 818 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
798 u_int m = 0, width = 80; 819 width = ws.ws_col;
799 struct winsize ws;
800 820
821 if (!(lflag & LS_SHORT_VIEW)) {
801 /* Count entries for sort and find longest filename */ 822 /* Count entries for sort and find longest filename */
802 for (i = 0; g.gl_pathv[i]; i++) 823 for (i = 0; g.gl_pathv[i]; i++)
803 m = MAX(m, strlen(g.gl_pathv[i])); 824 m = MAX(m, strlen(g.gl_pathv[i]));
804 825
805 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
806 width = ws.ws_col;
807
808 columns = width / (m + 2); 826 columns = width / (m + 2);
809 columns = MAX(columns, 1); 827 columns = MAX(columns, 1);
810 colspace = width / columns; 828 colspace = width / columns;
811 } 829 }
812 830
813 for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) { 831 for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
814 char *fname;
815
816 fname = path_strip(g.gl_pathv[i], strip_path); 832 fname = path_strip(g.gl_pathv[i], strip_path);
817
818 if (lflag & LS_LONG_VIEW) { 833 if (lflag & LS_LONG_VIEW) {
819 char *lname; 834 if (g.gl_statv[i] == NULL) {
820 struct stat sb; 835 error("no stat information for %s", fname);
821 836 continue;
822 /* 837 }
823 * XXX: this is slow - 1 roundtrip per path 838 lname = ls_file(fname, g.gl_statv[i], 1,
824 * A solution to this is to fork glob() and 839 (lflag & LS_SI_UNITS));
825 * build a sftp specific version which keeps the
826 * attribs (which currently get thrown away)
827 * that the server returns as well as the filenames.
828 */
829 memset(&sb, 0, sizeof(sb));
830 if (a == NULL)
831 a = do_lstat(conn, g.gl_pathv[i], 1);
832 if (a != NULL)
833 attrib_to_stat(a, &sb);
834 lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS));
835 printf("%s\n", lname); 840 printf("%s\n", lname);
836 xfree(lname); 841 xfree(lname);
837 } else { 842 } else {
@@ -852,7 +857,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
852 if (g.gl_pathc) 857 if (g.gl_pathc)
853 globfree(&g); 858 globfree(&g);
854 859
855 return (0); 860 return 0;
856} 861}
857 862
858static int 863static int
@@ -1108,7 +1113,7 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1108 1113
1109static int 1114static int
1110parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, 1115parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1111 int *hflag, unsigned long *n_arg, char **path1, char **path2) 1116 int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
1112{ 1117{
1113 const char *cmd, *cp = *cpp; 1118 const char *cmd, *cp = *cpp;
1114 char *cp2, **argv; 1119 char *cp2, **argv;
@@ -1158,7 +1163,8 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1158 switch (cmdnum) { 1163 switch (cmdnum) {
1159 case I_GET: 1164 case I_GET:
1160 case I_PUT: 1165 case I_PUT:
1161 if ((optidx = parse_getput_flags(cmd, argv, argc, pflag, rflag)) == -1) 1166 if ((optidx = parse_getput_flags(cmd, argv, argc,
1167 pflag, rflag)) == -1)
1162 return -1; 1168 return -1;
1163 /* Get first pathname (mandatory) */ 1169 /* Get first pathname (mandatory) */
1164 if (argc - optidx < 1) { 1170 if (argc - optidx < 1) {
@@ -1174,8 +1180,11 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1174 undo_glob_escape(*path2); 1180 undo_glob_escape(*path2);
1175 } 1181 }
1176 break; 1182 break;
1177 case I_RENAME: 1183 case I_LINK:
1184 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1185 return -1;
1178 case I_SYMLINK: 1186 case I_SYMLINK:
1187 case I_RENAME:
1179 if (argc - optidx < 2) { 1188 if (argc - optidx < 2) {
1180 error("You must specify two paths after a %s " 1189 error("You must specify two paths after a %s "
1181 "command.", cmd); 1190 "command.", cmd);
@@ -1278,7 +1287,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1278 int err_abort) 1287 int err_abort)
1279{ 1288{
1280 char *path1, *path2, *tmp; 1289 char *path1, *path2, *tmp;
1281 int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i; 1290 int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
1291 int cmdnum, i;
1282 unsigned long n_arg = 0; 1292 unsigned long n_arg = 0;
1283 Attrib a, *aa; 1293 Attrib a, *aa;
1284 char path_buf[MAXPATHLEN]; 1294 char path_buf[MAXPATHLEN];
@@ -1286,8 +1296,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1286 glob_t g; 1296 glob_t g;
1287 1297
1288 path1 = path2 = NULL; 1298 path1 = path2 = NULL;
1289 cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, &n_arg, 1299 cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
1290 &path1, &path2); 1300 &sflag, &n_arg, &path1, &path2);
1291 1301
1292 if (iflag != 0) 1302 if (iflag != 0)
1293 err_abort = 0; 1303 err_abort = 0;
@@ -1315,8 +1325,11 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1315 err = do_rename(conn, path1, path2); 1325 err = do_rename(conn, path1, path2);
1316 break; 1326 break;
1317 case I_SYMLINK: 1327 case I_SYMLINK:
1328 sflag = 1;
1329 case I_LINK:
1330 path1 = make_absolute(path1, *pwd);
1318 path2 = make_absolute(path2, *pwd); 1331 path2 = make_absolute(path2, *pwd);
1319 err = do_symlink(conn, path1, path2); 1332 err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
1320 break; 1333 break;
1321 case I_RM: 1334 case I_RM:
1322 path1 = make_absolute(path1, *pwd); 1335 path1 = make_absolute(path1, *pwd);
@@ -1745,6 +1758,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1745 case '"': 1758 case '"':
1746 case '\\': 1759 case '\\':
1747 case '\t': 1760 case '\t':
1761 case '[':
1748 case ' ': 1762 case ' ':
1749 if (quote == '\0' || tmp2[i] == quote) { 1763 if (quote == '\0' || tmp2[i] == quote) {
1750 if (el_insertstr(el, ins) == -1) 1764 if (el_insertstr(el, ins) == -1)
@@ -1874,7 +1888,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
1874 1888
1875 /* Tab Completion */ 1889 /* Tab Completion */
1876 el_set(el, EL_ADDFN, "ftp-complete", 1890 el_set(el, EL_ADDFN, "ftp-complete",
1877 "Context senstive argument completion", complete); 1891 "Context sensitive argument completion", complete);
1878 complete_ctx.conn = conn; 1892 complete_ctx.conn = conn;
1879 complete_ctx.remote_pathp = &remote_path; 1893 complete_ctx.remote_pathp = &remote_path;
1880 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); 1894 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
@@ -2054,7 +2068,7 @@ usage(void)
2054 fprintf(stderr, 2068 fprintf(stderr,
2055 "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" 2069 "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2056 " [-D sftp_server_path] [-F ssh_config] " 2070 " [-D sftp_server_path] [-F ssh_config] "
2057 "[-i identity_file]\n" 2071 "[-i identity_file] [-l limit]\n"
2058 " [-o ssh_option] [-P port] [-R num_requests] " 2072 " [-o ssh_option] [-P port] [-R num_requests] "
2059 "[-S program]\n" 2073 "[-S program]\n"
2060 " [-s subsystem | sftp_server] host\n" 2074 " [-s subsystem | sftp_server] host\n"
@@ -2073,6 +2087,7 @@ main(int argc, char **argv)
2073 int debug_level = 0, sshver = 2; 2087 int debug_level = 0, sshver = 2;
2074 char *file1 = NULL, *sftp_server = NULL; 2088 char *file1 = NULL, *sftp_server = NULL;
2075 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 2089 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2090 const char *errstr;
2076 LogLevel ll = SYSLOG_LEVEL_INFO; 2091 LogLevel ll = SYSLOG_LEVEL_INFO;
2077 arglist args; 2092 arglist args;
2078 extern int optind; 2093 extern int optind;
@@ -2080,6 +2095,7 @@ main(int argc, char **argv)
2080 struct sftp_conn *conn; 2095 struct sftp_conn *conn;
2081 size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; 2096 size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2082 size_t num_requests = DEFAULT_NUM_REQUESTS; 2097 size_t num_requests = DEFAULT_NUM_REQUESTS;
2098 long long limit_kbps = 0;
2083 2099
2084 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2100 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2085 sanitise_stdfd(); 2101 sanitise_stdfd();
@@ -2097,7 +2113,7 @@ main(int argc, char **argv)
2097 infile = stdin; 2113 infile = stdin;
2098 2114
2099 while ((ch = getopt(argc, argv, 2115 while ((ch = getopt(argc, argv,
2100 "1246hpqrvCc:D:i:o:s:S:b:B:F:P:R:")) != -1) { 2116 "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
2101 switch (ch) { 2117 switch (ch) {
2102 /* Passed through to ssh(1) */ 2118 /* Passed through to ssh(1) */
2103 case '4': 2119 case '4':
@@ -2158,6 +2174,13 @@ main(int argc, char **argv)
2158 case 'D': 2174 case 'D':
2159 sftp_direct = optarg; 2175 sftp_direct = optarg;
2160 break; 2176 break;
2177 case 'l':
2178 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
2179 &errstr);
2180 if (errstr != NULL)
2181 usage();
2182 limit_kbps *= 1024; /* kbps */
2183 break;
2161 case 'r': 2184 case 'r':
2162 global_rflag = 1; 2185 global_rflag = 1;
2163 break; 2186 break;
@@ -2235,7 +2258,7 @@ main(int argc, char **argv)
2235 } 2258 }
2236 freeargs(&args); 2259 freeargs(&args);
2237 2260
2238 conn = do_init(in, out, copy_buffer_len, num_requests); 2261 conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2239 if (conn == NULL) 2262 if (conn == NULL)
2240 fatal("Couldn't initialise connection to server"); 2263 fatal("Couldn't initialise connection to server");
2241 2264