diff options
author | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2011-01-24 12:43:25 +0000 |
commit | 626f1d986ff72aa514da63e34744e1de9cf21b9a (patch) | |
tree | d215a5280bc2e57251e4a9e08bfd3674ad824a94 /sftp.c | |
parent | 6ed622cb6fe8f71bbe0d998cdd12280410bfb420 (diff) | |
parent | 0970072c89b079b022538e3c366fbfa2c53fc821 (diff) |
* New upstream release (http://www.openssh.org/txt/release-5.7):
- Implement Elliptic Curve Cryptography modes for key exchange (ECDH)
and host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA
offer better performance than plain DH and DSA at the same equivalent
symmetric key length, as well as much shorter keys.
- sftp(1)/sftp-server(8): add a protocol extension to support a hard
link operation. It is available through the "ln" command in the
client. The old "ln" behaviour of creating a symlink is available
using its "-s" option or through the preexisting "symlink" command.
- scp(1): Add a new -3 option to scp: Copies between two remote hosts
are transferred through the local host (closes: #508613).
- ssh(1): "atomically" create the listening mux socket by binding it on
a temporary name and then linking it into position after listen() has
succeeded. This allows the mux clients to determine that the server
socket is either ready or stale without races (closes: #454784).
Stale server sockets are now automatically removed (closes: #523250).
- ssh(1): install a SIGCHLD handler to reap expired child process
(closes: #594687).
- ssh(1)/ssh-agent(1): honour $TMPDIR for client xauth and ssh-agent
temporary directories (closes: #357469, although only if you arrange
for ssh-agent to actually see $TMPDIR since the setgid bit will cause
it to be stripped off).
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 141 |
1 files changed, 82 insertions, 59 deletions
@@ -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 | ||
379 | static int | 380 | static int |
381 | parse_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 | |||
404 | static int | ||
380 | parse_ls_flags(char **argv, int argc, int *lflag) | 405 | parse_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 | |||
758 | do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | 783 | do_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 | ||
858 | static int | 863 | static int |
@@ -1108,7 +1113,7 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, | |||
1108 | 1113 | ||
1109 | static int | 1114 | static int |
1110 | parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, | 1115 | parse_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 | ||