Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
a25cd810
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
a25cd810
编写于
2月 10, 2006
作者:
T
Tom Lane
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Enable pg_ctl to give up admin privileges when starting the server under
Windows (if newer than NT4, else works same as before). Magnus
上级
eb6d1270
变更
1
显示空白变更内容
内联
并排
Showing
1 changed file
with
219 addition
and
27 deletion
+219
-27
src/bin/pg_ctl/pg_ctl.c
src/bin/pg_ctl/pg_ctl.c
+219
-27
未找到文件。
src/bin/pg_ctl/pg_ctl.c
浏览文件 @
a25cd810
...
...
@@ -4,11 +4,19 @@
*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.6
5 2006/02/07 11:36:36 petere
Exp $
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.6
6 2006/02/10 22:00:59 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
#ifdef WIN32
/*
* Need this to get defines for restricted tokens and jobs. And it
* has to be set before any header from the Win32 API is loaded.
*/
#define _WIN32_WINNT 0x0500
#endif
#include "postgres_fe.h"
#include "libpq-fe.h"
...
...
@@ -111,6 +119,7 @@ static void pgwin32_SetServiceStatus(DWORD);
static
void
WINAPI
pgwin32_ServiceHandler
(
DWORD
);
static
void
WINAPI
pgwin32_ServiceMain
(
DWORD
,
LPTSTR
*
);
static
void
pgwin32_doRunAsService
(
void
);
static
int
CreateRestrictedProcess
(
char
*
cmd
,
PROCESS_INFORMATION
*
processInfo
);
#endif
static
pgpid_t
get_pgpid
(
void
);
static
char
**
readfile
(
const
char
*
path
);
...
...
@@ -325,42 +334,46 @@ readfile(const char *path)
static
int
start_postmaster
(
void
)
{
char
cmd
[
MAXPGPATH
];
#ifndef WIN32
/*
* Since there might be quotes to handle here, it is easier simply to pass
* everything to a shell to process them.
*/
char
cmd
[
MAXPGPATH
];
/*
* Win32 needs START /B rather than "&".
*
* Win32 has a problem with START and quoted executable names. You must
* add a "" as the title at the beginning so you can quote the executable
* name: http://www.winnetmag.com/Article/ArticleID/14589/14589.html
* http://dev.remotenetworktechnology.com/cmd/cmdfaq.htm
*/
if
(
log_file
!=
NULL
)
#ifndef WIN32
/* Cygwin doesn't have START */
snprintf
(
cmd
,
MAXPGPATH
,
"%s
\"
%s
\"
%s%s <
\"
%s
\"
>>
\"
%s
\"
2>&1 &%s"
,
SYSTEMQUOTE
,
postgres_path
,
pgdata_opt
,
post_opts
,
DEVNULL
,
log_file
,
SYSTEMQUOTE
);
#else
snprintf
(
cmd
,
MAXPGPATH
,
"%sSTART /B
\"\"
\"
%s
\"
%s%s <
\"
%s
\"
>>
\"
%s
\"
2>&1%s"
,
SYSTEMQUOTE
,
postgres_path
,
pgdata_opt
,
post_opts
,
DEVNULL
,
log_file
,
SYSTEMQUOTE
);
#endif
else
#ifndef WIN32
/* Cygwin doesn't have START */
snprintf
(
cmd
,
MAXPGPATH
,
"%s
\"
%s
\"
%s%s <
\"
%s
\"
2>&1 &%s"
,
SYSTEMQUOTE
,
postgres_path
,
pgdata_opt
,
post_opts
,
DEVNULL
,
SYSTEMQUOTE
);
#else
snprintf
(
cmd
,
MAXPGPATH
,
"%sSTART /B
\"\"
\"
%s
\"
%s%s <
\"
%s
\"
2>&1%s"
,
return
system
(
cmd
);
#else
/* WIN32 */
/*
* On win32 we don't use system(). So we don't need to use &
* (which would be START /B on win32). However, we still call the shell
* (CMD.EXE) with it to handle redirection etc.
*/
PROCESS_INFORMATION
pi
;
if
(
log_file
!=
NULL
)
snprintf
(
cmd
,
MAXPGPATH
,
"CMD /C %s
\"
%s
\"
%s%s <
\"
%s
\"
>>
\"
%s
\"
2>&1%s"
,
SYSTEMQUOTE
,
postgres_path
,
pgdata_opt
,
post_opts
,
DEVNULL
,
log_file
,
SYSTEMQUOTE
);
else
snprintf
(
cmd
,
MAXPGPATH
,
"CMD /C %s
\"
%s
\"
%s%s <
\"
%s
\"
2>&1%s"
,
SYSTEMQUOTE
,
postgres_path
,
pgdata_opt
,
post_opts
,
DEVNULL
,
SYSTEMQUOTE
);
#endif
return
system
(
cmd
);
if
(
!
CreateRestrictedProcess
(
cmd
,
&
pi
))
return
GetLastError
();
CloseHandle
(
pi
.
hProcess
);
CloseHandle
(
pi
.
hThread
);
return
0
;
#endif
/* WIN32 */
}
...
...
@@ -1063,7 +1076,6 @@ pgwin32_ServiceHandler(DWORD request)
static
void
WINAPI
pgwin32_ServiceMain
(
DWORD
argc
,
LPTSTR
*
argv
)
{
STARTUPINFO
si
;
PROCESS_INFORMATION
pi
;
DWORD
ret
;
...
...
@@ -1077,8 +1089,6 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
status
.
dwCurrentState
=
SERVICE_START_PENDING
;
memset
(
&
pi
,
0
,
sizeof
(
pi
));
memset
(
&
si
,
0
,
sizeof
(
si
));
si
.
cb
=
sizeof
(
si
);
/* Register the control request handler */
if
((
hStatus
=
RegisterServiceCtrlHandler
(
register_servicename
,
pgwin32_ServiceHandler
))
==
(
SERVICE_STATUS_HANDLE
)
0
)
...
...
@@ -1089,7 +1099,7 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
/* Start the postmaster */
pgwin32_SetServiceStatus
(
SERVICE_START_PENDING
);
if
(
!
Create
Process
(
NULL
,
pgwin32_CommandLine
(
false
),
NULL
,
NULL
,
TRUE
,
0
,
NULL
,
NULL
,
&
si
,
&
pi
))
if
(
!
Create
RestrictedProcess
(
pgwin32_CommandLine
(
false
)
,
&
pi
))
{
pgwin32_SetServiceStatus
(
SERVICE_STOPPED
);
return
;
...
...
@@ -1141,6 +1151,188 @@ pgwin32_doRunAsService(void)
exit
(
1
);
}
}
/*
* Mingw headers are incomplete, and so are the libraries. So we have to load
* a whole lot of API functions dynamically. Since we have to do this anyway,
* also load the couple of functions that *do* exist in minwg headers but not
* on NT4. That way, we don't break on NT4.
*/
typedef
WINAPI
BOOL
(
*
__CreateRestrictedToken
)(
HANDLE
,
DWORD
,
DWORD
,
PSID_AND_ATTRIBUTES
,
DWORD
,
PLUID_AND_ATTRIBUTES
,
DWORD
,
PSID_AND_ATTRIBUTES
,
PHANDLE
);
typedef
WINAPI
BOOL
(
*
__IsProcessInJob
)(
HANDLE
,
HANDLE
,
PBOOL
);
typedef
WINAPI
HANDLE
(
*
__CreateJobObject
)(
LPSECURITY_ATTRIBUTES
,
LPCTSTR
);
typedef
WINAPI
BOOL
(
*
__SetInformationJobObject
)(
HANDLE
,
JOBOBJECTINFOCLASS
,
LPVOID
,
DWORD
);
typedef
WINAPI
BOOL
(
*
__AssignProcessToJobObject
)(
HANDLE
,
HANDLE
);
typedef
WINAPI
BOOL
(
*
__QueryInformationJobObject
)(
HANDLE
,
JOBOBJECTINFOCLASS
,
LPVOID
,
DWORD
,
LPDWORD
);
/* Windows API define missing from MingW headers */
#define DISABLE_MAX_PRIVILEGE 0x1
/*
* Create a restricted token, a job object sandbox, and execute the specified
* process with it.
*
* Returns 0 on success, non-zero on failure, same as CreateProcess().
*
* On NT4, or any other system not containing the required functions, will
* launch the process under the current token without doing any modifications.
*
* NOTE! Job object will only work when running as a service, because it's
* automatically destroyed when pg_ctl exits.
*/
static
int
CreateRestrictedProcess
(
char
*
cmd
,
PROCESS_INFORMATION
*
processInfo
)
{
int
r
;
BOOL
b
;
STARTUPINFO
si
;
HANDLE
origToken
;
HANDLE
restrictedToken
;
SID_IDENTIFIER_AUTHORITY
NtAuthority
=
{
SECURITY_NT_AUTHORITY
};
SID_AND_ATTRIBUTES
dropSids
[
2
];
/* Functions loaded dynamically */
__CreateRestrictedToken
_CreateRestrictedToken
=
NULL
;
__IsProcessInJob
_IsProcessInJob
=
NULL
;
__CreateJobObject
_CreateJobObject
=
NULL
;
__SetInformationJobObject
_SetInformationJobObject
=
NULL
;
__AssignProcessToJobObject
_AssignProcessToJobObject
=
NULL
;
__QueryInformationJobObject
_QueryInformationJobObject
=
NULL
;
HANDLE
Kernel32Handle
;
HANDLE
Advapi32Handle
;
ZeroMemory
(
&
si
,
sizeof
(
si
));
si
.
cb
=
sizeof
(
si
);
Advapi32Handle
=
LoadLibrary
(
"ADVAPI32.DLL"
);
if
(
Advapi32Handle
!=
NULL
)
{
_CreateRestrictedToken
=
(
__CreateRestrictedToken
)
GetProcAddress
(
Advapi32Handle
,
"CreateRestrictedToken"
);
}
if
(
_CreateRestrictedToken
==
NULL
)
{
/* NT4 doesn't have CreateRestrictedToken, so just call ordinary CreateProcess */
write_stderr
(
"WARNING: Unable to create restricted tokens on this platform
\n
"
);
if
(
Advapi32Handle
!=
NULL
)
FreeLibrary
(
Advapi32Handle
);
return
CreateProcess
(
NULL
,
cmd
,
NULL
,
NULL
,
FALSE
,
0
,
NULL
,
NULL
,
&
si
,
processInfo
);
}
/* Open the current token to use as a base for the restricted one */
if
(
!
OpenProcessToken
(
GetCurrentProcess
(),
TOKEN_ALL_ACCESS
,
&
origToken
))
{
write_stderr
(
"Failed to open process token: %lu
\n
"
,
GetLastError
());
return
0
;
}
/* Allocate list of SIDs to remove */
ZeroMemory
(
&
dropSids
,
sizeof
(
dropSids
));
if
(
!
AllocateAndInitializeSid
(
&
NtAuthority
,
2
,
SECURITY_BUILTIN_DOMAIN_RID
,
DOMAIN_ALIAS_RID_ADMINS
,
0
,
0
,
0
,
0
,
0
,
0
,
&
dropSids
[
0
].
Sid
)
||
!
AllocateAndInitializeSid
(
&
NtAuthority
,
2
,
SECURITY_BUILTIN_DOMAIN_RID
,
DOMAIN_ALIAS_RID_POWER_USERS
,
0
,
0
,
0
,
0
,
0
,
0
,
&
dropSids
[
1
].
Sid
))
{
write_stderr
(
"Failed to allocate SIDs: %lu
\n
"
,
GetLastError
());
return
0
;
}
b
=
_CreateRestrictedToken
(
origToken
,
DISABLE_MAX_PRIVILEGE
,
sizeof
(
dropSids
)
/
sizeof
(
dropSids
[
0
]),
dropSids
,
0
,
NULL
,
0
,
NULL
,
&
restrictedToken
);
FreeSid
(
dropSids
[
1
].
Sid
);
FreeSid
(
dropSids
[
0
].
Sid
);
CloseHandle
(
origToken
);
FreeLibrary
(
Advapi32Handle
);
if
(
!
b
)
{
write_stderr
(
"Failed to create restricted token: %lu
\n
"
,
GetLastError
());
return
0
;
}
r
=
CreateProcessAsUser
(
restrictedToken
,
NULL
,
cmd
,
NULL
,
NULL
,
TRUE
,
CREATE_SUSPENDED
,
NULL
,
NULL
,
&
si
,
processInfo
);
Kernel32Handle
=
LoadLibrary
(
"KERNEL32.DLL"
);
if
(
Kernel32Handle
!=
NULL
)
{
_IsProcessInJob
=
(
__IsProcessInJob
)
GetProcAddress
(
Kernel32Handle
,
"IsProcessInJob"
);
_CreateJobObject
=
(
__CreateJobObject
)
GetProcAddress
(
Kernel32Handle
,
"CreateJobObjectA"
);
_SetInformationJobObject
=
(
__SetInformationJobObject
)
GetProcAddress
(
Kernel32Handle
,
"SetInformationJobObject"
);
_AssignProcessToJobObject
=
(
__AssignProcessToJobObject
)
GetProcAddress
(
Kernel32Handle
,
"AssignProcessToJobObject"
);
_QueryInformationJobObject
=
(
__QueryInformationJobObject
)
GetProcAddress
(
Kernel32Handle
,
"QueryInformationJobObject"
);
}
/* Verify that we found all functions */
if
(
_IsProcessInJob
==
NULL
||
_CreateJobObject
==
NULL
||
_SetInformationJobObject
==
NULL
||
_AssignProcessToJobObject
==
NULL
||
_QueryInformationJobObject
==
NULL
)
{
write_stderr
(
"WARNING: Unable to locate all job object functions in system API!
\n
"
);
}
else
{
BOOL
inJob
;
if
(
_IsProcessInJob
(
processInfo
->
hProcess
,
NULL
,
&
inJob
))
{
if
(
!
inJob
)
{
/* Job objects are working, and the new process isn't in one, so we can create one safely.
If any problems show up when setting it, we're going to ignore them. */
HANDLE
job
;
char
jobname
[
128
];
sprintf
(
jobname
,
"PostgreSQL_%lu"
,
processInfo
->
dwProcessId
);
job
=
_CreateJobObject
(
NULL
,
jobname
);
if
(
job
)
{
JOBOBJECT_BASIC_LIMIT_INFORMATION
basicLimit
;
JOBOBJECT_BASIC_UI_RESTRICTIONS
uiRestrictions
;
JOBOBJECT_SECURITY_LIMIT_INFORMATION
securityLimit
;
ZeroMemory
(
&
basicLimit
,
sizeof
(
basicLimit
));
ZeroMemory
(
&
uiRestrictions
,
sizeof
(
uiRestrictions
));
ZeroMemory
(
&
securityLimit
,
sizeof
(
securityLimit
));
basicLimit
.
LimitFlags
=
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
|
JOB_OBJECT_LIMIT_PRIORITY_CLASS
;
basicLimit
.
PriorityClass
=
NORMAL_PRIORITY_CLASS
;
_SetInformationJobObject
(
job
,
JobObjectBasicLimitInformation
,
&
basicLimit
,
sizeof
(
basicLimit
));
uiRestrictions
.
UIRestrictionsClass
=
JOB_OBJECT_UILIMIT_DESKTOP
|
JOB_OBJECT_UILIMIT_DISPLAYSETTINGS
|
JOB_OBJECT_UILIMIT_EXITWINDOWS
|
JOB_OBJECT_UILIMIT_HANDLES
|
JOB_OBJECT_UILIMIT_READCLIPBOARD
|
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS
|
JOB_OBJECT_UILIMIT_WRITECLIPBOARD
;
_SetInformationJobObject
(
job
,
JobObjectBasicUIRestrictions
,
&
uiRestrictions
,
sizeof
(
uiRestrictions
));
securityLimit
.
SecurityLimitFlags
=
JOB_OBJECT_SECURITY_NO_ADMIN
|
JOB_OBJECT_SECURITY_ONLY_TOKEN
;
securityLimit
.
JobToken
=
restrictedToken
;
_SetInformationJobObject
(
job
,
JobObjectSecurityLimitInformation
,
&
securityLimit
,
sizeof
(
securityLimit
));
_AssignProcessToJobObject
(
job
,
processInfo
->
hProcess
);
}
}
}
}
CloseHandle
(
restrictedToken
);
ResumeThread
(
processInfo
->
hThread
);
FreeLibrary
(
Kernel32Handle
);
/*
* We intentionally don't close the job object handle, because we want the
* object to live on until pg_ctl shuts down.
*/
return
r
;
}
#endif
static
void
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录