doc: clarify that pg_global can _only_ be used for system tabs.
[pgsql.git] / src / common / restricted_token.c
blob4ae1ed1e8ae57d8940485a7f511f0b5e3a643d82
1 /*-------------------------------------------------------------------------
3 * restricted_token.c
4 * helper routine to ensure restricted token on Windows
7 * Portions Copyright (c) 1996-2023, 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 /* Windows API define missing from some versions of MingW headers */
32 #ifndef DISABLE_MAX_PRIVILEGE
33 #define DISABLE_MAX_PRIVILEGE 0x1
34 #endif
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.
44 HANDLE
45 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
47 BOOL b;
48 STARTUPINFO si;
49 HANDLE origToken;
50 HANDLE restrictedToken;
51 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
52 SID_AND_ATTRIBUTES dropSids[2];
54 ZeroMemory(&si, sizeof(si));
55 si.cb = 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",
61 GetLastError());
62 return 0;
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,
72 0, &dropSids[1].Sid))
74 pg_log_error("could not allocate SIDs: error code %lu",
75 GetLastError());
76 CloseHandle(origToken);
77 return 0;
80 b = CreateRestrictedToken(origToken,
81 DISABLE_MAX_PRIVILEGE,
82 sizeof(dropSids) / sizeof(dropSids[0]),
83 dropSids,
84 0, NULL,
85 0, NULL,
86 &restrictedToken);
88 FreeSid(dropSids[1].Sid);
89 FreeSid(dropSids[0].Sid);
90 CloseHandle(origToken);
92 if (!b)
94 pg_log_error("could not create restricted token: error code %lu", GetLastError());
95 return 0;
98 #ifndef __CYGWIN__
99 AddUserToTokenDacl(restrictedToken);
100 #endif
102 if (!CreateProcessAsUser(restrictedToken,
103 NULL,
104 cmd,
105 NULL,
106 NULL,
107 TRUE,
108 CREATE_SUSPENDED,
109 NULL,
110 NULL,
111 &si,
112 processInfo))
115 pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError());
116 return 0;
119 ResumeThread(processInfo->hThread);
120 return restrictedToken;
122 #endif
125 * On Windows make sure that we are running with a restricted token,
126 * On other platforms do nothing.
128 void
129 get_restricted_token(void)
131 #ifdef WIN32
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;
143 char *cmdline;
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());
155 else
158 * Successfully re-executed. Now wait for child process to capture
159 * the exit code.
161 DWORD x;
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());
169 exit(x);
171 pg_free(cmdline);
173 #endif