1 /*-------------------------------------------------------------------------
4 * helper routine to ensure restricted token on Windows
7 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/common/restricted_token.c
14 *-------------------------------------------------------------------------
18 #error "This file is not expected to be compiled for backend code"
21 #include "postgres_fe.h"
23 #include "common/restricted_token.h"
30 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
32 /* Windows API define missing from some versions of MingW headers */
33 #ifndef DISABLE_MAX_PRIVILEGE
34 #define DISABLE_MAX_PRIVILEGE 0x1
38 * Create a restricted token and execute the specified process with it.
40 * Returns restricted token on success and 0 on failure.
42 * On NT4, or any other system not containing the required functions, will
43 * NOT execute anything.
46 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname)
51 HANDLE restrictedToken;
52 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
53 SID_AND_ATTRIBUTES dropSids[2];
54 __CreateRestrictedToken _CreateRestrictedToken = NULL;
55 HANDLE Advapi32Handle;
57 ZeroMemory(&si, sizeof(si));
60 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
61 if (Advapi32Handle != NULL)
63 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
66 if (_CreateRestrictedToken == NULL)
68 fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
69 if (Advapi32Handle != NULL)
70 FreeLibrary(Advapi32Handle);
74 /* Open the current token to use as a base for the restricted one */
75 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
77 fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
81 /* Allocate list of SIDs to remove */
82 ZeroMemory(&dropSids, sizeof(dropSids));
83 if (!AllocateAndInitializeSid(&NtAuthority, 2,
84 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
85 0, &dropSids[0].Sid) ||
86 !AllocateAndInitializeSid(&NtAuthority, 2,
87 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
90 fprintf(stderr, _("%s: could not allocate SIDs: error code %lu\n"),
91 progname, GetLastError());
95 b = _CreateRestrictedToken(origToken,
96 DISABLE_MAX_PRIVILEGE,
97 sizeof(dropSids) / sizeof(dropSids[0]),
103 FreeSid(dropSids[1].Sid);
104 FreeSid(dropSids[0].Sid);
105 CloseHandle(origToken);
106 FreeLibrary(Advapi32Handle);
110 fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"),
111 progname, GetLastError());
116 AddUserToTokenDacl(restrictedToken);
119 if (!CreateProcessAsUser(restrictedToken,
132 fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
136 ResumeThread(processInfo->hThread);
137 return restrictedToken;
142 * On Windows make sure that we are running with a restricted token,
143 * On other platforms do nothing.
146 get_restricted_token(const char *progname)
149 HANDLE restrictedToken;
152 * Before we execute another program, make sure that we are running with a
153 * restricted token. If not, re-execute ourselves with one.
156 if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
157 || strcmp(restrict_env, "1") != 0)
159 PROCESS_INFORMATION pi;
162 ZeroMemory(&pi, sizeof(pi));
164 cmdline = pg_strdup(GetCommandLine());
166 putenv("PG_RESTRICT_EXEC=1");
168 if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi, progname)) == 0)
170 fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
175 * Successfully re-execed. Now wait for child process to capture
180 CloseHandle(restrictedToken);
181 CloseHandle(pi.hThread);
182 WaitForSingleObject(pi.hProcess, INFINITE);
184 if (!GetExitCodeProcess(pi.hProcess, &x))
186 fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());