@@ -21,7 +21,16 @@ static void copy_clog_xlog_xid(migratorContext *ctx);
21
21
static void set_frozenxids (migratorContext * ctx );
22
22
static void setup (migratorContext * ctx ,char * argv0 ,bool live_check );
23
23
static void cleanup (migratorContext * ctx );
24
+ static void get_restricted_token (const char * progname );
24
25
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
25
34
26
35
int
27
36
main (int argc ,char * * argv )
@@ -35,6 +44,8 @@ main(int argc, char **argv)
35
44
36
45
parseCommandLine (& ctx ,argc ,argv );
37
46
47
+ get_restricted_token (ctx .progname );
48
+
38
49
output_check_banner (& ctx ,& live_check );
39
50
40
51
setup (& ctx ,argv [0 ],live_check );
@@ -103,6 +114,162 @@ main(int argc, char **argv)
103
114
return 0 ;
104
115
}
105
116
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
+ }
106
273
107
274
static void
108
275
setup (migratorContext * ctx ,char * argv0 ,bool live_check )
@@ -443,3 +610,18 @@ cleanup(migratorContext *ctx)
443
610
snprintf (filename ,sizeof (filename ),"%s/%s" ,ctx -> cwd ,DB_DUMP_FILE );
444
611
unlink (filename );
445
612
}
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