]> Sergey Matveev's repositories - nnn.git/commitdiff
add shell_escape() to properly escape filenames fed to shell
authorNRK <nrk@disroot.org>
Tue, 21 Mar 2023 10:59:25 +0000 (16:59 +0600)
committerNRK <nrk@disroot.org>
Wed, 22 Mar 2023 04:09:39 +0000 (10:09 +0600)
Fixes: https://github.com/jarun/nnn/issues/1615
src/nnn.c

index 491749ab74333e92ee84d26802d34a93f01d64f0..6c32f8a101412342b7af733c566890b166be34b6 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -1299,6 +1299,42 @@ static char *abspath(const char *filepath, char *cwd, char *buf)
        return resolved_path;
 }
 
+/* wraps the argument in single quotes so it can be safely fed to shell */
+static bool shell_escape(char *output, size_t outlen, const char *s)
+{
+       size_t n = xstrlen(s), w = 0;
+
+       if (s == output) {
+               DPRINTF_S("s == output");
+               return FALSE;
+       }
+
+       output[w++] = '\''; /* begin single quote */
+       for (size_t r = 0; r < n; ++r) {
+               /* potentially too big: 4 for the single quote case, 2 from
+                * outside the loop */
+               if (w + 6 >= outlen)
+                       return FALSE;
+
+               switch (s[r]) {
+               /* the only thing that has special meaning inside single
+                * quotes are single quotes themselves. */
+               case '\'':
+                       output[w++] = '\''; /* end single quote */
+                       output[w++] = '\\'; /* put \' so it's treated as literal single quote */
+                       output[w++] = '\'';
+                       output[w++] = '\''; /* start single quoting again */
+                       break;
+               default:
+                       output[w++] = s[r];
+                       break;
+               }
+       }
+       output[w++] = '\''; /* end single quote */
+       output[w++] = '\0'; /* nul terminator */
+       return TRUE;
+}
+
 static bool set_tilde_in_path(char *path)
 {
        if (is_prefix(path, home, homelen)) {
@@ -2779,8 +2815,8 @@ static void write_lastdir(const char *curpath, const char *outfile)
                        ? (tilde ? g_buf : outfile)
                        : cfgpath, O_CREAT | O_WRONLY | O_TRUNC, S_IWUSR | S_IRUSR);
 
-       if (fd != -1) {
-               dprintf(fd, "cd \"%s\"", curpath);
+       if (fd != -1 && shell_escape(g_buf, sizeof(g_buf), curpath)) {
+               dprintf(fd, "cd %s", g_buf);
                close(fd);
        }
 }