Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)