@@ -21,7 +21,16 @@ static void copy_clog_xlog_xid(migratorContext *ctx);
2121static void set_frozenxids (migratorContext * ctx );
2222static void setup (migratorContext * ctx ,char * argv0 ,bool live_check );
2323static void cleanup (migratorContext * ctx );
24+ static void get_restricted_token (const char * progname );
2425
26+ #ifdef WIN32
27+ static char * pg_strdupn (const char * str );
28+ static int CreateRestrictedProcess (char * cmd ,PROCESS_INFORMATION * processInfo ,const char * progname );
29+ #endif
30+
31+ #ifdef WIN32
32+ static char * restrict_env ;
33+ #endif
2534
2635int
2736main (int argc ,char * * argv )
@@ -35,6 +44,8 @@ main(int argc, char **argv)
3544
3645parseCommandLine (& ctx ,argc ,argv );
3746
47+ get_restricted_token (ctx .progname );
48+
3849output_check_banner (& ctx ,& live_check );
3950
4051setup (& ctx ,argv [0 ],live_check );
@@ -103,6 +114,162 @@ main(int argc, char **argv)
103114return 0 ;
104115}
105116
117+ #ifdef WIN32
118+ typedef BOOL (WINAPI * __CreateRestrictedToken ) (HANDLE ,DWORD ,DWORD ,PSID_AND_ATTRIBUTES ,DWORD ,PLUID_AND_ATTRIBUTES ,DWORD ,PSID_AND_ATTRIBUTES ,PHANDLE );
119+
120+ /* Windows API define missing from some versions of MingW headers */
121+ #ifndef DISABLE_MAX_PRIVILEGE
122+ #define DISABLE_MAX_PRIVILEGE 0x1
123+ #endif
124+
125+ /*
126+ * Create a restricted token and execute the specified process with it.
127+ *
128+ * Returns 0 on failure, non-zero on success, same as CreateProcess().
129+ *
130+ * On NT4, or any other system not containing the required functions, will
131+ * NOT execute anything.
132+ */
133+ static int
134+ CreateRestrictedProcess (char * cmd ,PROCESS_INFORMATION * processInfo ,const char * progname )
135+ {
136+ BOOL b ;
137+ STARTUPINFO si ;
138+ HANDLE origToken ;
139+ HANDLE restrictedToken ;
140+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
141+ SID_AND_ATTRIBUTES dropSids [2 ];
142+ __CreateRestrictedToken _CreateRestrictedToken = NULL ;
143+ HANDLE Advapi32Handle ;
144+
145+ ZeroMemory (& si ,sizeof (si ));
146+ si .cb = sizeof (si );
147+
148+ Advapi32Handle = LoadLibrary ("ADVAPI32.DLL" );
149+ if (Advapi32Handle != NULL )
150+ {
151+ _CreateRestrictedToken = (__CreateRestrictedToken )GetProcAddress (Advapi32Handle ,"CreateRestrictedToken" );
152+ }
153+
154+ if (_CreateRestrictedToken == NULL )
155+ {
156+ fprintf (stderr ,_ ("%s: WARNING: cannot create restricted tokens on this platform\n" ),progname );
157+ if (Advapi32Handle != NULL )
158+ FreeLibrary (Advapi32Handle );
159+ return 0 ;
160+ }
161+
162+ /* Open the current token to use as a base for the restricted one */
163+ if (!OpenProcessToken (GetCurrentProcess (),TOKEN_ALL_ACCESS ,& origToken ))
164+ {
165+ fprintf (stderr ,_ ("%s: could not open process token: error code %lu\n" ),progname ,GetLastError ());
166+ return 0 ;
167+ }
168+
169+ /* Allocate list of SIDs to remove */
170+ ZeroMemory (& dropSids ,sizeof (dropSids ));
171+ if (!AllocateAndInitializeSid (& NtAuthority ,2 ,
172+ SECURITY_BUILTIN_DOMAIN_RID ,DOMAIN_ALIAS_RID_ADMINS ,0 ,0 ,0 ,0 ,0 ,
173+ 0 ,& dropSids [0 ].Sid )||
174+ !AllocateAndInitializeSid (& NtAuthority ,2 ,
175+ SECURITY_BUILTIN_DOMAIN_RID ,DOMAIN_ALIAS_RID_POWER_USERS ,0 ,0 ,0 ,0 ,0 ,
176+ 0 ,& dropSids [1 ].Sid ))
177+ {
178+ fprintf (stderr ,_ ("%s: could not to allocate SIDs: error code %lu\n" ),progname ,GetLastError ());
179+ return 0 ;
180+ }
181+
182+ b = _CreateRestrictedToken (origToken ,
183+ DISABLE_MAX_PRIVILEGE ,
184+ sizeof (dropSids ) /sizeof (dropSids [0 ]),
185+ dropSids ,
186+ 0 ,NULL ,
187+ 0 ,NULL ,
188+ & restrictedToken );
189+
190+ FreeSid (dropSids [1 ].Sid );
191+ FreeSid (dropSids [0 ].Sid );
192+ CloseHandle (origToken );
193+ FreeLibrary (Advapi32Handle );
194+
195+ if (!b )
196+ {
197+ fprintf (stderr ,_ ("%s: could not create restricted token: error code %lu\n" ),progname ,GetLastError ());
198+ return 0 ;
199+ }
200+
201+ #ifndef __CYGWIN__
202+ AddUserToTokenDacl (restrictedToken );
203+ #endif
204+
205+ if (!CreateProcessAsUser (restrictedToken ,
206+ NULL ,
207+ cmd ,
208+ NULL ,
209+ NULL ,
210+ TRUE,
211+ CREATE_SUSPENDED ,
212+ NULL ,
213+ NULL ,
214+ & si ,
215+ processInfo ))
216+
217+ {
218+ fprintf (stderr ,_ ("%s: could not start process for command \"%s\": error code %lu\n" ),progname ,cmd ,GetLastError ());
219+ return 0 ;
220+ }
221+
222+ return ResumeThread (processInfo -> hThread );
223+ }
224+ #endif
225+
226+ void
227+ get_restricted_token (const char * progname )
228+ {
229+ #ifdef WIN32
230+
231+ /*
232+ * Before we execute another program, make sure that we are running with a
233+ * restricted token. If not, re-execute ourselves with one.
234+ */
235+
236+ if ((restrict_env = getenv ("PG_RESTRICT_EXEC" ))== NULL
237+ || strcmp (restrict_env ,"1" )!= 0 )
238+ {
239+ PROCESS_INFORMATION pi ;
240+ char * cmdline ;
241+
242+ ZeroMemory (& pi ,sizeof (pi ));
243+
244+ cmdline = pg_strdupn (GetCommandLine ());
245+
246+ putenv ("PG_RESTRICT_EXEC=1" );
247+
248+ if (!CreateRestrictedProcess (cmdline ,& pi ,progname ))
249+ {
250+ fprintf (stderr ,_ ("%s: could not re-execute with restricted token: error code %lu\n" ),progname ,GetLastError ());
251+ }
252+ else
253+ {
254+ /*
255+ * Successfully re-execed. Now wait for child process to capture
256+ * exitcode.
257+ */
258+ DWORD x ;
259+
260+ CloseHandle (pi .hThread );
261+ WaitForSingleObject (pi .hProcess ,INFINITE );
262+
263+ if (!GetExitCodeProcess (pi .hProcess ,& x ))
264+ {
265+ fprintf (stderr ,_ ("%s: could not get exit code from subprocess: error code %lu\n" ),progname ,GetLastError ());
266+ exit (1 );
267+ }
268+ exit (x );
269+ }
270+ }
271+ #endif
272+ }
106273
107274static void
108275setup (migratorContext * ctx ,char * argv0 ,bool live_check )
@@ -443,3 +610,18 @@ cleanup(migratorContext *ctx)
443610snprintf (filename ,sizeof (filename ),"%s/%s" ,ctx -> cwd ,DB_DUMP_FILE );
444611unlink (filename );
445612}
613+
614+ #ifdef WIN32
615+ static char *
616+ pg_strdupn (const char * str )
617+ {
618+ char * result = strdup (str );
619+
620+ if (!result )
621+ {
622+ fprintf (stderr ,_ ("out of memory\n" ));
623+ exit (1 );
624+ }
625+ return result ;
626+ }
627+ #endif