diff --git a/openssh-8.7p1-sftpscp-dir-create.patch b/openssh-8.7p1-sftpscp-dir-create.patch new file mode 100644 index 0000000..a549170 --- /dev/null +++ b/openssh-8.7p1-sftpscp-dir-create.patch @@ -0,0 +1,167 @@ +diff -up openssh-8.7p1/scp.c.sftpdirs openssh-8.7p1/scp.c +--- openssh-8.7p1/scp.c.sftpdirs 2022-02-02 14:11:12.553447509 +0100 ++++ openssh-8.7p1/scp.c 2022-02-02 14:12:56.081316414 +0100 +@@ -130,6 +130,7 @@ + #include "misc.h" + #include "progressmeter.h" + #include "utf8.h" ++#include "sftp.h" + + #include "sftp-common.h" + #include "sftp-client.h" +@@ -660,7 +661,7 @@ main(int argc, char **argv) + * Finally check the exit status of the ssh process, if one was forked + * and no error has occurred yet + */ +- if (do_cmd_pid != -1 && errs == 0) { ++ if (do_cmd_pid != -1 && (mode == MODE_SFTP || errs == 0)) { + if (remin != -1) + (void) close(remin); + if (remout != -1) +@@ -1264,13 +1265,18 @@ tolocal(int argc, char **argv, enum scp_ + static char * + prepare_remote_path(struct sftp_conn *conn, const char *path) + { ++ size_t nslash; ++ + /* Handle ~ prefixed paths */ +- if (*path != '~') +- return xstrdup(path); + if (*path == '\0' || strcmp(path, "~") == 0) + return xstrdup("."); +- if (strncmp(path, "~/", 2) == 0) +- return xstrdup(path + 2); ++ if (*path != '~') ++ return xstrdup(path); ++ if (strncmp(path, "~/", 2) == 0) { ++ if ((nslash = strspn(path + 2, "/")) == strlen(path + 2)) ++ return xstrdup("."); ++ return xstrdup(path + 2 + nslash); ++ } + if (can_expand_path(conn)) + return do_expand_path(conn, path); + /* No protocol extension */ +@@ -1282,10 +1288,16 @@ void + source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) + { + char *target = NULL, *filename = NULL, *abs_dst = NULL; +- int target_is_dir; +- ++ int src_is_dir, target_is_dir; ++ Attrib a; ++ struct stat st; ++ ++ memset(&a, '\0', sizeof(a)); ++ if (stat(src, &st) != 0) ++ fatal("stat local \"%s\": %s", src, strerror(errno)); ++ src_is_dir = S_ISDIR(st.st_mode); + if ((filename = basename(src)) == NULL) +- fatal("basename %s: %s", src, strerror(errno)); ++ fatal("basename \"%s\": %s", src, strerror(errno)); + + /* + * No need to glob here - the local shell already took care of +@@ -1295,8 +1307,12 @@ source_sftp(int argc, char *src, char *t + cleanup_exit(255); + target_is_dir = remote_is_dir(conn, target); + if (targetshouldbedirectory && !target_is_dir) { +- fatal("Target is not a directory, but more files selected " +- "for upload"); ++ debug("target directory \"%s\" does not exist", target); ++ a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS; ++ a.perm = st.st_mode | 0700; /* ensure writable */ ++ if (do_mkdir(conn, target, &a, 1) != 0) ++ cleanup_exit(255); /* error already logged */ ++ target_is_dir = 1; + } + if (target_is_dir) + abs_dst = path_append(target, filename); +@@ -1306,14 +1322,17 @@ source_sftp(int argc, char *src, char *t + } + debug3_f("copying local %s to remote %s", src, abs_dst); + +- if (local_is_dir(src) && iamrecursive) { ++ if (src_is_dir && iamrecursive) { + if (upload_dir(conn, src, abs_dst, pflag, + SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) { +- fatal("failed to upload directory %s to %s", ++ error("failed to upload directory %s to %s", + src, abs_dst); ++ errs = 1; + } +- } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) +- fatal("failed to upload file %s to %s", src, abs_dst); ++ } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) { ++ error("failed to upload file %s to %s", src, abs_dst); ++ errs = 1; ++ } + + free(abs_dst); + free(target); +@@ -1487,14 +1506,15 @@ sink_sftp(int argc, char *dst, const cha + char *abs_dst = NULL; + glob_t g; + char *filename, *tmp = NULL; +- int i, r, err = 0; ++ int i, r, err = 0, dst_is_dir; ++ struct stat st; + + memset(&g, 0, sizeof(g)); ++ + /* + * Here, we need remote glob as SFTP can not depend on remote shell + * expansions + */ +- + if ((abs_src = prepare_remote_path(conn, src)) == NULL) { + err = -1; + goto out; +@@ -1510,11 +1530,24 @@ sink_sftp(int argc, char *dst, const cha + goto out; + } + +- if (g.gl_matchc > 1 && !local_is_dir(dst)) { +- error("Multiple files match pattern, but destination " +- "\"%s\" is not a directory", dst); +- err = -1; +- goto out; ++ if ((r = stat(dst, &st)) != 0) ++ debug2_f("stat local \"%s\": %s", dst, strerror(errno)); ++ dst_is_dir = r == 0 && S_ISDIR(st.st_mode); ++ ++ if (g.gl_matchc > 1 && !dst_is_dir) { ++ if (r == 0) { ++ error("Multiple files match pattern, but destination " ++ "\"%s\" is not a directory", dst); ++ err = -1; ++ goto out; ++ } ++ debug2_f("creating destination \"%s\"", dst); ++ if (mkdir(dst, 0777) != 0) { ++ error("local mkdir \"%s\": %s", dst, strerror(errno)); ++ err = -1; ++ goto out; ++ } ++ dst_is_dir = 1; + } + + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { +@@ -1525,7 +1558,7 @@ sink_sftp(int argc, char *dst, const cha + goto out; + } + +- if (local_is_dir(dst)) ++ if (dst_is_dir) + abs_dst = path_append(dst, filename); + else + abs_dst = xstrdup(dst); +@@ -1551,7 +1584,8 @@ out: + free(tmp); + globfree(&g); + if (err == -1) { +- fatal("Failed to download file '%s'", src); ++ error("Failed to download '%s'", src); ++ errs = 1; + } + } + diff --git a/openssh.spec b/openssh.spec index 8a00742..f419b72 100644 --- a/openssh.spec +++ b/openssh.spec @@ -51,7 +51,7 @@ # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 %global openssh_ver 8.7p1 -%global openssh_rel 6 +%global openssh_rel 7 %global pam_ssh_agent_ver 0.10.4 %global pam_ssh_agent_rel 4 @@ -201,6 +201,8 @@ Patch977: openssh-8.7p1-scp-kill-switch.patch Patch978: openssh-8.7p1-upstream-cve-2021-41617.patch # fix for `ssh-keygen -Y find-principals -f /dev/null -s /dev/null` (#2024902) Patch979: openssh-8.7p1-find-principals-fix.patch +# Create non-existent directories when scp works in sftp mode +Patch980: openssh-8.7p1-sftpscp-dir-create.patch Patch1000: openssh-8.7p1-minimize-sha1-use.patch @@ -382,6 +384,7 @@ popd %patch977 -p1 -b .kill-scp %patch978 -p1 -b .cve-2021-41617 %patch979 -p1 -b .find-principals +%patch980 -p1 -b .sftpdirs %patch200 -p1 -b .audit %patch201 -p1 -b .audit-race @@ -668,6 +671,10 @@ test -f %{sysconfig_anaconda} && \ %endif %changelog +* Wed Feb 02 2022 Dmitry Belyavskiy - 8.7p1-7 +- Switch to SFTP protocol in scp utility by default - upstream fixes + Related: rhbz#2001002 + * Tue Dec 21 2021 Dmitry Belyavskiy - 8.7p1-6 - Fix SSH connection to localhost not possible in FIPS Related: rhbz#2031868