Consistently use "superuser" instead of "super user"
[pgsql.git] / src / common / restricted_token.c
blob667040d734c3aba250fd48c0c17d9dc7bc5d24d6
1 /*-------------------------------------------------------------------------
3 * restricted_token.c
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
11 * IDENTIFICATION
12 * src/common/restricted_token.c
14 *-------------------------------------------------------------------------
17 #ifndef FRONTEND
18 #error "This file is not expected to be compiled for backend code"
19 #endif
21 #include "postgres_fe.h"
23 #include "common/logging.h"
24 #include "common/restricted_token.h"
26 #ifdef WIN32
28 /* internal vars */
29 char *restrict_env;
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
36 #endif
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.
46 HANDLE
47 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
49 BOOL b;
50 STARTUPINFO si;
51 HANDLE origToken;
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));
59 si.cb = 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());
66 return 0;
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",
74 GetLastError());
75 FreeLibrary(Advapi32Handle);
76 return 0;
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",
83 GetLastError());
84 FreeLibrary(Advapi32Handle);
85 return 0;
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,
95 0, &dropSids[1].Sid))
97 pg_log_error("could not allocate SIDs: error code %lu",
98 GetLastError());
99 CloseHandle(origToken);
100 FreeLibrary(Advapi32Handle);
101 return 0;
104 b = _CreateRestrictedToken(origToken,
105 DISABLE_MAX_PRIVILEGE,
106 sizeof(dropSids) / sizeof(dropSids[0]),
107 dropSids,
108 0, NULL,
109 0, NULL,
110 &restrictedToken);
112 FreeSid(dropSids[1].Sid);
113 FreeSid(dropSids[0].Sid);
114 CloseHandle(origToken);
115 FreeLibrary(Advapi32Handle);
117 if (!b)
119 pg_log_error("could not create restricted token: error code %lu", GetLastError());
120 return 0;
123 #ifndef __CYGWIN__
124 AddUserToTokenDacl(restrictedToken);
125 #endif
127 if (!CreateProcessAsUser(restrictedToken,
128 NULL,
129 cmd,
130 NULL,
131 NULL,
132 TRUE,
133 CREATE_SUSPENDED,
134 NULL,
135 NULL,
136 &si,
137 processInfo))
140 pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError());
141 return 0;
144 ResumeThread(processInfo->hThread);
145 return restrictedToken;
147 #endif
150 * On Windows make sure that we are running with a restricted token,
151 * On other platforms do nothing.
153 void
154 get_restricted_token(void)
156 #ifdef WIN32
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;
168 char *cmdline;
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());
180 else
183 * Successfully re-executed. Now wait for child process to capture
184 * the exit code.
186 DWORD x;
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());
195 exit(1);
197 exit(x);
199 pg_free(cmdline);
201 #endif