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