Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita25cd81

Browse files
committed
Enable pg_ctl to give up admin privileges when starting the server under
Windows (if newer than NT4, else works same as before).Magnus
1 parenteb6d127 commita25cd81

File tree

1 file changed

+219
-27
lines changed

1 file changed

+219
-27
lines changed

‎src/bin/pg_ctl/pg_ctl.c

Lines changed: 219 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@
44
*
55
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.65 2006/02/07 11:36:36 petere Exp $
7+
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.66 2006/02/10 22:00:59 tgl Exp $
88
*
99
*-------------------------------------------------------------------------
1010
*/
1111

12+
#ifdefWIN32
13+
/*
14+
* Need this to get defines for restricted tokens and jobs. And it
15+
* has to be set before any header from the Win32 API is loaded.
16+
*/
17+
#define_WIN32_WINNT 0x0500
18+
#endif
19+
1220
#include"postgres_fe.h"
1321
#include"libpq-fe.h"
1422

@@ -111,6 +119,7 @@ static void pgwin32_SetServiceStatus(DWORD);
111119
staticvoidWINAPIpgwin32_ServiceHandler(DWORD);
112120
staticvoidWINAPIpgwin32_ServiceMain(DWORD,LPTSTR*);
113121
staticvoidpgwin32_doRunAsService(void);
122+
staticintCreateRestrictedProcess(char*cmd,PROCESS_INFORMATION*processInfo);
114123
#endif
115124
staticpgpid_tget_pgpid(void);
116125
staticchar**readfile(constchar*path);
@@ -325,42 +334,46 @@ readfile(const char *path)
325334
staticint
326335
start_postmaster(void)
327336
{
337+
charcmd[MAXPGPATH];
338+
#ifndefWIN32
328339
/*
329340
* Since there might be quotes to handle here, it is easier simply to pass
330341
* everything to a shell to process them.
331342
*/
332-
charcmd[MAXPGPATH];
333-
334-
/*
335-
* Win32 needs START /B rather than "&".
336-
*
337-
* Win32 has a problem with START and quoted executable names. You must
338-
* add a "" as the title at the beginning so you can quote the executable
339-
* name: http://www.winnetmag.com/Article/ArticleID/14589/14589.html
340-
* http://dev.remotenetworktechnology.com/cmd/cmdfaq.htm
341-
*/
342343
if (log_file!=NULL)
343-
#ifndefWIN32/* Cygwin doesn't have START */
344344
snprintf(cmd,MAXPGPATH,"%s\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &%s",
345345
SYSTEMQUOTE,postgres_path,pgdata_opt,post_opts,
346346
DEVNULL,log_file,SYSTEMQUOTE);
347-
#else
348-
snprintf(cmd,MAXPGPATH,"%sSTART /B \"\" \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1%s",
349-
SYSTEMQUOTE,postgres_path,pgdata_opt,post_opts,
350-
DEVNULL,log_file,SYSTEMQUOTE);
351-
#endif
352-
else
353-
#ifndefWIN32/* Cygwin doesn't have START */
347+
else
354348
snprintf(cmd,MAXPGPATH,"%s\"%s\" %s%s < \"%s\" 2>&1 &%s",
355349
SYSTEMQUOTE,postgres_path,pgdata_opt,post_opts,
356350
DEVNULL,SYSTEMQUOTE);
357-
#else
358-
snprintf(cmd,MAXPGPATH,"%sSTART /B \"\" \"%s\" %s%s < \"%s\" 2>&1%s",
351+
352+
returnsystem(cmd);
353+
354+
#else/* WIN32 */
355+
/*
356+
* On win32 we don't use system(). So we don't need to use &
357+
* (which would be START /B on win32). However, we still call the shell
358+
* (CMD.EXE) with it to handle redirection etc.
359+
*/
360+
PROCESS_INFORMATIONpi;
361+
362+
if (log_file!=NULL)
363+
snprintf(cmd,MAXPGPATH,"CMD /C %s\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1%s",
364+
SYSTEMQUOTE,postgres_path,pgdata_opt,post_opts,
365+
DEVNULL,log_file,SYSTEMQUOTE);
366+
else
367+
snprintf(cmd,MAXPGPATH,"CMD /C %s\"%s\" %s%s < \"%s\" 2>&1%s",
359368
SYSTEMQUOTE,postgres_path,pgdata_opt,post_opts,
360369
DEVNULL,SYSTEMQUOTE);
361-
#endif
362370

363-
returnsystem(cmd);
371+
if (!CreateRestrictedProcess(cmd,&pi))
372+
returnGetLastError();
373+
CloseHandle(pi.hProcess);
374+
CloseHandle(pi.hThread);
375+
return0;
376+
#endif/* WIN32 */
364377
}
365378

366379

@@ -1063,7 +1076,6 @@ pgwin32_ServiceHandler(DWORD request)
10631076
staticvoidWINAPI
10641077
pgwin32_ServiceMain(DWORDargc,LPTSTR*argv)
10651078
{
1066-
STARTUPINFOsi;
10671079
PROCESS_INFORMATIONpi;
10681080
DWORDret;
10691081

@@ -1077,8 +1089,6 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
10771089
status.dwCurrentState=SERVICE_START_PENDING;
10781090

10791091
memset(&pi,0,sizeof(pi));
1080-
memset(&si,0,sizeof(si));
1081-
si.cb=sizeof(si);
10821092

10831093
/* Register the control request handler */
10841094
if ((hStatus=RegisterServiceCtrlHandler(register_servicename,pgwin32_ServiceHandler))== (SERVICE_STATUS_HANDLE)0)
@@ -1089,7 +1099,7 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
10891099

10901100
/* Start the postmaster */
10911101
pgwin32_SetServiceStatus(SERVICE_START_PENDING);
1092-
if (!CreateProcess(NULL,pgwin32_CommandLine(false),NULL,NULL, TRUE,0,NULL,NULL,&si,&pi))
1102+
if (!CreateRestrictedProcess(pgwin32_CommandLine(false),&pi))
10931103
{
10941104
pgwin32_SetServiceStatus(SERVICE_STOPPED);
10951105
return;
@@ -1141,6 +1151,188 @@ pgwin32_doRunAsService(void)
11411151
exit(1);
11421152
}
11431153
}
1154+
1155+
1156+
/*
1157+
* Mingw headers are incomplete, and so are the libraries. So we have to load
1158+
* a whole lot of API functions dynamically. Since we have to do this anyway,
1159+
* also load the couple of functions that *do* exist in minwg headers but not
1160+
* on NT4. That way, we don't break on NT4.
1161+
*/
1162+
typedefWINAPIBOOL (*__CreateRestrictedToken)(HANDLE,DWORD,DWORD,PSID_AND_ATTRIBUTES,DWORD,PLUID_AND_ATTRIBUTES,DWORD,PSID_AND_ATTRIBUTES,PHANDLE);
1163+
typedefWINAPIBOOL (*__IsProcessInJob)(HANDLE,HANDLE,PBOOL);
1164+
typedefWINAPIHANDLE (*__CreateJobObject)(LPSECURITY_ATTRIBUTES,LPCTSTR);
1165+
typedefWINAPIBOOL (*__SetInformationJobObject)(HANDLE,JOBOBJECTINFOCLASS,LPVOID,DWORD);
1166+
typedefWINAPIBOOL (*__AssignProcessToJobObject)(HANDLE,HANDLE);
1167+
typedefWINAPIBOOL (*__QueryInformationJobObject)(HANDLE,JOBOBJECTINFOCLASS,LPVOID,DWORD,LPDWORD);
1168+
1169+
/* Windows API define missing from MingW headers */
1170+
#defineDISABLE_MAX_PRIVILEGE 0x1
1171+
1172+
/*
1173+
* Create a restricted token, a job object sandbox, and execute the specified
1174+
* process with it.
1175+
*
1176+
* Returns 0 on success, non-zero on failure, same as CreateProcess().
1177+
*
1178+
* On NT4, or any other system not containing the required functions, will
1179+
* launch the process under the current token without doing any modifications.
1180+
*
1181+
* NOTE! Job object will only work when running as a service, because it's
1182+
* automatically destroyed when pg_ctl exits.
1183+
*/
1184+
staticint
1185+
CreateRestrictedProcess(char*cmd,PROCESS_INFORMATION*processInfo)
1186+
{
1187+
intr;
1188+
BOOLb;
1189+
STARTUPINFOsi;
1190+
HANDLEorigToken;
1191+
HANDLErestrictedToken;
1192+
SID_IDENTIFIER_AUTHORITYNtAuthority= {SECURITY_NT_AUTHORITY};
1193+
SID_AND_ATTRIBUTESdropSids[2];
1194+
1195+
/* Functions loaded dynamically */
1196+
__CreateRestrictedToken_CreateRestrictedToken=NULL;
1197+
__IsProcessInJob_IsProcessInJob=NULL;
1198+
__CreateJobObject_CreateJobObject=NULL;
1199+
__SetInformationJobObject_SetInformationJobObject=NULL;
1200+
__AssignProcessToJobObject_AssignProcessToJobObject=NULL;
1201+
__QueryInformationJobObject_QueryInformationJobObject=NULL;
1202+
HANDLEKernel32Handle;
1203+
HANDLEAdvapi32Handle;
1204+
1205+
ZeroMemory(&si,sizeof(si));
1206+
si.cb=sizeof(si);
1207+
1208+
Advapi32Handle=LoadLibrary("ADVAPI32.DLL");
1209+
if (Advapi32Handle!=NULL)
1210+
{
1211+
_CreateRestrictedToken= (__CreateRestrictedToken)GetProcAddress(Advapi32Handle,"CreateRestrictedToken");
1212+
}
1213+
1214+
if (_CreateRestrictedToken==NULL)
1215+
{
1216+
/* NT4 doesn't have CreateRestrictedToken, so just call ordinary CreateProcess */
1217+
write_stderr("WARNING: Unable to create restricted tokens on this platform\n");
1218+
if (Advapi32Handle!=NULL)
1219+
FreeLibrary(Advapi32Handle);
1220+
returnCreateProcess(NULL,cmd,NULL,NULL, FALSE,0,NULL,NULL,&si,processInfo);
1221+
}
1222+
1223+
/* Open the current token to use as a base for the restricted one */
1224+
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&origToken))
1225+
{
1226+
write_stderr("Failed to open process token: %lu\n",GetLastError());
1227+
return0;
1228+
}
1229+
1230+
/* Allocate list of SIDs to remove */
1231+
ZeroMemory(&dropSids,sizeof(dropSids));
1232+
if (!AllocateAndInitializeSid(&NtAuthority,2,
1233+
SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS,0,0,0,0,0,
1234+
0,&dropSids[0].Sid)||
1235+
!AllocateAndInitializeSid(&NtAuthority,2,
1236+
SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_POWER_USERS,0,0,0,0,0,
1237+
0,&dropSids[1].Sid))
1238+
{
1239+
write_stderr("Failed to allocate SIDs: %lu\n",GetLastError());
1240+
return0;
1241+
}
1242+
1243+
b=_CreateRestrictedToken(origToken,
1244+
DISABLE_MAX_PRIVILEGE,
1245+
sizeof(dropSids)/sizeof(dropSids[0]),
1246+
dropSids,
1247+
0,NULL,
1248+
0,NULL,
1249+
&restrictedToken);
1250+
1251+
FreeSid(dropSids[1].Sid);
1252+
FreeSid(dropSids[0].Sid);
1253+
CloseHandle(origToken);
1254+
FreeLibrary(Advapi32Handle);
1255+
1256+
if (!b)
1257+
{
1258+
write_stderr("Failed to create restricted token: %lu\n",GetLastError());
1259+
return0;
1260+
}
1261+
1262+
r=CreateProcessAsUser(restrictedToken,NULL,cmd,NULL,NULL, TRUE,CREATE_SUSPENDED,NULL,NULL,&si,processInfo);
1263+
1264+
Kernel32Handle=LoadLibrary("KERNEL32.DLL");
1265+
if (Kernel32Handle!=NULL)
1266+
{
1267+
_IsProcessInJob= (__IsProcessInJob)GetProcAddress(Kernel32Handle,"IsProcessInJob");
1268+
_CreateJobObject= (__CreateJobObject)GetProcAddress(Kernel32Handle,"CreateJobObjectA");
1269+
_SetInformationJobObject= (__SetInformationJobObject)GetProcAddress(Kernel32Handle,"SetInformationJobObject");
1270+
_AssignProcessToJobObject= (__AssignProcessToJobObject)GetProcAddress(Kernel32Handle,"AssignProcessToJobObject");
1271+
_QueryInformationJobObject= (__QueryInformationJobObject)GetProcAddress(Kernel32Handle,"QueryInformationJobObject");
1272+
}
1273+
1274+
/* Verify that we found all functions */
1275+
if (_IsProcessInJob==NULL||_CreateJobObject==NULL||_SetInformationJobObject==NULL||_AssignProcessToJobObject==NULL||_QueryInformationJobObject==NULL)
1276+
{
1277+
write_stderr("WARNING: Unable to locate all job object functions in system API!\n");
1278+
}
1279+
else
1280+
{
1281+
BOOLinJob;
1282+
if (_IsProcessInJob(processInfo->hProcess,NULL,&inJob))
1283+
{
1284+
if (!inJob)
1285+
{
1286+
/* Job objects are working, and the new process isn't in one, so we can create one safely.
1287+
If any problems show up when setting it, we're going to ignore them. */
1288+
HANDLEjob;
1289+
charjobname[128];
1290+
1291+
sprintf(jobname,"PostgreSQL_%lu",processInfo->dwProcessId);
1292+
1293+
job=_CreateJobObject(NULL,jobname);
1294+
if (job)
1295+
{
1296+
JOBOBJECT_BASIC_LIMIT_INFORMATIONbasicLimit;
1297+
JOBOBJECT_BASIC_UI_RESTRICTIONSuiRestrictions;
1298+
JOBOBJECT_SECURITY_LIMIT_INFORMATIONsecurityLimit;
1299+
1300+
ZeroMemory(&basicLimit,sizeof(basicLimit));
1301+
ZeroMemory(&uiRestrictions,sizeof(uiRestrictions));
1302+
ZeroMemory(&securityLimit,sizeof(securityLimit));
1303+
1304+
basicLimit.LimitFlags=JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |JOB_OBJECT_LIMIT_PRIORITY_CLASS;
1305+
basicLimit.PriorityClass=NORMAL_PRIORITY_CLASS;
1306+
_SetInformationJobObject(job,JobObjectBasicLimitInformation,&basicLimit,sizeof(basicLimit));
1307+
1308+
uiRestrictions.UIRestrictionsClass=JOB_OBJECT_UILIMIT_DESKTOP |JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
1309+
JOB_OBJECT_UILIMIT_EXITWINDOWS |JOB_OBJECT_UILIMIT_HANDLES |JOB_OBJECT_UILIMIT_READCLIPBOARD |
1310+
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS |JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
1311+
_SetInformationJobObject(job,JobObjectBasicUIRestrictions,&uiRestrictions,sizeof(uiRestrictions));
1312+
1313+
securityLimit.SecurityLimitFlags=JOB_OBJECT_SECURITY_NO_ADMIN |JOB_OBJECT_SECURITY_ONLY_TOKEN;
1314+
securityLimit.JobToken=restrictedToken;
1315+
_SetInformationJobObject(job,JobObjectSecurityLimitInformation,&securityLimit,sizeof(securityLimit));
1316+
1317+
_AssignProcessToJobObject(job,processInfo->hProcess);
1318+
}
1319+
}
1320+
}
1321+
}
1322+
1323+
CloseHandle(restrictedToken);
1324+
1325+
ResumeThread(processInfo->hThread);
1326+
1327+
FreeLibrary(Kernel32Handle);
1328+
1329+
/*
1330+
* We intentionally don't close the job object handle, because we want the
1331+
* object to live on until pg_ctl shuts down.
1332+
*/
1333+
returnr;
1334+
}
1335+
11441336
#endif
11451337

11461338
staticvoid

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp