blob: 64d558fcc03cf6971a7f2aa4a64a3917acdf7acc [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001--- 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)