Bug 705866: Move accelerator files.
authorRobin Watts <[email protected]>
Thu, 23 Mar 2023 11:42:13 +0000 (11:42 +0000)
committerRobin Watts <[email protected]>
Thu, 30 Mar 2023 18:18:32 +0000 (19:18 +0100)
Currently, MuPDF puts accelerator files into the directory given
by the environment variables for TEMP, or TMP, or failing that
'/var/tmp' or '/tmp/'.

It has been suggested that this is a security risk because people
can cause access to block by using a fifo.

On windows machines, we try to save in %USERPROFILE%\.config\mupdf.
If USERPROFILE is not defined, we drop back to TEMP and TMP as
before - these are generally user specific on modern Windows boxes.

On other machines, we try $XDG_CACHE_HOME/mupdf, or $HOME/.cache/mupdf.

platform/gl/gl-main.c
platform/x11/pdfapp.c
source/tools/mudraw.c

index 3e361fe59bb2009a388630142f1abaa9e494bccb..5eefd005ef59f8bc366a4942b6e5293a71146b16 100644 (file)
@@ -496,19 +496,73 @@ static void save_history(void)
        js_freestate(J);
 }
 
-static int convert_to_accel_path(char outname[], char *absname, size_t len)
+static int
+fz_mkdir(char *path)
+{
+#ifdef _WIN32
+       int ret;
+       wchar_t *wpath = fz_wchar_from_utf8(path);
+
+       if (wpath == NULL)
+               return -1;
+
+       ret = _wmkdir(wpath);
+
+       free(wpath);
+
+       return ret;
+#else
+       return mkdir(path);
+#endif
+}
+
+static int create_accel_path(char outname[], size_t len, int create, const char *absname, ...)
+{
+       va_list args;
+       char *s = outname;
+       size_t z, remain = len;
+       char *arg;
+
+       va_start(args, absname);
+
+       while ((arg = va_arg(args, char *)) != NULL)
+       {
+               z = fz_snprintf(s, remain, "%s", arg);
+               if (z+1 > remain)
+                       goto fail; /* won't fit */
+
+               if (create)
+                       fz_mkdir(outname);
+               if (!fz_is_directory(ctx, outname))
+                       goto fail; /* directory creation failed, or that dir doesn't exist! */
+#ifdef _WIN32
+               s[z] = '\\';
+#else
+               s[z] = '/';
+#endif
+               s[z+1] = 0;
+               s += z+1;
+               remain -= z+1;
+       }
+
+       if (fz_snprintf(s, remain, "%s.accel", absname) >= remain)
+               goto fail; /* won't fit */
+
+       va_end(args);
+
+       return 1;
+
+fail:
+       va_end(args);
+
+       return 0;
+}
+
+static int convert_to_accel_path(char outname[], char *absname, size_t len, int create)
 {
        char *tmpdir;
        char *s;
 
-       tmpdir = getenv("TEMP");
-       if (!tmpdir)
-               tmpdir = getenv("TMP");
-       if (!tmpdir)
-               tmpdir = "/var/tmp";
-       if (!fz_is_directory(ctx, tmpdir))
-               tmpdir = "/tmp";
-
        if (absname[0] == '/' || absname[0] == '\\')
                ++absname;
 
@@ -519,17 +573,34 @@ static int convert_to_accel_path(char outname[], char *absname, size_t len)
                ++s;
        }
 
-       if (fz_snprintf(outname, len, "%s/%s.accel", tmpdir, absname) >= len)
-               return 0;
-       return 1;
+#ifdef _WIN32
+       tmpdir = getenv("USERPROFILE");
+       if (tmpdir && create_accel_path(outname, len, create, absname, tmpdir, ".config", "mupdf", NULL))
+               return 1; /* OK! */
+       /* TEMP and TMP are user-specific on modern windows. */
+       tmpdir = getenv("TEMP");
+       if (tmpdir && create_accel_path(outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+       tmpdir = getenv("TMP");
+       if (tmpdir && create_accel_path(outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+#else
+       tmpdir = getenv("XDG_CACHE_HOME");
+       if (tmpdir && create_accel_path(outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+       tmpdir = getenv("HOME");
+       if (tmpdir && create_accel_path(outname, len, create, absname, tmpdir, ".cache", "mupdf", NULL))
+               return 1; /* OK! */
+#endif
+       return 0; /* Fail */
 }
 
-static int get_accelerator_filename(char outname[], size_t len)
+static int get_accelerator_filename(char outname[], size_t len, int create)
 {
        char absname[PATH_MAX];
        if (!fz_realpath(filename, absname))
                return 0;
-       if (!convert_to_accel_path(outname, absname, len))
+       if (!convert_to_accel_path(outname, absname, len, create))
                return 0;
        return 1;
 }
@@ -542,7 +613,7 @@ static void save_accelerator(void)
                return;
        if (!fz_document_supports_accelerator(ctx, doc))
                return;
-       if (!get_accelerator_filename(absname, sizeof(absname)))
+       if (!get_accelerator_filename(absname, sizeof(absname), 1))
                return;
 
        fz_save_accelerator(ctx, doc, absname);
@@ -1714,7 +1785,7 @@ static void load_document(void)
        fz_drop_document(ctx, doc);
 
        /* If there was an accelerator to load, what would it be called? */
-       if (get_accelerator_filename(accelpath, sizeof(accelpath)))
+       if (get_accelerator_filename(accelpath, sizeof(accelpath), 0))
        {
                /* Check whether that file exists, and isn't older than
                 * the document. */
index f98e7b37847bc2cc16a934712e0c83ef3022ac4d..4042f90109de7879f463528f7c350f5b5461cb56 100644 (file)
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #endif
 
-static int convert_to_accel_path(fz_context *ctx, char outname[], char *absname, size_t len)
+static int
+fz_mkdir(char *path)
+{
+#ifdef _WIN32
+       int ret;
+       wchar_t *wpath = fz_wchar_from_utf8(path);
+
+       if (wpath == NULL)
+               return -1;
+
+       ret = _wmkdir(wpath);
+
+       free(wpath);
+
+       return ret;
+#else
+       return mkdir(path);
+#endif
+}
+
+static int create_accel_path(fz_context *ctx, char outname[], size_t len, int create, const char *absname, ...)
+{
+       va_list args;
+       char *s = outname;
+       size_t z, remain = len;
+       char *arg;
+
+       va_start(args, absname);
+
+       while ((arg = va_arg(args, char *)) != NULL)
+       {
+               z = fz_snprintf(s, remain, "%s", arg);
+               if (z+1 > remain)
+                       goto fail; /* won't fit */
+
+               if (create)
+                       fz_mkdir(outname);
+               if (!fz_is_directory(ctx, outname))
+                       goto fail; /* directory creation failed, or that dir doesn't exist! */
+#ifdef _WIN32
+               s[z] = '\\';
+#else
+               s[z] = '/';
+#endif
+               s[z+1] = 0;
+               s += z+1;
+               remain -= z+1;
+       }
+
+       if (fz_snprintf(s, remain, "%s.accel", absname) >= remain)
+               goto fail; /* won't fit */
+
+       va_end(args);
+
+       return 1;
+
+fail:
+       va_end(args);
+
+       return 0;
+}
+
+static int convert_to_accel_path(fz_context *ctx, char outname[], char *absname, size_t len, int create)
 {
        char *tmpdir;
        char *s;
 
-       tmpdir = getenv("TEMP");
-       if (!tmpdir)
-               tmpdir = getenv("TMP");
-       if (!tmpdir)
-               tmpdir = "/var/tmp";
-       if (!fz_is_directory(ctx, tmpdir))
-               tmpdir = "/tmp";
-
        if (absname[0] == '/' || absname[0] == '\\')
                ++absname;
 
@@ -47,17 +101,34 @@ static int convert_to_accel_path(fz_context *ctx, char outname[], char *absname,
                ++s;
        }
 
-       if (fz_snprintf(outname, len, "%s/%s.accel", tmpdir, absname) >= len)
-               return 0;
-       return 1;
+#ifdef _WIN32
+       tmpdir = getenv("USERPROFILE");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, ".config", "mupdf", NULL))
+               return 1; /* OK! */
+       /* TEMP and TMP are user-specific on modern windows. */
+       tmpdir = getenv("TEMP");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+       tmpdir = getenv("TMP");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+#else
+       tmpdir = getenv("XDG_CACHE_HOME");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+       tmpdir = getenv("HOME");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, ".cache", "mupdf", NULL))
+               return 1; /* OK! */
+#endif
+       return 0; /* Fail */
 }
 
-static int get_accelerator_filename(fz_context *ctx, char outname[], size_t len, const char *filename)
+static int get_accelerator_filename(fz_context *ctx, char outname[], size_t len, const char *filename, int create)
 {
        char absname[PATH_MAX];
        if (!fz_realpath(filename, absname))
                return 0;
-       if (!convert_to_accel_path(ctx, outname, absname, len))
+       if (!convert_to_accel_path(ctx, outname, absname, len, create))
                return 0;
        return 1;
 }
@@ -70,7 +141,7 @@ static void save_accelerator(fz_context *ctx, fz_document *doc, const char *file
                return;
        if (!fz_document_supports_accelerator(ctx, doc))
                return;
-       if (!get_accelerator_filename(ctx, absname, sizeof(absname), filename))
+       if (!get_accelerator_filename(ctx, absname, sizeof(absname), filename, 1))
                return;
 
        fz_save_accelerator(ctx, doc, absname);
@@ -425,7 +496,7 @@ void pdfapp_open_progressive(pdfapp_t *app, char *filename, int reload, int kbps
                        time_t dtime;
 
                        /* If there was an accelerator to load, what would it be called? */
-                       if (get_accelerator_filename(ctx, accelpath, sizeof(accelpath), filename))
+                       if (get_accelerator_filename(ctx, accelpath, sizeof(accelpath), filename, 0))
                        {
                                /* Check whether that file exists, and isn't older than
                                 * the document. */
index 1237694331eeb97ea2bb97d0ec1e732860a257b0..f68aa8972bb38ccd528f1781f358c2f5ecb168a3 100644 (file)
@@ -1884,19 +1884,73 @@ static void apply_layer_config(fz_context *ctx, fz_document *doc, const char *lc
 #endif
 }
 
-static int convert_to_accel_path(fz_context *ctx, char outname[], char *absname, size_t len)
+static int
+fz_mkdir(char *path)
+{
+#ifdef _WIN32
+       int ret;
+       wchar_t *wpath = fz_wchar_from_utf8(path);
+
+       if (wpath == NULL)
+               return -1;
+
+       ret = _wmkdir(wpath);
+
+       free(wpath);
+
+       return ret;
+#else
+       return mkdir(path);
+#endif
+}
+
+static int create_accel_path(fz_context *ctx, char outname[], size_t len, int create, const char *absname, ...)
+{
+       va_list args;
+       char *s = outname;
+       size_t z, remain = len;
+       char *arg;
+
+       va_start(args, absname);
+
+       while ((arg = va_arg(args, char *)) != NULL)
+       {
+               z = fz_snprintf(s, remain, "%s", arg);
+               if (z+1 > remain)
+                       goto fail; /* won't fit */
+
+               if (create)
+                       fz_mkdir(outname);
+               if (!fz_is_directory(ctx, outname))
+                       goto fail; /* directory creation failed, or that dir doesn't exist! */
+#ifdef _WIN32
+               s[z] = '\\';
+#else
+               s[z] = '/';
+#endif
+               s[z+1] = 0;
+               s += z+1;
+               remain -= z+1;
+       }
+
+       if (fz_snprintf(s, remain, "%s.accel", absname) >= remain)
+               goto fail; /* won't fit */
+
+       va_end(args);
+
+       return 1;
+
+fail:
+       va_end(args);
+
+       return 0;
+}
+
+static int convert_to_accel_path(fz_context *ctx, char outname[], char *absname, size_t len, int create)
 {
        char *tmpdir;
        char *s;
 
-       tmpdir = getenv("TEMP");
-       if (!tmpdir)
-               tmpdir = getenv("TMP");
-       if (!tmpdir)
-               tmpdir = "/var/tmp";
-       if (!fz_is_directory(ctx, tmpdir))
-               tmpdir = "/tmp";
-
        if (absname[0] == '/' || absname[0] == '\\')
                ++absname;
 
@@ -1907,17 +1961,34 @@ static int convert_to_accel_path(fz_context *ctx, char outname[], char *absname,
                ++s;
        }
 
-       if (fz_snprintf(outname, len, "%s/%s.accel", tmpdir, absname) >= len)
-               return 0;
-       return 1;
+#ifdef _WIN32
+       tmpdir = getenv("USERPROFILE");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, ".config", "mupdf", NULL))
+               return 1; /* OK! */
+       /* TEMP and TMP are user-specific on modern windows. */
+       tmpdir = getenv("TEMP");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+       tmpdir = getenv("TMP");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+#else
+       tmpdir = getenv("XDG_CACHE_HOME");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, "mupdf", NULL))
+               return 1; /* OK! */
+       tmpdir = getenv("HOME");
+       if (tmpdir && create_accel_path(ctx, outname, len, create, absname, tmpdir, ".cache", "mupdf", NULL))
+               return 1; /* OK! */
+#endif
+       return 0; /* Fail */
 }
 
-static int get_accelerator_filename(fz_context *ctx, char outname[], size_t len, const char *fname)
+static int get_accelerator_filename(fz_context *ctx, char outname[], size_t len, const char *filename, int create)
 {
        char absname[PATH_MAX];
-       if (!fz_realpath(fname, absname))
+       if (!fz_realpath(filename, absname))
                return 0;
-       if (!convert_to_accel_path(ctx, outname, absname, len))
+       if (!convert_to_accel_path(ctx, outname, absname, len, create))
                return 0;
        return 1;
 }
@@ -1930,7 +2001,7 @@ static void save_accelerator(fz_context *ctx, fz_document *doc, const char *fnam
                return;
        if (!fz_document_supports_accelerator(ctx, doc))
                return;
-       if (!get_accelerator_filename(ctx, absname, sizeof(absname), fname))
+       if (!get_accelerator_filename(ctx, absname, sizeof(absname), fname, 1))
                return;
 
        fz_save_accelerator(ctx, doc, absname);
@@ -2447,7 +2518,7 @@ int mudraw_main(int argc, char **argv)
                                        if (!useaccel)
                                                accel = NULL;
                                        /* If there was an accelerator to load, what would it be called? */
-                                       else if (get_accelerator_filename(ctx, accelpath, sizeof(accelpath), filename))
+                                       else if (get_accelerator_filename(ctx, accelpath, sizeof(accelpath), filename, 0))
                                        {
                                                /* Check whether that file exists, and isn't older than
                                                 * the document. */