1 /*-------------------------------------------------------------------------
4 * helper routine to ensure restricted token on Windows
7 * Portions Copyright (c) 1996-2024, 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"
29 static char *restrict_env
;
31 /* Windows API define missing from some versions of MingW headers */
32 #ifndef DISABLE_MAX_PRIVILEGE
33 #define DISABLE_MAX_PRIVILEGE 0x1
37 * Create a restricted token and execute the specified process with it.
39 * Returns restricted token on success and 0 on failure.
41 * On any system not containing the required functions, do nothing
42 * but still report an error.
45 CreateRestrictedProcess(char *cmd
, PROCESS_INFORMATION
*processInfo
)
50 HANDLE restrictedToken
;
51 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
52 SID_AND_ATTRIBUTES dropSids
[2];
54 ZeroMemory(&si
, sizeof(si
));
57 /* Open the current token to use as a base for the restricted one */
58 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS
, &origToken
))
60 pg_log_error("could not open process token: error code %lu",
65 /* Allocate list of SIDs to remove */
66 ZeroMemory(&dropSids
, sizeof(dropSids
));
67 if (!AllocateAndInitializeSid(&NtAuthority
, 2,
68 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0,
69 0, &dropSids
[0].Sid
) ||
70 !AllocateAndInitializeSid(&NtAuthority
, 2,
71 SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_POWER_USERS
, 0, 0, 0, 0, 0,
74 pg_log_error("could not allocate SIDs: error code %lu",
76 CloseHandle(origToken
);
80 b
= CreateRestrictedToken(origToken
,
81 DISABLE_MAX_PRIVILEGE
,
82 sizeof(dropSids
) / sizeof(dropSids
[0]),
88 FreeSid(dropSids
[1].Sid
);
89 FreeSid(dropSids
[0].Sid
);
90 CloseHandle(origToken
);
94 pg_log_error("could not create restricted token: error code %lu", GetLastError());
99 AddUserToTokenDacl(restrictedToken
);
102 if (!CreateProcessAsUser(restrictedToken
,
115 pg_log_error("could not start process for command \"%s\": error code %lu", cmd
, GetLastError());
119 ResumeThread(processInfo
->hThread
);
120 return restrictedToken
;
125 * On Windows make sure that we are running with a restricted token,
126 * On other platforms do nothing.
129 get_restricted_token(void)
132 HANDLE restrictedToken
;
135 * Before we execute another program, make sure that we are running with a
136 * restricted token. If not, re-execute ourselves with one.
139 if ((restrict_env
= getenv("PG_RESTRICT_EXEC")) == NULL
140 || strcmp(restrict_env
, "1") != 0)
142 PROCESS_INFORMATION pi
;
145 ZeroMemory(&pi
, sizeof(pi
));
147 cmdline
= pg_strdup(GetCommandLine());
149 setenv("PG_RESTRICT_EXEC", "1", 1);
151 if ((restrictedToken
= CreateRestrictedProcess(cmdline
, &pi
)) == 0)
153 pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError());
158 * Successfully re-executed. Now wait for child process to capture
163 CloseHandle(restrictedToken
);
164 CloseHandle(pi
.hThread
);
165 WaitForSingleObject(pi
.hProcess
, INFINITE
);
167 if (!GetExitCodeProcess(pi
.hProcess
, &x
))
168 pg_fatal("could not get exit code from subprocess: error code %lu", GetLastError());