@@ -49,6 +49,11 @@ static void copy_clog_xlog_xid(void);
49
49
static void set_frozenxids (void );
50
50
static void setup (char * argv0 ,bool live_check );
51
51
static 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
52
57
53
58
/* This is the database used by pg_dumpall to restore global tables */
54
59
#define GLOBAL_DUMP_DB "postgres"
@@ -57,6 +62,10 @@ ClusterInfo old_cluster,
57
62
new_cluster ;
58
63
OSInfo os_info ;
59
64
65
+ #ifdef WIN32
66
+ static char * restrict_env ;
67
+ #endif
68
+
60
69
int
61
70
main (int argc ,char * * argv )
62
71
{
@@ -66,6 +75,8 @@ main(int argc, char **argv)
66
75
67
76
parseCommandLine (argc ,argv );
68
77
78
+ get_restricted_token (os_info .progname );
79
+
69
80
output_check_banner (& live_check );
70
81
71
82
setup (argv [0 ],live_check );
@@ -139,6 +150,162 @@ main(int argc, char **argv)
139
150
return 0 ;
140
151
}
141
152
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
+ }
142
309
143
310
static void
144
311
setup (char * argv0 ,bool live_check )