Skip to content

Commit 22b3f5b

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 46bfe44 commit 22b3f5b

File tree

2 files changed

+347
-0
lines changed

2 files changed

+347
-0
lines changed

contrib/pg_upgrade/pg_upgrade.c

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ static void copy_clog_xlog_xid(void);
4949
static void set_frozenxids(void);
5050
static void setup(char *argv0, bool live_check);
5151
static void cleanup(void);
52+
static void get_restricted_token(const char *progname);
53+
54+
#ifdef WIN32
55+
static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname);
56+
#endif
5257

5358
/* This is the database used by pg_dumpall to restore global tables */
5459
#define GLOBAL_DUMP_DB "postgres"
@@ -57,6 +62,10 @@ ClusterInfo old_cluster,
5762
new_cluster;
5863
OSInfo os_info;
5964

65+
#ifdef WIN32
66+
static char *restrict_env;
67+
#endif
68+
6069
int
6170
main(int argc, char **argv)
6271
{
@@ -66,6 +75,8 @@ main(int argc, char **argv)
6675

6776
parseCommandLine(argc, argv);
6877

78+
get_restricted_token(os_info.progname);
79+
6980
output_check_banner(&live_check);
7081

7182
setup(argv[0], live_check);
@@ -139,6 +150,162 @@ main(int argc, char **argv)
139150
return 0;
140151
}
141152

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

143310
static void
144311
setup(char *argv0, bool live_check)

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