]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: When performing operations that glob(3) a remote path, ensure
authordjm@openbsd.org <djm@openbsd.org>
Sun, 8 May 2022 22:32:36 +0000 (22:32 +0000)
committerDamien Miller <djm@mindrot.org>
Sun, 8 May 2022 22:33:59 +0000 (08:33 +1000)
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@

OpenBSD-Commit-ID: 4f647f58482cbad3d58b1eab7f6a1691433deeef

sftp.c

diff --git a/sftp.c b/sftp.c
index 4efc025a504cd7b624a612c30d718eb214babc23..387132e50ba2d3379173d45278f2fbe62b9290eb 100644 (file)
--- a/sftp.c
+++ b/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 <djm@openbsd.org>
  *
@@ -601,18 +601,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);
@@ -1565,7 +1592,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)
@@ -1626,7 +1653,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:
@@ -1666,7 +1693,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;
@@ -1683,7 +1710,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,
@@ -1958,7 +1985,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);