900-pg_ctl-setuid.patch (3339B)
1 Index: postgresql-9.5.4/src/bin/pg_ctl/pg_ctl.c 2 =================================================================== 3 --- postgresql-9.5.4.orig/src/bin/pg_ctl/pg_ctl.c 4 +++ postgresql-9.5.4/src/bin/pg_ctl/pg_ctl.c 5 @@ -95,6 +95,7 @@ static char *event_source = NULL; 6 static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */ 7 static char *register_username = NULL; 8 static char *register_password = NULL; 9 +static char *username = ""; 10 static char *argv0 = NULL; 11 static bool allow_core_files = false; 12 static time_t start_time; 13 @@ -2114,6 +2115,9 @@ do_help(void) 14 #endif 15 printf(_(" -s, --silent only print errors, no informational messages\n")); 16 printf(_(" -t, --timeout=SECS seconds to wait when using -w option\n")); 17 +#if !defined(WIN32) && !defined(__CYGWIN__) 18 + printf(_(" -U, --username=NAME user name of account PostgreSQL server is running as\n")); 19 +#endif 20 printf(_(" -V, --version output version information, then exit\n")); 21 printf(_(" -w wait until operation completes\n")); 22 printf(_(" -W do not wait until operation completes\n")); 23 @@ -2310,6 +2314,7 @@ main(int argc, char **argv) 24 {"pgdata", required_argument, NULL, 'D'}, 25 {"silent", no_argument, NULL, 's'}, 26 {"timeout", required_argument, NULL, 't'}, 27 + {"username", required_argument, NULL, 'U'}, 28 {"core-files", no_argument, NULL, 'c'}, 29 {NULL, 0, NULL, 0} 30 }; 31 @@ -2350,20 +2355,6 @@ main(int argc, char **argv) 32 } 33 } 34 35 - /* 36 - * Disallow running as root, to forestall any possible security holes. 37 - */ 38 -#ifndef WIN32 39 - if (geteuid() == 0) 40 - { 41 - write_stderr(_("%s: cannot be run as root\n" 42 - "Please log in (using, e.g., \"su\") as the " 43 - "(unprivileged) user that will\n" 44 - "own the server process.\n"), 45 - progname); 46 - exit(1); 47 - } 48 -#endif 49 50 env_wait = getenv("PGCTLTIMEOUT"); 51 if (env_wait != NULL) 52 @@ -2449,11 +2440,15 @@ main(int argc, char **argv) 53 wait_seconds_arg = true; 54 break; 55 case 'U': 56 +#if defined(WIN32) || defined(__CYGWIN__) 57 if (strchr(optarg, '\\')) 58 register_username = pg_strdup(optarg); 59 else 60 /* Prepend .\ for local accounts */ 61 register_username = psprintf(".\\%s", optarg); 62 +#else 63 + username = pg_strdup(optarg); 64 +#endif 65 break; 66 case 'w': 67 do_wait = true; 68 @@ -2535,6 +2530,41 @@ main(int argc, char **argv) 69 exit(1); 70 } 71 72 + /* 73 + * Disallow running as root, to forestall any possible security holes. 74 + */ 75 +#if !defined(WIN32) && !defined(__CYGWIN__) 76 + if (geteuid() == 0) 77 + { 78 + struct passwd *p; 79 + if (!username || !strlen(username)) { 80 + fprintf(stderr, 81 + _("%s: when run as root, username needs to be provided\n"), 82 + progname); 83 + exit(1); 84 + } 85 + p = getpwnam(username); 86 + if (!p) { 87 + fprintf(stderr, 88 + _("%s: invalid username: %s\n"), 89 + progname, username); 90 + exit(1); 91 + } 92 + if (!p->pw_uid) { 93 + fprintf(stderr, 94 + _("%s: user needs to be non-root\n"), 95 + progname); 96 + exit(1); 97 + } 98 + if (setgid(p->pw_gid) || setuid(p->pw_uid)) { 99 + fprintf(stderr, 100 + _("%s: failed to set user id %d: %d (%s)\n"), 101 + progname, p->pw_uid, errno, strerror(errno)); 102 + exit(1); 103 + } 104 + } 105 +#endif 106 + 107 /* Note we put any -D switch into the env var above */ 108 pg_config = getenv("PGDATA"); 109 if (pg_config)