1 /*-------------------------------------------------------------------------
4 * helper routine to ensure restricted token on Windows
7 * Portions Copyright (c) 1996-2021, 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/logging.h"
24 #include "common/restricted_token.h"
31 typedef BOOL (WINAPI
* __CreateRestrictedToken
) (HANDLE
, DWORD
, DWORD
, PSID_AND_ATTRIBUTES
, DWORD
, PLUID_AND_ATTRIBUTES
, DWORD
, PSID_AND_ATTRIBUTES
, PHANDLE
);
33 /* Windows API define missing from some versions of MingW headers */
34 #ifndef DISABLE_MAX_PRIVILEGE
35 #define DISABLE_MAX_PRIVILEGE 0x1
39 * Create a restricted token and execute the specified process with it.
41 * Returns restricted token on success and 0 on failure.
43 * On any system not containing the required functions, do nothing
44 * but still report an error.
47 CreateRestrictedProcess(char *cmd
, PROCESS_INFORMATION
*processInfo
)
52 HANDLE restrictedToken
;
53 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
54 SID_AND_ATTRIBUTES dropSids
[2];
55 __CreateRestrictedToken _CreateRestrictedToken
;
56 HANDLE Advapi32Handle
;
58 ZeroMemory(&si
, sizeof(si
));
61 Advapi32Handle
= LoadLibrary("ADVAPI32.DLL");
62 if (Advapi32Handle
== NULL
)
64 pg_log_error("could not load library \"%s\": error code %lu",
65 "ADVAPI32.DLL", GetLastError());
69 _CreateRestrictedToken
= (__CreateRestrictedToken
) (pg_funcptr_t
) GetProcAddress(Advapi32Handle
, "CreateRestrictedToken");
71 if (_CreateRestrictedToken
== NULL
)
73 pg_log_error("cannot create restricted tokens on this platform: error code %lu",
75 FreeLibrary(Advapi32Handle
);
79 /* Open the current token to use as a base for the restricted one */
80 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS
, &origToken
))
82 pg_log_error("could not open process token: error code %lu",
84 FreeLibrary(Advapi32Handle
);
88 /* Allocate list of SIDs to remove */
89 ZeroMemory(&dropSids
, sizeof(dropSids
));
90 if (!AllocateAndInitializeSid(&NtAuthority
, 2,
91 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0,
92 0, &dropSids
[0].Sid
) ||
93 !AllocateAndInitializeSid(&NtAuthority
, 2,
94 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_POWER_USERS
, 0, 0, 0, 0, 0,
97 pg_log_error("could not allocate SIDs: error code %lu",
99 CloseHandle(origToken
);
100 FreeLibrary(Advapi32Handle
);
104 b
= _CreateRestrictedToken(origToken
,
105 DISABLE_MAX_PRIVILEGE
,
106 sizeof(dropSids
) / sizeof(dropSids
[0]),
112 FreeSid(dropSids
[1].Sid
);
113 FreeSid(dropSids
[0].Sid
);
114 CloseHandle(origToken
);
115 FreeLibrary(Advapi32Handle
);
119 pg_log_error("could not create restricted token: error code %lu", GetLastError());
124 AddUserToTokenDacl(restrictedToken
);
127 if (!CreateProcessAsUser(restrictedToken
,
140 pg_log_error("could not start process for command \"%s\": error code %lu", cmd
, GetLastError());
144 ResumeThread(processInfo
->hThread
);
145 return restrictedToken
;
150 * On Windows make sure that we are running with a restricted token,
151 * On other platforms do nothing.
154 get_restricted_token(void)
157 HANDLE restrictedToken
;
160 * Before we execute another program, make sure that we are running with a
161 * restricted token. If not, re-execute ourselves with one.
164 if ((restrict_env
= getenv("PG_RESTRICT_EXEC")) == NULL
165 || strcmp(restrict_env
, "1") != 0)
167 PROCESS_INFORMATION pi
;
170 ZeroMemory(&pi
, sizeof(pi
));
172 cmdline
= pg_strdup(GetCommandLine());
174 setenv("PG_RESTRICT_EXEC", "1", 1);
176 if ((restrictedToken
= CreateRestrictedProcess(cmdline
, &pi
)) == 0)
178 pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError());
183 * Successfully re-executed. Now wait for child process to capture
188 CloseHandle(restrictedToken
);
189 CloseHandle(pi
.hThread
);
190 WaitForSingleObject(pi
.hProcess
, INFINITE
);
192 if (!GetExitCodeProcess(pi
.hProcess
, &x
))
194 pg_log_error("could not get exit code from subprocess: error code %lu", GetLastError());