]> granicus.if.org Git - postgresql/commitdiff
Allow "-C variable" and "--describe-config" even to root users.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Apr 2014 02:03:35 +0000 (22:03 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 5 Apr 2014 02:03:35 +0000 (22:03 -0400)
There's no really compelling reason to refuse to do these read-only,
non-server-starting options as root, and there's at least one good
reason to allow -C: pg_ctl uses -C to find out the true data directory
location when pointed at a config-only directory.  On Windows, this is
done before dropping administrator privileges, which means that pg_ctl
fails for administrators if and only if a config-only layout is used.

Since the root-privilege check is done so early in startup, it's a bit
awkward to check for these switches.  Make the somewhat arbitrary
decision that we'll only skip the root check if -C is the first switch.
This is not just to make the code a bit simpler: it also guarantees that
we can't misinterpret a --boot mode switch.  (While AuxiliaryProcessMain
doesn't currently recognize any such switch, it might have one in the
future.)  This is no particular problem for pg_ctl, and since the whole
behavior is undocumented anyhow, it's not a documentation issue either.
(--describe-config only works as the first switch anyway, so this is
no restriction for that case either.)

Back-patch to 9.2 where pg_ctl first began to use -C.

MauMau, heavily edited by me

src/backend/main/main.c
src/bin/pg_ctl/pg_ctl.c

index a8ab4c4ab6f64056e64682aa2d19e7c29ef933a0..1b9cbd1de360816aea194b601c0442a60be2514c 100644 (file)
@@ -58,6 +58,8 @@ static void check_root(const char *progname);
 int
 main(int argc, char *argv[])
 {
+       bool            do_check_root = true;
+
        progname = get_progname(argv[0]);
 
        /*
@@ -151,7 +153,8 @@ main(int argc, char *argv[])
        unsetenv("LC_ALL");
 
        /*
-        * Catch standard options before doing much else
+        * Catch standard options before doing much else, in particular before we
+        * insist on not being root.
         */
        if (argc > 1)
        {
@@ -165,12 +168,29 @@ main(int argc, char *argv[])
                        puts("postgres (PostgreSQL) " PG_VERSION);
                        exit(0);
                }
+
+               /*
+                * In addition to the above, we allow "--describe-config" and "-C var"
+                * to be called by root.  This is reasonably safe since these are
+                * read-only activities.  The -C case is important because pg_ctl may
+                * try to invoke it while still holding administrator privileges on
+                * Windows.  Note that while -C can normally be in any argv position,
+                * if you wanna bypass the root check you gotta put it first.  This
+                * reduces the risk that we might misinterpret some other mode's -C
+                * switch as being the postmaster/postgres one.
+                */
+               if (strcmp(argv[1], "--describe-config") == 0)
+                       do_check_root = false;
+               else if (argc > 2 && strcmp(argv[1], "-C") == 0)
+                       do_check_root = false;
        }
 
        /*
-        * Make sure we are not running as root.
+        * Make sure we are not running as root, unless it's safe for the selected
+        * option.
         */
-       check_root(progname);
+       if (do_check_root)
+               check_root(progname);
 
        /*
         * Dispatch to one of various subprograms depending on first argument.
index 1f921819c23563bc9068fb1bab83ba2bec61627d..fc87e7d76ed166af23cf83fa91991211605af409 100644 (file)
@@ -2034,9 +2034,11 @@ adjust_data_dir(void)
        else
                my_exec_path = pg_strdup(exec_path);
 
-       snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s -C data_directory" SYSTEMQUOTE,
-                        my_exec_path, pgdata_opt ? pgdata_opt : "", post_opts ?
-                        post_opts : "");
+       /* it's important for -C to be the first option, see main.c */
+       snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" -C data_directory %s%s" SYSTEMQUOTE,
+                        my_exec_path,
+                        pgdata_opt ? pgdata_opt : "",
+                        post_opts ? post_opts : "");
 
        fd = popen(cmd, "r");
        if (fd == NULL || fgets(filename, sizeof(filename), fd) == NULL)