Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * restricted_token.c
4 : : * helper routine to ensure restricted token on Windows
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : *
11 : : * IDENTIFICATION
12 : : * src/common/restricted_token.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : :
17 : : #ifndef FRONTEND
18 : : #error "This file is not expected to be compiled for backend code"
19 : : #endif
20 : :
21 : : #include "postgres_fe.h"
22 : :
23 : : #include "common/logging.h"
24 : : #include "common/restricted_token.h"
25 : :
26 : : #ifdef WIN32
27 : :
28 : : /* internal vars */
29 : : char *restrict_env;
30 : :
31 : : /* Windows API define missing from some versions of MingW headers */
32 : : #ifndef DISABLE_MAX_PRIVILEGE
33 : : #define DISABLE_MAX_PRIVILEGE 0x1
34 : : #endif
35 : :
36 : : /*
37 : : * Create a restricted token and execute the specified process with it.
38 : : *
39 : : * Returns restricted token on success and 0 on failure.
40 : : *
41 : : * On any system not containing the required functions, do nothing
42 : : * but still report an error.
43 : : */
44 : : HANDLE
45 : : CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
46 : : {
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];
53 : :
54 : : ZeroMemory(&si, sizeof(si));
55 : : si.cb = sizeof(si);
56 : :
57 : : /* Open the current token to use as a base for the restricted one */
58 : : if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
59 : : {
60 : : pg_log_error("could not open process token: error code %lu",
61 : : GetLastError());
62 : : return 0;
63 : : }
64 : :
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))
73 : : {
74 : : pg_log_error("could not allocate SIDs: error code %lu",
75 : : GetLastError());
76 : : CloseHandle(origToken);
77 : : return 0;
78 : : }
79 : :
80 : : b = CreateRestrictedToken(origToken,
81 : : DISABLE_MAX_PRIVILEGE,
82 : : sizeof(dropSids) / sizeof(dropSids[0]),
83 : : dropSids,
84 : : 0, NULL,
85 : : 0, NULL,
86 : : &restrictedToken);
87 : :
88 : : FreeSid(dropSids[1].Sid);
89 : : FreeSid(dropSids[0].Sid);
90 : : CloseHandle(origToken);
91 : :
92 : : if (!b)
93 : : {
94 : : pg_log_error("could not create restricted token: error code %lu", GetLastError());
95 : : return 0;
96 : : }
97 : :
98 : : #ifndef __CYGWIN__
99 : : AddUserToTokenDacl(restrictedToken);
100 : : #endif
101 : :
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))
113 : :
114 : : {
115 : : pg_log_error("could not start process for command \"%s\": error code %lu", cmd, GetLastError());
116 : : return 0;
117 : : }
118 : :
119 : : ResumeThread(processInfo->hThread);
120 : : return restrictedToken;
121 : : }
122 : : #endif
123 : :
124 : : /*
125 : : * On Windows make sure that we are running with a restricted token,
126 : : * On other platforms do nothing.
127 : : */
128 : : void
1840 peter@eisentraut.org 129 :CBC 501 : get_restricted_token(void)
130 : : {
131 : : #ifdef WIN32
132 : : HANDLE restrictedToken;
133 : :
134 : : /*
135 : : * Before we execute another program, make sure that we are running with a
136 : : * restricted token. If not, re-execute ourselves with one.
137 : : */
138 : :
139 : : if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
140 : : || strcmp(restrict_env, "1") != 0)
141 : : {
142 : : PROCESS_INFORMATION pi;
143 : : char *cmdline;
144 : :
145 : : ZeroMemory(&pi, sizeof(pi));
146 : :
147 : : cmdline = pg_strdup(GetCommandLine());
148 : :
149 : : setenv("PG_RESTRICT_EXEC", "1", 1);
150 : :
151 : : if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi)) == 0)
152 : : {
153 : : pg_log_error("could not re-execute with restricted token: error code %lu", GetLastError());
154 : : }
155 : : else
156 : : {
157 : : /*
158 : : * Successfully re-executed. Now wait for child process to capture
159 : : * the exit code.
160 : : */
161 : : DWORD x;
162 : :
163 : : CloseHandle(restrictedToken);
164 : : CloseHandle(pi.hThread);
165 : : WaitForSingleObject(pi.hProcess, INFINITE);
166 : :
167 : : if (!GetExitCodeProcess(pi.hProcess, &x))
168 : : pg_fatal("could not get exit code from subprocess: error code %lu", GetLastError());
169 : : exit(x);
170 : : }
171 : : pg_free(cmdline);
172 : : }
173 : : #endif
3303 andrew@dunslane.net 174 : 501 : }
|