Ping?

Christian Heckendorf wrote:

> Several sftp(1) commands will fail if the remote pwd contains glob(3)
> meta characters. This is due to glob being called on the concatenated
> pwd and command argument in order to generate a file list to operate
> on. However, the pwd is not escaped before calling glob, so glob
> will offer no useful results and sftp will error "not found".
> 
> The following commands will not work in some or all conditions when
> called from one of these meta character directories: get, rm, chmod,
> chown, chgrp, ls, and tab-completions.
> 
> The diff below extends the make_absolute() function to optionally
> add escape characters to the pwd before generating the absolute
> path version of the argument which will be sent to glob. I'd be
> happy to rewrite if a different solution is preferable.
> 
> --
> Christian
> 
> 
> Index: sftp.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/ssh/sftp.c,v
> retrieving revision 1.171
> diff -u -p -r1.171 sftp.c
> --- sftp.c    20 Aug 2015 22:32:42 -0000      1.171
> +++ sftp.c    27 Dec 2015 21:03:08 -0000
> @@ -154,6 +154,10 @@ struct CMD {
>  #define REMOTE       1
>  #define LOCAL        2
>  
> +/* Options for handling glob meta chars in pwd */
> +#define NOESCAPE_META        0
> +#define ESCAPE_META  1
> +
>  static const struct CMD cmds[] = {
>       { "bye",        I_QUIT,         NOARGS  },
>       { "cd",         I_CHDIR,        REMOTE  },
> @@ -330,14 +334,63 @@ path_strip(char *path, char *strip)
>       return (xstrdup(path));
>  }
>  
> +/* Escape any glob(3) meta characters in the pwd */
>  static char *
> -make_absolute(char *p, char *pwd)
> +escape_glob_meta(char *pwd)
>  {
> -     char *abs_str;
> +     size_t i, j, expand_len, len;
> +     char *esc_pwd;
> +
> +     len = strlen(pwd);
> +
> +     expand_len = 0;
> +     for (i = 0; i < len; i++) {
> +             switch (pwd[i]) {
> +             case '*':
> +             case '?':
> +             case '[':
> +             case '\\':
> +                     expand_len++;
> +                     break;
> +             }
> +     }
> +
> +     esc_pwd = xmalloc(len + expand_len + 1);
> +
> +     for (i = j = 0; i < len; i++) {
> +             switch (pwd[i]) {
> +             case '*':
> +             case '?':
> +             case '[':
> +             case '\\':
> +                     esc_pwd[j++] = '\\';
> +                     /* FALLTHROUGH */
> +             default:
> +                     esc_pwd[j++] = pwd[i];
> +                     break;
> +             }
> +     }
> +     esc_pwd[j] = 0;
> +
> +     return esc_pwd;
> +}
> +
> +static char *
> +make_absolute(char *p, char *pwd, int escopt)
> +{
> +     char *abs_str, *tmp_pwd;
>  
>       /* Derelativise */
>       if (p && p[0] != '/') {
> -             abs_str = path_append(pwd, p);
> +             if(escopt == ESCAPE_META)
> +                     tmp_pwd = escape_glob_meta(pwd);
> +             else
> +                     tmp_pwd = pwd;
> +
> +             abs_str = path_append(tmp_pwd, p);
> +
> +             if(escopt == ESCAPE_META)
> +                     free(tmp_pwd);
>               free(p);
>               return(abs_str);
>       } else
> @@ -573,7 +626,7 @@ process_get(struct sftp_conn *conn, char
>       int i, r, err = 0;
>  
>       abs_src = xstrdup(src);
> -     abs_src = make_absolute(abs_src, pwd);
> +     abs_src = make_absolute(abs_src, pwd, ESCAPE_META);
>       memset(&g, 0, sizeof(g));
>  
>       debug3("Looking up %s", abs_src);
> @@ -660,7 +713,7 @@ process_put(struct sftp_conn *conn, char
>  
>       if (dst) {
>               tmp_dst = xstrdup(dst);
> -             tmp_dst = make_absolute(tmp_dst, pwd);
> +             tmp_dst = make_absolute(tmp_dst, pwd, NOESCAPE_META);
>       }
>  
>       memset(&g, 0, sizeof(g));
> @@ -707,7 +760,8 @@ process_put(struct sftp_conn *conn, char
>               } else if (tmp_dst) {
>                       abs_dst = path_append(tmp_dst, filename);
>               } else {
> -                     abs_dst = make_absolute(xstrdup(filename), pwd);
> +                     abs_dst = make_absolute(xstrdup(filename), pwd,
> +                         NOESCAPE_META);
>               }
>               free(tmp);
>  
> @@ -1417,20 +1471,20 @@ parse_dispatch_command(struct sftp_conn 
>                   rflag, aflag, fflag);
>               break;
>       case I_RENAME:
> -             path1 = make_absolute(path1, *pwd);
> -             path2 = make_absolute(path2, *pwd);
> +             path1 = make_absolute(path1, *pwd, NOESCAPE_META);
> +             path2 = make_absolute(path2, *pwd, NOESCAPE_META);
>               err = do_rename(conn, path1, path2, lflag);
>               break;
>       case I_SYMLINK:
>               sflag = 1;
>       case I_LINK:
>               if (!sflag)
> -                     path1 = make_absolute(path1, *pwd);
> -             path2 = make_absolute(path2, *pwd);
> +                     path1 = make_absolute(path1, *pwd, NOESCAPE_META);
> +             path2 = make_absolute(path2, *pwd, NOESCAPE_META);
>               err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
>               break;
>       case I_RM:
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, ESCAPE_META);
>               remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
>               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
>                       if (!quiet)
> @@ -1441,18 +1495,18 @@ parse_dispatch_command(struct sftp_conn 
>               }
>               break;
>       case I_MKDIR:
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, NOESCAPE_META);
>               attrib_clear(&a);
>               a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
>               a.perm = 0777;
>               err = do_mkdir(conn, path1, &a, 1);
>               break;
>       case I_RMDIR:
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, NOESCAPE_META);
>               err = do_rmdir(conn, path1);
>               break;
>       case I_CHDIR:
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, NOESCAPE_META);
>               if ((tmp = do_realpath(conn, path1)) == NULL) {
>                       err = 1;
>                       break;
> @@ -1489,14 +1543,14 @@ parse_dispatch_command(struct sftp_conn 
>               if (*path1 != '/')
>                       tmp = *pwd;
>  
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, ESCAPE_META);
>               err = do_globbed_ls(conn, path1, tmp, lflag);
>               break;
>       case I_DF:
>               /* Default to current directory if no path specified */
>               if (path1 == NULL)
>                       path1 = xstrdup(*pwd);
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, NOESCAPE_META);
>               err = do_df(conn, path1, hflag, iflag);
>               break;
>       case I_LCHDIR:
> @@ -1527,7 +1581,7 @@ parse_dispatch_command(struct sftp_conn 
>               printf("Local umask: %03lo\n", n_arg);
>               break;
>       case I_CHMOD:
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, ESCAPE_META);
>               attrib_clear(&a);
>               a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
>               a.perm = n_arg;
> @@ -1542,7 +1596,7 @@ parse_dispatch_command(struct sftp_conn 
>               break;
>       case I_CHOWN:
>       case I_CHGRP:
> -             path1 = make_absolute(path1, *pwd);
> +             path1 = make_absolute(path1, *pwd, ESCAPE_META);
>               remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
>               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
>                       if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
> @@ -1814,7 +1868,7 @@ complete_match(EditLine *el, struct sftp
>  
>       memset(&g, 0, sizeof(g));
>       if (remote != LOCAL) {
> -             tmp = make_absolute(tmp, remote_path);
> +             tmp = make_absolute(tmp, remote_path, ESCAPE_META);
>               remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
>       } else
>               glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
> @@ -2032,7 +2086,7 @@ interactive_loop(struct sftp_conn *conn,
>  
>       if (file1 != NULL) {
>               dir = xstrdup(file1);
> -             dir = make_absolute(dir, remote_path);
> +             dir = make_absolute(dir, remote_path, NOESCAPE_META);
>  
>               if (remote_is_dir(conn, dir) && file2 == NULL) {
>                       if (!quiet)
> @@ -2046,6 +2100,10 @@ interactive_loop(struct sftp_conn *conn,
>                               return (-1);
>                       }
>               } else {
> +                     free(dir);
> +                     dir = xstrdup(file1);
> +                     dir = make_absolute(dir, remote_path, ESCAPE_META);
> +
>                       /* XXX this is wrong wrt quoting */
>                       snprintf(cmd, sizeof cmd, "get%s %s%s%s",
>                           global_aflag ? " -a" : "", dir,
> 

Reply via email to