--- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -88,6 +88,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; @@ -1930,6 +1931,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 until operation completes\n")); printf(_(" -W do not wait until operation completes\n")); @@ -2126,6 +2130,7 @@ main(int argc, char **argv) {"pgdata", required_argument, NULL, 'D'}, {"silent", no_argument, NULL, 's'}, {"timeout", required_argument, NULL, 't'}, + {"username", required_argument, NULL, 'U'}, {"core-files", no_argument, NULL, 'c'}, {NULL, 0, NULL, 0} }; @@ -2166,20 +2171,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) @@ -2265,11 +2256,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; @@ -2351,6 +2346,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)