| --- a/src/bin/pg_ctl/pg_ctl.c |
| +++ b/src/bin/pg_ctl/pg_ctl.c |
| @@ -96,6 +96,7 @@ static char *event_source = NULL; |
| static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */ |
| static char *register_username = NULL; |
| static char *register_password = NULL; |
| +static char *username = ""; |
| static char *argv0 = NULL; |
| static bool allow_core_files = false; |
| static time_t start_time; |
| @@ -2086,6 +2087,9 @@ do_help(void) |
| #endif |
| printf(_(" -s, --silent only print errors, no informational messages\n")); |
| printf(_(" -t, --timeout=SECS seconds to wait when using -w option\n")); |
| +#if !defined(WIN32) && !defined(__CYGWIN__) |
| + printf(_(" -U, --username=NAME user name of account PostgreSQL server is running as\n")); |
| +#endif |
| printf(_(" -V, --version output version information, then exit\n")); |
| printf(_(" -w, --wait wait until operation completes (default)\n")); |
| printf(_(" -W, --no-wait do not wait until operation completes\n")); |
| @@ -2298,6 +2302,7 @@ main(int argc, char **argv) |
| {"options", required_argument, NULL, 'o'}, |
| {"silent", no_argument, NULL, 's'}, |
| {"timeout", required_argument, NULL, 't'}, |
| + {"username", required_argument, NULL, 'U'}, |
| {"core-files", no_argument, NULL, 'c'}, |
| {"wait", no_argument, NULL, 'w'}, |
| {"no-wait", no_argument, NULL, 'W'}, |
| @@ -2338,20 +2343,6 @@ main(int argc, char **argv) |
| } |
| } |
| |
| - /* |
| - * Disallow running as root, to forestall any possible security holes. |
| - */ |
| -#ifndef WIN32 |
| - if (geteuid() == 0) |
| - { |
| - write_stderr(_("%s: cannot be run as root\n" |
| - "Please log in (using, e.g., \"su\") as the " |
| - "(unprivileged) user that will\n" |
| - "own the server process.\n"), |
| - progname); |
| - exit(1); |
| - } |
| -#endif |
| |
| env_wait = getenv("PGCTLTIMEOUT"); |
| if (env_wait != NULL) |
| @@ -2437,11 +2428,15 @@ main(int argc, char **argv) |
| wait_seconds_arg = true; |
| break; |
| case 'U': |
| +#if defined(WIN32) || defined(__CYGWIN__) |
| if (strchr(optarg, '\\')) |
| register_username = pg_strdup(optarg); |
| else |
| /* Prepend .\ for local accounts */ |
| register_username = psprintf(".\\%s", optarg); |
| +#else |
| + username = pg_strdup(optarg); |
| +#endif |
| break; |
| case 'w': |
| do_wait = true; |
| @@ -2523,6 +2518,41 @@ main(int argc, char **argv) |
| exit(1); |
| } |
| |
| + /* |
| + * Disallow running as root, to forestall any possible security holes. |
| + */ |
| +#if !defined(WIN32) && !defined(__CYGWIN__) |
| + if (geteuid() == 0) |
| + { |
| + struct passwd *p; |
| + if (!username || !strlen(username)) { |
| + fprintf(stderr, |
| + _("%s: when run as root, username needs to be provided\n"), |
| + progname); |
| + exit(1); |
| + } |
| + p = getpwnam(username); |
| + if (!p) { |
| + fprintf(stderr, |
| + _("%s: invalid username: %s\n"), |
| + progname, username); |
| + exit(1); |
| + } |
| + if (!p->pw_uid) { |
| + fprintf(stderr, |
| + _("%s: user needs to be non-root\n"), |
| + progname); |
| + exit(1); |
| + } |
| + if (setgid(p->pw_gid) || setuid(p->pw_uid)) { |
| + fprintf(stderr, |
| + _("%s: failed to set user id %d: %d (%s)\n"), |
| + progname, p->pw_uid, errno, strerror(errno)); |
| + exit(1); |
| + } |
| + } |
| +#endif |
| + |
| /* Note we put any -D switch into the env var above */ |
| pg_config = getenv("PGDATA"); |
| if (pg_config) |