Skip to content

Commit 0904eb3

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 246bbf6 commit 0904eb3

File tree

2 files changed

+331
-0
lines changed

2 files changed

+331
-0
lines changed

contrib/pg_upgrade/pg_upgrade.c

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

5459
ClusterInfo old_cluster,
5560
new_cluster;
@@ -66,6 +71,9 @@ char *output_files[] = {
6671
NULL
6772
};
6873

74+
#ifdef WIN32
75+
static char *restrict_env;
76+
#endif
6977

7078
int
7179
main(int argc, char **argv)
@@ -77,6 +85,8 @@ main(int argc, char **argv)
7785

7886
parseCommandLine(argc, argv);
7987

88+
get_restricted_token(os_info.progname);
89+
8090
adjust_data_dir(&old_cluster);
8191
adjust_data_dir(&new_cluster);
8292

@@ -175,6 +185,162 @@ main(int argc, char **argv)
175185
return 0;
176186
}
177187

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

179345
static void
180346
setup(char *argv0, bool *live_check)

src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ static XLogSegNo newXlogSegNo; /* new XLOG segment # */
6565
static bool guessed = false; /* T if we had to guess at any values */
6666
static const char *progname;
6767

68+
#ifdef WIN32
69+
static char *restrict_env;
70+
#endif
71+
6872
static bool ReadControlFile(void);
6973
static void GuessControlValues(void);
7074
static void PrintControlValues(bool guessed);
@@ -74,7 +78,11 @@ static void KillExistingXLOG(void);
7478
static void KillExistingArchiveStatus(void);
7579
static void WriteEmptyXLOG(void);
7680
static void usage(void);
81+
static void get_restricted_token(const char *progname);
7782

83+
#ifdef WIN32
84+
static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname);
85+
#endif
7886

7987
int
8088
main(int argc, char *argv[])
@@ -260,6 +268,7 @@ main(int argc, char *argv[])
260268
}
261269
#endif
262270

271+
get_restricted_token(progname);
263272
DataDir = argv[optind];
264273

265274
if (chdir(DataDir) < 0)
@@ -1029,6 +1038,162 @@ WriteEmptyXLOG(void)
10291038
close(fd);
10301039
}
10311040

1041+
#ifdef WIN32
1042+
typedef BOOL(WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
1043+
1044+
/* Windows API define missing from some versions of MingW headers */
1045+
#ifndef DISABLE_MAX_PRIVILEGE
1046+
#define DISABLE_MAX_PRIVILEGE 0x1
1047+
#endif
1048+
1049+
/*
1050+
* Create a restricted token and execute the specified process with it.
1051+
*
1052+
* Returns 0 on failure, non-zero on success, same as CreateProcess().
1053+
*
1054+
* On NT4, or any other system not containing the required functions, will
1055+
* NOT execute anything.
1056+
*/
1057+
static int
1058+
CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname)
1059+
{
1060+
BOOL b;
1061+
STARTUPINFO si;
1062+
HANDLE origToken;
1063+
HANDLE restrictedToken;
1064+
SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
1065+
SID_AND_ATTRIBUTES dropSids[2];
1066+
__CreateRestrictedToken _CreateRestrictedToken = NULL;
1067+
HANDLE Advapi32Handle;
1068+
1069+
ZeroMemory(&si, sizeof(si));
1070+
si.cb = sizeof(si);
1071+
1072+
Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
1073+
if (Advapi32Handle != NULL)
1074+
{
1075+
_CreateRestrictedToken = (__CreateRestrictedToken)GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
1076+
}
1077+
1078+
if (_CreateRestrictedToken == NULL)
1079+
{
1080+
fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
1081+
if (Advapi32Handle != NULL)
1082+
FreeLibrary(Advapi32Handle);
1083+
return 0;
1084+
}
1085+
1086+
/* Open the current token to use as a base for the restricted one */
1087+
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
1088+
{
1089+
fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
1090+
return 0;
1091+
}
1092+
1093+
/* Allocate list of SIDs to remove */
1094+
ZeroMemory(&dropSids, sizeof(dropSids));
1095+
if (!AllocateAndInitializeSid(&NtAuthority, 2,
1096+
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
1097+
0, &dropSids[0].Sid) ||
1098+
!AllocateAndInitializeSid(&NtAuthority, 2,
1099+
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
1100+
0, &dropSids[1].Sid))
1101+
{
1102+
fprintf(stderr, _("%s: could not to allocate SIDs: error code %lu\n"), progname, GetLastError());
1103+
return 0;
1104+
}
1105+
1106+
b = _CreateRestrictedToken(origToken,
1107+
DISABLE_MAX_PRIVILEGE,
1108+
sizeof(dropSids) / sizeof(dropSids[0]),
1109+
dropSids,
1110+
0, NULL,
1111+
0, NULL,
1112+
&restrictedToken);
1113+
1114+
FreeSid(dropSids[1].Sid);
1115+
FreeSid(dropSids[0].Sid);
1116+
CloseHandle(origToken);
1117+
FreeLibrary(Advapi32Handle);
1118+
1119+
if (!b)
1120+
{
1121+
fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"), progname, GetLastError());
1122+
return 0;
1123+
}
1124+
1125+
#ifndef __CYGWIN__
1126+
AddUserToTokenDacl(restrictedToken);
1127+
#endif
1128+
1129+
if (!CreateProcessAsUser(restrictedToken,
1130+
NULL,
1131+
cmd,
1132+
NULL,
1133+
NULL,
1134+
TRUE,
1135+
CREATE_SUSPENDED,
1136+
NULL,
1137+
NULL,
1138+
&si,
1139+
processInfo))
1140+
1141+
{
1142+
fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
1143+
return 0;
1144+
}
1145+
1146+
return ResumeThread(processInfo->hThread);
1147+
}
1148+
#endif
1149+
1150+
void
1151+
get_restricted_token(const char *progname)
1152+
{
1153+
#ifdef WIN32
1154+
1155+
/*
1156+
* Before we execute another program, make sure that we are running with a
1157+
* restricted token. If not, re-execute ourselves with one.
1158+
*/
1159+
1160+
if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
1161+
|| strcmp(restrict_env, "1") != 0)
1162+
{
1163+
PROCESS_INFORMATION pi;
1164+
char *cmdline;
1165+
1166+
ZeroMemory(&pi, sizeof(pi));
1167+
1168+
cmdline = pg_strdup(GetCommandLine());
1169+
1170+
putenv("PG_RESTRICT_EXEC=1");
1171+
1172+
if (!CreateRestrictedProcess(cmdline, &pi, progname))
1173+
{
1174+
fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
1175+
}
1176+
else
1177+
{
1178+
/*
1179+
* Successfully re-execed. Now wait for child process to capture
1180+
* exitcode.
1181+
*/
1182+
DWORD x;
1183+
1184+
CloseHandle(pi.hThread);
1185+
WaitForSingleObject(pi.hProcess, INFINITE);
1186+
1187+
if (!GetExitCodeProcess(pi.hProcess, &x))
1188+
{
1189+
fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
1190+
exit(1);
1191+
}
1192+
exit(x);
1193+
}
1194+
}
1195+
#endif
1196+
}
10321197

10331198
static void
10341199
usage(void)

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