@@ -49,6 +49,11 @@ static void copy_clog_xlog_xid(void);
4949static void set_frozenxids (void );
5050static void setup (char * argv0 ,bool live_check );
5151static void cleanup (void );
52+ static void get_restricted_token (const char * progname );
53+
54+ #ifdef WIN32
55+ static int CreateRestrictedProcess (char * cmd ,PROCESS_INFORMATION * processInfo ,const char * progname );
56+ #endif
5257
5358/* This is the database used by pg_dumpall to restore global tables */
5459#define GLOBAL_DUMP_DB "postgres"
@@ -57,6 +62,10 @@ ClusterInfo old_cluster,
5762new_cluster ;
5863OSInfo os_info ;
5964
65+ #ifdef WIN32
66+ static char * restrict_env ;
67+ #endif
68+
6069int
6170main (int argc ,char * * argv )
6271{
@@ -66,6 +75,8 @@ main(int argc, char **argv)
6675
6776parseCommandLine (argc ,argv );
6877
78+ get_restricted_token (os_info .progname );
79+
6980output_check_banner (& live_check );
7081
7182setup (argv [0 ],live_check );
@@ -139,6 +150,162 @@ main(int argc, char **argv)
139150return 0 ;
140151}
141152
153+ #ifdef WIN32
154+ typedef BOOL (WINAPI * __CreateRestrictedToken ) (HANDLE ,DWORD ,DWORD ,PSID_AND_ATTRIBUTES ,DWORD ,PLUID_AND_ATTRIBUTES ,DWORD ,PSID_AND_ATTRIBUTES ,PHANDLE );
155+
156+ /* Windows API define missing from some versions of MingW headers */
157+ #ifndef DISABLE_MAX_PRIVILEGE
158+ #define DISABLE_MAX_PRIVILEGE 0x1
159+ #endif
160+
161+ /*
162+ * Create a restricted token and execute the specified process with it.
163+ *
164+ * Returns 0 on failure, non-zero on success, same as CreateProcess().
165+ *
166+ * On NT4, or any other system not containing the required functions, will
167+ * NOT execute anything.
168+ */
169+ static int
170+ CreateRestrictedProcess (char * cmd ,PROCESS_INFORMATION * processInfo ,const char * progname )
171+ {
172+ BOOL b ;
173+ STARTUPINFO si ;
174+ HANDLE origToken ;
175+ HANDLE restrictedToken ;
176+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
177+ SID_AND_ATTRIBUTES dropSids [2 ];
178+ __CreateRestrictedToken _CreateRestrictedToken = NULL ;
179+ HANDLE Advapi32Handle ;
180+
181+ ZeroMemory (& si ,sizeof (si ));
182+ si .cb = sizeof (si );
183+
184+ Advapi32Handle = LoadLibrary ("ADVAPI32.DLL" );
185+ if (Advapi32Handle != NULL )
186+ {
187+ _CreateRestrictedToken = (__CreateRestrictedToken )GetProcAddress (Advapi32Handle ,"CreateRestrictedToken" );
188+ }
189+
190+ if (_CreateRestrictedToken == NULL )
191+ {
192+ fprintf (stderr ,_ ("%s: WARNING: cannot create restricted tokens on this platform\n" ),progname );
193+ if (Advapi32Handle != NULL )
194+ FreeLibrary (Advapi32Handle );
195+ return 0 ;
196+ }
197+
198+ /* Open the current token to use as a base for the restricted one */
199+ if (!OpenProcessToken (GetCurrentProcess (),TOKEN_ALL_ACCESS ,& origToken ))
200+ {
201+ fprintf (stderr ,_ ("%s: could not open process token: error code %lu\n" ),progname ,GetLastError ());
202+ return 0 ;
203+ }
204+
205+ /* Allocate list of SIDs to remove */
206+ ZeroMemory (& dropSids ,sizeof (dropSids ));
207+ if (!AllocateAndInitializeSid (& NtAuthority ,2 ,
208+ SECURITY_BUILTIN_DOMAIN_RID ,DOMAIN_ALIAS_RID_ADMINS ,0 ,0 ,0 ,0 ,0 ,
209+ 0 ,& dropSids [0 ].Sid )||
210+ !AllocateAndInitializeSid (& NtAuthority ,2 ,
211+ SECURITY_BUILTIN_DOMAIN_RID ,DOMAIN_ALIAS_RID_POWER_USERS ,0 ,0 ,0 ,0 ,0 ,
212+ 0 ,& dropSids [1 ].Sid ))
213+ {
214+ fprintf (stderr ,_ ("%s: could not to allocate SIDs: error code %lu\n" ),progname ,GetLastError ());
215+ return 0 ;
216+ }
217+
218+ b = _CreateRestrictedToken (origToken ,
219+ DISABLE_MAX_PRIVILEGE ,
220+ sizeof (dropSids ) /sizeof (dropSids [0 ]),
221+ dropSids ,
222+ 0 ,NULL ,
223+ 0 ,NULL ,
224+ & restrictedToken );
225+
226+ FreeSid (dropSids [1 ].Sid );
227+ FreeSid (dropSids [0 ].Sid );
228+ CloseHandle (origToken );
229+ FreeLibrary (Advapi32Handle );
230+
231+ if (!b )
232+ {
233+ fprintf (stderr ,_ ("%s: could not create restricted token: error code %lu\n" ),progname ,GetLastError ());
234+ return 0 ;
235+ }
236+
237+ #ifndef __CYGWIN__
238+ AddUserToTokenDacl (restrictedToken );
239+ #endif
240+
241+ if (!CreateProcessAsUser (restrictedToken ,
242+ NULL ,
243+ cmd ,
244+ NULL ,
245+ NULL ,
246+ TRUE,
247+ CREATE_SUSPENDED ,
248+ NULL ,
249+ NULL ,
250+ & si ,
251+ processInfo ))
252+
253+ {
254+ fprintf (stderr ,_ ("%s: could not start process for command \"%s\": error code %lu\n" ),progname ,cmd ,GetLastError ());
255+ return 0 ;
256+ }
257+
258+ return ResumeThread (processInfo -> hThread );
259+ }
260+ #endif
261+
262+ void
263+ get_restricted_token (const char * progname )
264+ {
265+ #ifdef WIN32
266+
267+ /*
268+ * Before we execute another program, make sure that we are running with a
269+ * restricted token. If not, re-execute ourselves with one.
270+ */
271+
272+ if ((restrict_env = getenv ("PG_RESTRICT_EXEC" ))== NULL
273+ || strcmp (restrict_env ,"1" )!= 0 )
274+ {
275+ PROCESS_INFORMATION pi ;
276+ char * cmdline ;
277+
278+ ZeroMemory (& pi ,sizeof (pi ));
279+
280+ cmdline = pg_strdup (GetCommandLine ());
281+
282+ putenv ("PG_RESTRICT_EXEC=1" );
283+
284+ if (!CreateRestrictedProcess (cmdline ,& pi ,progname ))
285+ {
286+ fprintf (stderr ,_ ("%s: could not re-execute with restricted token: error code %lu\n" ),progname ,GetLastError ());
287+ }
288+ else
289+ {
290+ /*
291+ * Successfully re-execed. Now wait for child process to capture
292+ * exitcode.
293+ */
294+ DWORD x ;
295+
296+ CloseHandle (pi .hThread );
297+ WaitForSingleObject (pi .hProcess ,INFINITE );
298+
299+ if (!GetExitCodeProcess (pi .hProcess ,& x ))
300+ {
301+ fprintf (stderr ,_ ("%s: could not get exit code from subprocess: error code %lu\n" ),progname ,GetLastError ());
302+ exit (1 );
303+ }
304+ exit (x );
305+ }
306+ }
307+ #endif
308+ }
142309
143310static void
144311setup (char * argv0 ,bool live_check )