@@ -50,6 +50,11 @@ static void copy_clog_xlog_xid(void);
5050static void set_frozenxids (void );
5151static void setup (char * argv0 , bool live_check );
5252static void cleanup (void );
53+ static void get_restricted_token (const char * progname );
54+
55+ #ifdef WIN32
56+ static int CreateRestrictedProcess (char * cmd , PROCESS_INFORMATION * processInfo , const char * progname );
57+ #endif
5358
5459ClusterInfo old_cluster ,
5560 new_cluster ;
@@ -67,6 +72,9 @@ char *output_files[] = {
6772 NULL
6873};
6974
75+ #ifdef WIN32
76+ static char * restrict_env ;
77+ #endif
7078
7179int
7280main (int argc , char * * argv )
@@ -78,6 +86,8 @@ main(int argc, char **argv)
7886
7987 parseCommandLine (argc , argv );
8088
89+ get_restricted_token (os_info .progname );
90+
8191 adjust_data_dir (& old_cluster );
8292 adjust_data_dir (& new_cluster );
8393
@@ -170,6 +180,162 @@ main(int argc, char **argv)
170180 return 0 ;
171181}
172182
183+ #ifdef WIN32
184+ typedef BOOL (WINAPI * __CreateRestrictedToken ) (HANDLE , DWORD , DWORD , PSID_AND_ATTRIBUTES , DWORD , PLUID_AND_ATTRIBUTES , DWORD , PSID_AND_ATTRIBUTES , PHANDLE );
185+
186+ /* Windows API define missing from some versions of MingW headers */
187+ #ifndef DISABLE_MAX_PRIVILEGE
188+ #define DISABLE_MAX_PRIVILEGE 0x1
189+ #endif
190+
191+ /*
192+ * Create a restricted token and execute the specified process with it.
193+ *
194+ * Returns 0 on failure, non-zero on success, same as CreateProcess().
195+ *
196+ * On NT4, or any other system not containing the required functions, will
197+ * NOT execute anything.
198+ */
199+ static int
200+ CreateRestrictedProcess (char * cmd , PROCESS_INFORMATION * processInfo , const char * progname )
201+ {
202+ BOOL b ;
203+ STARTUPINFO si ;
204+ HANDLE origToken ;
205+ HANDLE restrictedToken ;
206+ SID_IDENTIFIER_AUTHORITY NtAuthority = { SECURITY_NT_AUTHORITY };
207+ SID_AND_ATTRIBUTES dropSids [2 ];
208+ __CreateRestrictedToken _CreateRestrictedToken = NULL ;
209+ HANDLE Advapi32Handle ;
210+
211+ ZeroMemory (& si , sizeof (si ));
212+ si .cb = sizeof (si );
213+
214+ Advapi32Handle = LoadLibrary ("ADVAPI32.DLL" );
215+ if (Advapi32Handle != NULL )
216+ {
217+ _CreateRestrictedToken = (__CreateRestrictedToken )GetProcAddress (Advapi32Handle , "CreateRestrictedToken" );
218+ }
219+
220+ if (_CreateRestrictedToken == NULL )
221+ {
222+ fprintf (stderr , _ ("%s: WARNING: cannot create restricted tokens on this platform\n" ), progname );
223+ if (Advapi32Handle != NULL )
224+ FreeLibrary (Advapi32Handle );
225+ return 0 ;
226+ }
227+
228+ /* Open the current token to use as a base for the restricted one */
229+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_ALL_ACCESS , & origToken ))
230+ {
231+ fprintf (stderr , _ ("%s: could not open process token: error code %lu\n" ), progname , GetLastError ());
232+ return 0 ;
233+ }
234+
235+ /* Allocate list of SIDs to remove */
236+ ZeroMemory (& dropSids , sizeof (dropSids ));
237+ if (!AllocateAndInitializeSid (& NtAuthority , 2 ,
238+ SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_ADMINS , 0 , 0 , 0 , 0 , 0 ,
239+ 0 , & dropSids [0 ].Sid ) ||
240+ !AllocateAndInitializeSid (& NtAuthority , 2 ,
241+ SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_POWER_USERS , 0 , 0 , 0 , 0 , 0 ,
242+ 0 , & dropSids [1 ].Sid ))
243+ {
244+ fprintf (stderr , _ ("%s: could not to allocate SIDs: error code %lu\n" ), progname , GetLastError ());
245+ return 0 ;
246+ }
247+
248+ b = _CreateRestrictedToken (origToken ,
249+ DISABLE_MAX_PRIVILEGE ,
250+ sizeof (dropSids ) / sizeof (dropSids [0 ]),
251+ dropSids ,
252+ 0 , NULL ,
253+ 0 , NULL ,
254+ & restrictedToken );
255+
256+ FreeSid (dropSids [1 ].Sid );
257+ FreeSid (dropSids [0 ].Sid );
258+ CloseHandle (origToken );
259+ FreeLibrary (Advapi32Handle );
260+
261+ if (!b )
262+ {
263+ fprintf (stderr , _ ("%s: could not create restricted token: error code %lu\n" ), progname , GetLastError ());
264+ return 0 ;
265+ }
266+
267+ #ifndef __CYGWIN__
268+ AddUserToTokenDacl (restrictedToken );
269+ #endif
270+
271+ if (!CreateProcessAsUser (restrictedToken ,
272+ NULL ,
273+ cmd ,
274+ NULL ,
275+ NULL ,
276+ TRUE,
277+ CREATE_SUSPENDED ,
278+ NULL ,
279+ NULL ,
280+ & si ,
281+ processInfo ))
282+
283+ {
284+ fprintf (stderr , _ ("%s: could not start process for command \"%s\": error code %lu\n" ), progname , cmd , GetLastError ());
285+ return 0 ;
286+ }
287+
288+ return ResumeThread (processInfo -> hThread );
289+ }
290+ #endif
291+
292+ void
293+ get_restricted_token (const char * progname )
294+ {
295+ #ifdef WIN32
296+
297+ /*
298+ * Before we execute another program, make sure that we are running with a
299+ * restricted token. If not, re-execute ourselves with one.
300+ */
301+
302+ if ((restrict_env = getenv ("PG_RESTRICT_EXEC" )) == NULL
303+ || strcmp (restrict_env , "1" ) != 0 )
304+ {
305+ PROCESS_INFORMATION pi ;
306+ char * cmdline ;
307+
308+ ZeroMemory (& pi , sizeof (pi ));
309+
310+ cmdline = pg_strdup (GetCommandLine ());
311+
312+ putenv ("PG_RESTRICT_EXEC=1" );
313+
314+ if (!CreateRestrictedProcess (cmdline , & pi , progname ))
315+ {
316+ fprintf (stderr , _ ("%s: could not re-execute with restricted token: error code %lu\n" ), progname , GetLastError ());
317+ }
318+ else
319+ {
320+ /*
321+ * Successfully re-execed. Now wait for child process to capture
322+ * exitcode.
323+ */
324+ DWORD x ;
325+
326+ CloseHandle (pi .hThread );
327+ WaitForSingleObject (pi .hProcess , INFINITE );
328+
329+ if (!GetExitCodeProcess (pi .hProcess , & x ))
330+ {
331+ fprintf (stderr , _ ("%s: could not get exit code from subprocess: error code %lu\n" ), progname , GetLastError ());
332+ exit (1 );
333+ }
334+ exit (x );
335+ }
336+ }
337+ #endif
338+ }
173339
174340static void
175341setup (char * argv0 , bool live_check )
0 commit comments