From 83dfc89e6176888db58194a194053c2120d052d0 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 1 Mar 2022 07:45:34 -0500 Subject: [PATCH] import openssh-8.7p1-7.el9 --- SOURCES/openssh-8.7p1-recursive-scp.patch | 173 ++++++++++++++++++ .../openssh-8.7p1-sftpscp-dir-create.patch | 167 +++++++++++++++++ SPECS/openssh.spec | 21 ++- 3 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 SOURCES/openssh-8.7p1-recursive-scp.patch create mode 100644 SOURCES/openssh-8.7p1-sftpscp-dir-create.patch diff --git a/SOURCES/openssh-8.7p1-recursive-scp.patch b/SOURCES/openssh-8.7p1-recursive-scp.patch new file mode 100644 index 0000000..98ca843 --- /dev/null +++ b/SOURCES/openssh-8.7p1-recursive-scp.patch @@ -0,0 +1,173 @@ +diff -up openssh-8.7p1/scp.c.scp-sftpdirs openssh-8.7p1/scp.c +--- openssh-8.7p1/scp.c.scp-sftpdirs 2022-02-07 12:31:07.407740407 +0100 ++++ openssh-8.7p1/scp.c 2022-02-07 12:31:07.409740424 +0100 +@@ -1324,7 +1324,7 @@ source_sftp(int argc, char *src, char *t + + if (src_is_dir && iamrecursive) { + if (upload_dir(conn, src, abs_dst, pflag, +- SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) { ++ SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) { + error("failed to upload directory %s to %s", + src, abs_dst); + errs = 1; +diff -up openssh-8.7p1/sftp-client.c.scp-sftpdirs openssh-8.7p1/sftp-client.c +--- openssh-8.7p1/sftp-client.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/sftp-client.c 2022-02-07 12:47:59.117516131 +0100 +@@ -971,7 +971,7 @@ do_fsetstat(struct sftp_conn *conn, cons + + /* Implements both the realpath and expand-path operations */ + static char * +-do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) ++do_realpath_expand(struct sftp_conn *conn, const char *path, int expand, int create_dir) + { + struct sshbuf *msg; + u_int expected_id, count, id; +@@ -1012,9 +1012,37 @@ do_realpath_expand(struct sftp_conn *con + + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal_fr(r, "parse status"); +- error("Couldn't canonicalize: %s", fx2txt(status)); +- sshbuf_free(msg); +- return NULL; ++ if ((status == SSH2_FX_NO_SUCH_FILE) && create_dir) { ++ if ((r = do_mkdir(conn, path, &a, 0)) != 0) { ++ sshbuf_free(msg); ++ return NULL; ++ } ++ ++ send_string_request(conn, id, SSH2_FXP_REALPATH, ++ path, strlen(path)); ++ ++ get_msg(conn, msg); ++ if ((r = sshbuf_get_u8(msg, &type)) != 0 || ++ (r = sshbuf_get_u32(msg, &id)) != 0) ++ fatal_fr(r, "parse"); ++ ++ if (id != expected_id) ++ fatal("ID mismatch (%u != %u)", id, expected_id); ++ ++ if (type == SSH2_FXP_STATUS) { ++ u_int status; ++ ++ if ((r = sshbuf_get_u32(msg, &status)) != 0) ++ fatal_fr(r, "parse status"); ++ error("Couldn't canonicalize: %s", fx2txt(status)); ++ sshbuf_free(msg); ++ return NULL; ++ } ++ } else { ++ error("Couldn't canonicalize: %s", fx2txt(status)); ++ sshbuf_free(msg); ++ return NULL; ++ } + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", + SSH2_FXP_NAME, type); +@@ -1039,9 +1067,9 @@ do_realpath_expand(struct sftp_conn *con + } + + char * +-do_realpath(struct sftp_conn *conn, const char *path) ++do_realpath(struct sftp_conn *conn, const char *path, int create_dir) + { +- return do_realpath_expand(conn, path, 0); ++ return do_realpath_expand(conn, path, 0, create_dir); + } + + int +@@ -1055,9 +1083,9 @@ do_expand_path(struct sftp_conn *conn, c + { + if (!can_expand_path(conn)) { + debug3_f("no server support, fallback to realpath"); +- return do_realpath_expand(conn, path, 0); ++ return do_realpath_expand(conn, path, 0, 0); + } +- return do_realpath_expand(conn, path, 1); ++ return do_realpath_expand(conn, path, 1, 0); + } + + int +@@ -1807,7 +1835,7 @@ download_dir(struct sftp_conn *conn, con + char *src_canon; + int ret; + +- if ((src_canon = do_realpath(conn, src)) == NULL) { ++ if ((src_canon = do_realpath(conn, src, 0)) == NULL) { + error("Unable to canonicalize path \"%s\"", src); + return -1; + } +@@ -2115,12 +2143,12 @@ upload_dir_internal(struct sftp_conn *co + int + upload_dir(struct sftp_conn *conn, const char *src, const char *dst, + int preserve_flag, int print_flag, int resume, int fsync_flag, +- int follow_link_flag) ++ int follow_link_flag, int create_dir) + { + char *dst_canon; + int ret; + +- if ((dst_canon = do_realpath(conn, dst)) == NULL) { ++ if ((dst_canon = do_realpath(conn, dst, create_dir)) == NULL) { + error("Unable to canonicalize path \"%s\"", dst); + return -1; + } +@@ -2557,7 +2585,7 @@ crossload_dir(struct sftp_conn *from, st + char *from_path_canon; + int ret; + +- if ((from_path_canon = do_realpath(from, from_path)) == NULL) { ++ if ((from_path_canon = do_realpath(from, from_path, 0)) == NULL) { + error("Unable to canonicalize path \"%s\"", from_path); + return -1; + } +diff -up openssh-8.7p1/sftp-client.h.scp-sftpdirs openssh-8.7p1/sftp-client.h +--- openssh-8.7p1/sftp-client.h.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/sftp-client.h 2022-02-07 12:31:07.410740433 +0100 +@@ -111,7 +111,7 @@ int do_fsetstat(struct sftp_conn *, cons + int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a); + + /* Canonicalise 'path' - caller must free result */ +-char *do_realpath(struct sftp_conn *, const char *); ++char *do_realpath(struct sftp_conn *, const char *, int); + + /* Canonicalisation with tilde expansion (requires server extension) */ + char *do_expand_path(struct sftp_conn *, const char *); +@@ -159,7 +159,7 @@ int do_upload(struct sftp_conn *, const + * times if 'pflag' is set + */ + int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int, +- int, int); ++ int, int, int); + + /* + * Download a 'from_path' from the 'from' connection and upload it to +diff -up openssh-8.7p1/sftp.c.scp-sftpdirs openssh-8.7p1/sftp.c +--- openssh-8.7p1/sftp.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/sftp.c 2022-02-07 12:31:07.411740442 +0100 +@@ -760,7 +760,7 @@ process_put(struct sftp_conn *conn, cons + if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { + if (upload_dir(conn, g.gl_pathv[i], abs_dst, + pflag || global_pflag, 1, resume, +- fflag || global_fflag, 0) == -1) ++ fflag || global_fflag, 0, 0) == -1) + err = -1; + } else { + if (do_upload(conn, g.gl_pathv[i], abs_dst, +@@ -1577,7 +1577,7 @@ parse_dispatch_command(struct sftp_conn + if (path1 == NULL || *path1 == '\0') + path1 = xstrdup(startdir); + path1 = make_absolute(path1, *pwd); +- if ((tmp = do_realpath(conn, path1)) == NULL) { ++ if ((tmp = do_realpath(conn, path1, 0)) == NULL) { + err = 1; + break; + } +@@ -2160,7 +2160,7 @@ interactive_loop(struct sftp_conn *conn, + } + #endif /* USE_LIBEDIT */ + +- remote_path = do_realpath(conn, "."); ++ remote_path = do_realpath(conn, ".", 0); + if (remote_path == NULL) + fatal("Need cwd"); + startdir = xstrdup(remote_path); diff --git a/SOURCES/openssh-8.7p1-sftpscp-dir-create.patch b/SOURCES/openssh-8.7p1-sftpscp-dir-create.patch new file mode 100644 index 0000000..a549170 --- /dev/null +++ b/SOURCES/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/SPECS/openssh.spec b/SPECS/openssh.spec index 8a00742..432148e 100644 --- a/SPECS/openssh.spec +++ b/SPECS/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,17 @@ 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 and some more minor fixes +# upstream commits: +# ba61123eef9c6356d438c90c1199a57a0d7bcb0a +# 63670d4e9030bcee490d5a9cce561373ac5b3b23 +# ac7c9ec894ed0825d04ef69c55babb49bab1d32e +Patch980: openssh-8.7p1-sftpscp-dir-create.patch +# Workaround for lack of sftp_realpath in older versions of RHEL +# https://bugzilla.redhat.com/show_bug.cgi?id=2038854 +# https://github.com/openssh/openssh-portable/pull/299 +# downstream only +Patch981: openssh-8.7p1-recursive-scp.patch Patch1000: openssh-8.7p1-minimize-sha1-use.patch @@ -382,6 +393,8 @@ popd %patch977 -p1 -b .kill-scp %patch978 -p1 -b .cve-2021-41617 %patch979 -p1 -b .find-principals +%patch980 -p1 -b .sftpdirs +%patch981 -p1 -b .scp-sftpdirs %patch200 -p1 -b .audit %patch201 -p1 -b .audit-race @@ -668,6 +681,12 @@ test -f %{sysconfig_anaconda} && \ %endif %changelog +* Mon Feb 07 2022 Dmitry Belyavskiy - 8.7p1-7 +- Switch to SFTP protocol in scp utility by default - upstream fixes + Related: rhbz#2001002 +- Workaround for RHEL 8 incompatibility in scp utility in SFTP mode + Related: rhbz#2038854 + * Tue Dec 21 2021 Dmitry Belyavskiy - 8.7p1-6 - Fix SSH connection to localhost not possible in FIPS Related: rhbz#2031868