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-2017, 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/restricted_token.h"
24 :
25 : #ifdef WIN32
26 :
27 : /* internal vars */
28 : char *restrict_env;
29 :
30 : typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
31 :
32 : /* Windows API define missing from some versions of MingW headers */
33 : #ifndef DISABLE_MAX_PRIVILEGE
34 : #define DISABLE_MAX_PRIVILEGE 0x1
35 : #endif
36 :
37 : /*
38 : * Create a restricted token and execute the specified process with it.
39 : *
40 : * Returns restricted token on success and 0 on failure.
41 : *
42 : * On NT4, or any other system not containing the required functions, will
43 : * NOT execute anything.
44 : */
45 : HANDLE
46 : CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, const char *progname)
47 : {
48 : BOOL b;
49 : STARTUPINFO si;
50 : HANDLE origToken;
51 : HANDLE restrictedToken;
52 : SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
53 : SID_AND_ATTRIBUTES dropSids[2];
54 : __CreateRestrictedToken _CreateRestrictedToken = NULL;
55 : HANDLE Advapi32Handle;
56 :
57 : ZeroMemory(&si, sizeof(si));
58 : si.cb = sizeof(si);
59 :
60 : Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
61 : if (Advapi32Handle != NULL)
62 : {
63 : _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
64 : }
65 :
66 : if (_CreateRestrictedToken == NULL)
67 : {
68 : fprintf(stderr, _("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
69 : if (Advapi32Handle != NULL)
70 : FreeLibrary(Advapi32Handle);
71 : return 0;
72 : }
73 :
74 : /* Open the current token to use as a base for the restricted one */
75 : if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
76 : {
77 : fprintf(stderr, _("%s: could not open process token: error code %lu\n"), progname, GetLastError());
78 : return 0;
79 : }
80 :
81 : /* Allocate list of SIDs to remove */
82 : ZeroMemory(&dropSids, sizeof(dropSids));
83 : if (!AllocateAndInitializeSid(&NtAuthority, 2,
84 : SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
85 : 0, &dropSids[0].Sid) ||
86 : !AllocateAndInitializeSid(&NtAuthority, 2,
87 : SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
88 : 0, &dropSids[1].Sid))
89 : {
90 : fprintf(stderr, _("%s: could not allocate SIDs: error code %lu\n"),
91 : progname, GetLastError());
92 : return 0;
93 : }
94 :
95 : b = _CreateRestrictedToken(origToken,
96 : DISABLE_MAX_PRIVILEGE,
97 : sizeof(dropSids) / sizeof(dropSids[0]),
98 : dropSids,
99 : 0, NULL,
100 : 0, NULL,
101 : &restrictedToken);
102 :
103 : FreeSid(dropSids[1].Sid);
104 : FreeSid(dropSids[0].Sid);
105 : CloseHandle(origToken);
106 : FreeLibrary(Advapi32Handle);
107 :
108 : if (!b)
109 : {
110 : fprintf(stderr, _("%s: could not create restricted token: error code %lu\n"),
111 : progname, GetLastError());
112 : return 0;
113 : }
114 :
115 : #ifndef __CYGWIN__
116 : AddUserToTokenDacl(restrictedToken);
117 : #endif
118 :
119 : if (!CreateProcessAsUser(restrictedToken,
120 : NULL,
121 : cmd,
122 : NULL,
123 : NULL,
124 : TRUE,
125 : CREATE_SUSPENDED,
126 : NULL,
127 : NULL,
128 : &si,
129 : processInfo))
130 :
131 : {
132 : fprintf(stderr, _("%s: could not start process for command \"%s\": error code %lu\n"), progname, cmd, GetLastError());
133 : return 0;
134 : }
135 :
136 : ResumeThread(processInfo->hThread);
137 : return restrictedToken;
138 : }
139 : #endif
140 :
141 : /*
142 : * On Windows make sure that we are running with a restricted token,
143 : * On other platforms do nothing.
144 : */
145 : void
146 1 : get_restricted_token(const char *progname)
147 : {
148 : #ifdef WIN32
149 : HANDLE restrictedToken;
150 :
151 : /*
152 : * Before we execute another program, make sure that we are running with a
153 : * restricted token. If not, re-execute ourselves with one.
154 : */
155 :
156 : if ((restrict_env = getenv("PG_RESTRICT_EXEC")) == NULL
157 : || strcmp(restrict_env, "1") != 0)
158 : {
159 : PROCESS_INFORMATION pi;
160 : char *cmdline;
161 :
162 : ZeroMemory(&pi, sizeof(pi));
163 :
164 : cmdline = pg_strdup(GetCommandLine());
165 :
166 : putenv("PG_RESTRICT_EXEC=1");
167 :
168 : if ((restrictedToken = CreateRestrictedProcess(cmdline, &pi, progname)) == 0)
169 : {
170 : fprintf(stderr, _("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
171 : }
172 : else
173 : {
174 : /*
175 : * Successfully re-execed. Now wait for child process to capture
176 : * exitcode.
177 : */
178 : DWORD x;
179 :
180 : CloseHandle(restrictedToken);
181 : CloseHandle(pi.hThread);
182 : WaitForSingleObject(pi.hProcess, INFINITE);
183 :
184 : if (!GetExitCodeProcess(pi.hProcess, &x))
185 : {
186 : fprintf(stderr, _("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
187 : exit(1);
188 : }
189 : exit(x);
190 : }
191 : }
192 : #endif
193 1 : }
|