@@ -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 ,
5560new_cluster ;
@@ -67,6 +72,9 @@ char *output_files[] = {
6772NULL
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
7987parseCommandLine (argc ,argv );
8088
89+ get_restricted_token (os_info .progname );
90+
8191adjust_data_dir (& old_cluster );
8292adjust_data_dir (& new_cluster );
8393
@@ -170,6 +180,162 @@ main(int argc, char **argv)
170180return 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 )