Restricted x11 no-prompt file access to current dir or restricted path.
authorDavid Griffith <dave@661.org>
Sun, 7 May 2023 18:38:01 +0000 (11:38 -0700)
committerDavid Griffith <dave@661.org>
Sun, 7 May 2023 18:42:03 +0000 (11:42 -0700)
This necessarily required implementing the -R option (restricted read/write).

doc/xfrotz.6
src/x11/x_init.c
src/x11/x_input.c

index 0b72b286e6ae9b0957766b2eb56c7da2856b90dd..31e7309c67ffdff115b989eb167583b36bf23182 100644 (file)
@@ -95,6 +95,22 @@ Enable branching on the
 .I @piracy
 opcode.  This opcode is seldom used.
 .TP
+.B \-R <path>
+(class \fBRestricted\fP, name \fBrestricted\fP)
+Restricted read/write.  Reading and writing files will be restricted
+only to the provided path. Ordinarily xfrotz will write or read its
+saves, transcripts, and move recordings in whatever path or directory
+the user provides when the
+.B SAVE,
+.B SCRIPT,
+or
+.B RECORDING
+commands are given.  This can be undesirable if xfrotz is run in a
+restricted environment, by a front end, or by a chatbot.  This option will
+cause xfrotz to write or read only to the provided path and nowhere else.
+Then the controlling process can then watch that directory for changes
+and need not worry about someone scribbling or snooping who-knows-where.
+.TP
 .B \-rm <number>
 (class \fBMargin\fP, name \fBrightMargin\fP)
 Sets the right margin.
index 3695d64eaa991aad1fdf712d5e38908caa08670b..5b063f8dd743e0eb2431670314ad859fd2c1523e 100644 (file)
@@ -226,6 +226,7 @@ void os_process_arguments(int argc, char *argv[])
                {"+e", ".ignoreErrors", XrmoptionNoArg, (void *)"false"},
                {"-p", ".piracy", XrmoptionNoArg, (void *)"true"},
                {"+p", ".piracy", XrmoptionNoArg, (void *)"false"},
+               {"-R", ".restricted", XrmoptionSepArg, (void *)NULL},
                {"-t", ".tandy", XrmoptionNoArg, (void *)"true"},
                {"+t", ".tandy", XrmoptionNoArg, (void *)"false"},
                {"-u", ".undoSlots", XrmoptionSepArg, (void *)NULL},
@@ -271,6 +272,8 @@ void os_process_arguments(int argc, char *argv[])
                 &f_setup.ignore_errors},
                {".Piracy", ".piracy", parse_boolean,
                 &f_setup.piracy},
+               {".Restricted", ".restricted", parse_string,
+                &f_setup.restricted_path},
                {".Tandy", ".tandy", parse_boolean,
                 &f_setup.tandy},
                {".UndoSlots", ".undoSlots", parse_int,
index 79507541c0a2a1b2222debabbaa2ba8d6350441c..a5fa1cc7349925c69ec1de565d4110c82ceac00d 100644 (file)
@@ -29,6 +29,7 @@
 #define XK_MISCELLANY
 #include <X11/keysymdef.h>
 #undef XK_MISCELLANY
+#include <libgen.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
@@ -240,9 +241,15 @@ char *os_read_file_name(const char *default_name, int flag)
        int saved_replay = istream_replay;
        int saved_record = ostream_record;
        char file_name[FILENAME_MAX + 1];
+       int i;
+       char *tempname;
        zchar answer[4];
+       char path_separator[2];
        char *ext;
 
+       path_separator[0] = PATH_SEPARATOR;
+       path_separator[1] = 0;
+
        /* Turn off playback and recording temporarily */
        istream_replay = 0;
        ostream_record = 0;
@@ -258,8 +265,40 @@ char *os_read_file_name(const char *default_name, int flag)
        }
 
        /* Use the default name if nothing was typed */
-       if (file_name[0] == 0)
-               strcpy(file_name, default_name);
+       if (file_name[0] == 0) {
+               /* If FILE_NO_PROMPT, restrict to currect directory. */
+               /* If FILE_NO_PROMPT and using restricted path, then */
+               /*   nothing more needs to be done to restrict the   */
+               /*   file access there. */
+               if (flag == FILE_NO_PROMPT && f_setup.restricted_path == NULL) {
+                       tempname = basename((char *)default_name);
+                       strncpy(file_name, tempname, FILENAME_MAX);
+               } else
+                       strcpy(file_name, default_name);
+       }
+
+       /* If we're restricted to one directory, strip any leading path left
+        * over from a previous call to os_read_file_name(), then prepend
+        * the prescribed path to the filename.  Hostile leading paths won't
+        * get this far.  Instead we return failure a few lines above here if
+        * someone tries it.
+        */
+       if (f_setup.restricted_path != NULL) {
+               for (i = strlen(file_name); i > 0; i--) {
+                       if (file_name[i] == PATH_SEPARATOR) {
+                               i++;
+                               break;
+                       }
+               }
+               tempname = strdup(file_name + i);
+               strncpy(file_name, f_setup.restricted_path, FILENAME_MAX);
+
+               /* Make sure the final character is the path separator. */
+               if (file_name[strlen(file_name)-1] != PATH_SEPARATOR) {
+                       strncat(file_name, path_separator, FILENAME_MAX - strlen(file_name) - 2);
+               }
+               strncat(file_name, tempname, strlen(file_name) - strlen(tempname) - 1);
+       }
 
        if (flag == FILE_NO_PROMPT) {
                ext = strrchr(file_name, '.');