From e353185754db4dc8e27e83fcb7d6001c242cccb9 Mon Sep 17 00:00:00 2001 From: djm Date: Sun, 8 May 2022 22:32:36 +0000 Subject: [PATCH] When performing operations that glob(3) a remote path, ensure that the implicit working directory used to construct that path escapes glob(3) characters. This prevents glob characters from being processed in places they shouldn't, e.g. "cd /tmp/a*/", "get *.txt" should have the get operation treat the path "/tmp/a*" literally and not attempt to expand it. Reported by Lusia Kundel; ok markus@ --- usr.bin/ssh/sftp.c | 49 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/usr.bin/ssh/sftp.c b/usr.bin/ssh/sftp.c index ad66df93d0e..e47adf5d09f 100644 --- a/usr.bin/ssh/sftp.c +++ b/usr.bin/ssh/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.214 2022/03/31 03:07:03 djm Exp $ */ +/* $OpenBSD: sftp.c,v 1.215 2022/05/08 22:32:36 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -580,18 +580,45 @@ parse_no_flags(const char *cmd, char **argv, int argc) return optind; } +static char * +escape_glob(const char *s) +{ + size_t i, o, len; + char *ret; + + len = strlen(s); + ret = xcalloc(2, len + 1); + for (i = o = 0; i < len; i++) { + if (strchr("[]?*\\", s[i]) != NULL) + ret[o++] = '\\'; + ret[o++] = s[i]; + } + ret[o++] = '\0'; + return ret; +} + +static char * +make_absolute_pwd_glob(const char *p, const char *pwd) +{ + char *ret, *escpwd; + + escpwd = escape_glob(pwd); + if (p == NULL) + return escpwd; + ret = make_absolute(xstrdup(p), escpwd); + free(escpwd); + return ret; +} + static int process_get(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd, int pflag, int rflag, int resume, int fflag) { - char *abs_src = NULL; - char *abs_dst = NULL; + char *filename, *abs_src = NULL, *abs_dst = NULL, *tmp = NULL; glob_t g; - char *filename, *tmp=NULL; int i, r, err = 0; - abs_src = xstrdup(src); - abs_src = make_absolute(abs_src, pwd); + abs_src = make_absolute_pwd_glob(src, pwd); memset(&g, 0, sizeof(g)); debug3("Looking up %s", abs_src); @@ -1538,7 +1565,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); break; case I_RM: - path1 = make_absolute(path1, *pwd); + path1 = make_absolute_pwd_glob(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!quiet) @@ -1599,7 +1626,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, if (!path_absolute(path1)) tmp = *pwd; - path1 = make_absolute(path1, *pwd); + path1 = make_absolute_pwd_glob(path1, *pwd); err = do_globbed_ls(conn, path1, tmp, lflag); break; case I_DF: @@ -1639,7 +1666,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, printf("Local umask: %03lo\n", n_arg); break; case I_CHMOD: - path1 = make_absolute(path1, *pwd); + path1 = make_absolute_pwd_glob(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = n_arg; @@ -1656,7 +1683,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, break; case I_CHOWN: case I_CHGRP: - path1 = make_absolute(path1, *pwd); + path1 = make_absolute_pwd_glob(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!(aa = (hflag ? do_lstat : do_stat)(conn, @@ -1930,7 +1957,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, memset(&g, 0, sizeof(g)); if (remote != LOCAL) { - tmp = make_absolute(tmp, remote_path); + tmp = make_absolute_pwd_glob(tmp, remote_path); remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); } else glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); -- 2.20.1