Skip to content

Commit bf22a8e

Browse files
committed
Run pg_upgrade and pg_resetxlog with restricted token on Windows
As with initdb these programs need to run with a restricted token, and if they don't pg_upgrade will fail when run as a user with Adminstrator privileges. Backpatch to all live branches. On the development branch the code is reorganized so that the restricted token code is now in a single location. On the stable bramches a less invasive change is made by simply copying the relevant code to pg_upgrade.c and pg_resetxlog.c. Patches and bug report from Muhammad Asif Naeem, reviewed by Michael Paquier, slightly edited by me.
1 parent 8f3c577 commit bf22a8e

File tree

2 files changed

+364
-0
lines changed

2 files changed

+364
-0
lines changed

contrib/pg_upgrade/pg_upgrade.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,16 @@ static void copy_clog_xlog_xid(migratorContext *ctx);
2121
static void set_frozenxids(migratorContext *ctx);
2222
static void setup(migratorContext *ctx, char *argv0, bool live_check);
2323
static void cleanup(migratorContext *ctx);
24+
static void get_restricted_token(const char *progname);
2425

26+
#ifdef WIN32
27+
static char * pg_strdupn(const char *str);
28+
static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname);
29+
#endif
30+
31+
#ifdef WIN32
32+
static char *restrict_env;
33+
#endif
2534

2635
int
2736
main(int argc, char **argv)
@@ -35,6 +44,8 @@ main(int argc, char **argv)
3544

3645
parseCommandLine(&ctx, argc, argv);
3746

47+
get_restricted_token(ctx.progname);
48+
3849
output_check_banner(&ctx, &live_check);
3950

4051
setup(&ctx, argv[0], live_check);
@@ -103,6 +114,162 @@ main(int argc, char **argv)
103114
return 0;
104115
}
105116

117+
#ifdef WIN32
118+
typedef BOOL(WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
119+
120+
/* Windows API define missing from some versions of MingW headers */
121+
#ifndef DISABLE_MAX_PRIVILEGE
122+
#define DISABLE_MAX_PRIVILEGE 0x1
123+
#endif
124+
125+
/*
126+
* Create a restricted token and execute the specified process with it.
127+
*
128+
* Returns 0 on failure, non-zero on success, same as CreateProcess().
129+
*
130+
* On NT4, or any other system not containing the required functions, will
131+
* NOT execute anything.
132+
*/
133+
static int
134+
CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname)
135+
{
136+
BOOL b;
137+
STARTUPINFO si;
138+
HANDLE origToken;
139+
HANDLE restrictedToken;
140+
SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
141+
SID_AND_ATTRIBUTES dropSids[2];
142+
__CreateRestrictedToken _CreateRestrictedToken = NULL;
143+
HANDLE Advapi32Handle;
144+
145+
ZeroMemory(&si, sizeof(si));
146+
si.cb = sizeof(si);
147+
148+
Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
149+
if (Advapi32Handle != NULL)
150+
{
151+
_CreateRestrictedToken = (__CreateRestrictedToken)GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
152+
}
153+
154+
if (_CreateRestrictedToken == NULL)
155+
{
156+
fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
157+
if (Advapi32Handle != NULL)
158+
FreeLibrary(Advapi32Handle);
159+
return 0;
160+
}
161+
162+
/* Open the current token to use as a base for the restricted one */
163+
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
164+
{
165+
fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
166+
return 0;
167+
}
168+
169+
/* Allocate list of SIDs to remove */
170+
ZeroMemory(&dropSids, sizeof(dropSids));
171+
if (!AllocateAndInitializeSid(&NtAuthority, 2,
172+
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
173+
0, &dropSids[0].Sid) ||
174+
!AllocateAndInitializeSid(&NtAuthority, 2,
175+
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
176+
0, &dropSids[1].Sid))
177+
{
178+
fprintf(stderr, _("%s: could not to allocate SIDs: error code %lu\n"), progname, GetLastError());
179+
return 0;
180+
}
181+
182+
b = _CreateRestrictedToken(origToken,
183+
DISABLE_MAX_PRIVILEGE,
184+
sizeof(dropSids) / sizeof(dropSids[0]),
185+
dropSids,
186+
0, NULL,
187+
0, NULL,
188+
&restrictedToken);
189+
190+
FreeSid(dropSids[1].Sid);
191+
FreeSid(dropSids[0].Sid);
192+
CloseHandle(origToken);
193+
FreeLibrary(Advapi32Handle);
194+
195+
if (!b)
196+
{
197+
fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"), progname, GetLastError());
198+
return 0;
199+
}
200+
201+
#ifndef __CYGWIN__
202+
AddUserToTokenDacl(restrictedToken);
203+
#endif
204+
205+
if (!CreateProcessAsUser(restrictedToken,
206+
NULL,
207+
cmd,
208+
NULL,
209+
NULL,
210+
TRUE,
211+
CREATE_SUSPENDED,
212+
NULL,
213+
NULL,
214+
&si,
215+
processInfo))
216+
217+
{
218+
fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
219+
return 0;
220+
}
221+
222+
return ResumeThread(processInfo->hThread);
223+
}
224+
#endif
225+
226+
void
227+
get_restricted_token(const char *progname)
228+
{
229+
#ifdef WIN32
230+
231+
/*
232+
* Before we execute another program, make sure that we are running with a
233+
* restricted token. If not, re-execute ourselves with one.
234+
*/
235+
236+
if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
237+
|| strcmp(restrict_env, "1") != 0)
238+
{
239+
PROCESS_INFORMATION pi;
240+
char *cmdline;
241+
242+
ZeroMemory(&pi, sizeof(pi));
243+
244+
cmdline = pg_strdupn(GetCommandLine());
245+
246+
putenv("PG_RESTRICT_EXEC=1");
247+
248+
if (!CreateRestrictedProcess(cmdline, &pi, progname))
249+
{
250+
fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
251+
}
252+
else
253+
{
254+
/*
255+
* Successfully re-execed. Now wait for child process to capture
256+
* exitcode.
257+
*/
258+
DWORD x;
259+
260+
CloseHandle(pi.hThread);
261+
WaitForSingleObject(pi.hProcess, INFINITE);
262+
263+
if (!GetExitCodeProcess(pi.hProcess, &x))
264+
{
265+
fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
266+
exit(1);
267+
}
268+
exit(x);
269+
}
270+
}
271+
#endif
272+
}
106273

107274
static void
108275
setup(migratorContext *ctx, char *argv0, bool live_check)
@@ -443,3 +610,18 @@ cleanup(migratorContext *ctx)
443610
snprintf(filename, sizeof(filename), "%s/%s", ctx->cwd, DB_DUMP_FILE);
444611
unlink(filename);
445612
}
613+
614+
#ifdef WIN32
615+
static char *
616+
pg_strdupn(const char *str)
617+
{
618+
char *result = strdup(str);
619+
620+
if (!result)
621+
{
622+
fprintf(stderr, _("out of memory\n"));
623+
exit(1);
624+
}
625+
return result;
626+
}
627+
#endif

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy