mirror of
https://github.com/postgres/postgres.git
synced 2025-05-08 07:21:33 +03:00
Fix and simplify check for whether we're running as Windows service.
If the process token contains SECURITY_SERVICE_RID, but it has been disabled by the SE_GROUP_USE_FOR_DENY_ONLY attribute, win32_is_service() would incorrectly report that we're running as a service. That situation arises, e.g. if postmaster is launched with a restricted security token, with the "Log in as Service" privilege explicitly removed. Replace the broken code with CheckProcessTokenMembership(), which does this correctly. Also replace similar code in win32_is_admin(), even though it got this right, for simplicity and consistency. Per bug #13755, reported by Breen Hagan. Back-patch to all supported versions. Patch by Takayuki Tsunakawa, reviewed by Michael Paquier. Discussion: https://www.postgresql.org/message-id/20151104062315.2745.67143%40wrigleys.postgresql.org
This commit is contained in:
parent
b4ff8609db
commit
ff30aec759
@ -18,11 +18,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
|
|
||||||
TOKEN_INFORMATION_CLASS class,
|
|
||||||
char **InfoBuffer, char *errbuf, int errsize);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Utility wrapper for frontend and backend when reporting an error
|
* Utility wrapper for frontend and backend when reporting an error
|
||||||
* message.
|
* message.
|
||||||
@ -53,33 +48,11 @@ log_error(const char *fmt,...)
|
|||||||
int
|
int
|
||||||
pgwin32_is_admin(void)
|
pgwin32_is_admin(void)
|
||||||
{
|
{
|
||||||
HANDLE AccessToken;
|
|
||||||
char *InfoBuffer = NULL;
|
|
||||||
char errbuf[256];
|
|
||||||
PTOKEN_GROUPS Groups;
|
|
||||||
PSID AdministratorsSid;
|
PSID AdministratorsSid;
|
||||||
PSID PowerUsersSid;
|
PSID PowerUsersSid;
|
||||||
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
||||||
UINT x;
|
BOOL IsAdministrators;
|
||||||
BOOL success;
|
BOOL IsPowerUsers;
|
||||||
|
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
|
|
||||||
{
|
|
||||||
log_error(_("could not open process token: error code %lu\n"),
|
|
||||||
GetLastError());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
|
|
||||||
&InfoBuffer, errbuf, sizeof(errbuf)))
|
|
||||||
{
|
|
||||||
log_error("%s", errbuf);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Groups = (PTOKEN_GROUPS) InfoBuffer;
|
|
||||||
|
|
||||||
CloseHandle(AccessToken);
|
|
||||||
|
|
||||||
if (!AllocateAndInitializeSid(&NtAuthority, 2,
|
if (!AllocateAndInitializeSid(&NtAuthority, 2,
|
||||||
SECURITY_BUILTIN_DOMAIN_RID,
|
SECURITY_BUILTIN_DOMAIN_RID,
|
||||||
@ -101,34 +74,35 @@ pgwin32_is_admin(void)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
success = FALSE;
|
if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) ||
|
||||||
|
!CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
|
||||||
for (x = 0; x < Groups->GroupCount; x++)
|
|
||||||
{
|
{
|
||||||
if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) &&
|
log_error(_("could not check access token membership: error code %lu\n"),
|
||||||
(Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
|
GetLastError());
|
||||||
(EqualSid(PowerUsersSid, Groups->Groups[x].Sid) &&
|
exit(1);
|
||||||
(Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
|
|
||||||
{
|
|
||||||
success = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(InfoBuffer);
|
|
||||||
FreeSid(AdministratorsSid);
|
FreeSid(AdministratorsSid);
|
||||||
FreeSid(PowerUsersSid);
|
FreeSid(PowerUsersSid);
|
||||||
return success;
|
|
||||||
|
if (IsAdministrators || IsPowerUsers)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We consider ourselves running as a service if one of the following is
|
* We consider ourselves running as a service if one of the following is
|
||||||
* true:
|
* true:
|
||||||
*
|
*
|
||||||
* 1) We are running as Local System (only used by services)
|
* 1) We are running as LocalSystem (only used by services)
|
||||||
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
|
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
|
||||||
* process token by the SCM when starting a service)
|
* process token by the SCM when starting a service)
|
||||||
*
|
*
|
||||||
|
* The check for LocalSystem is needed, because surprisingly, if a service
|
||||||
|
* is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
|
||||||
|
* process token.
|
||||||
|
*
|
||||||
* Return values:
|
* Return values:
|
||||||
* 0 = Not service
|
* 0 = Not service
|
||||||
* 1 = Service
|
* 1 = Service
|
||||||
@ -143,140 +117,62 @@ int
|
|||||||
pgwin32_is_service(void)
|
pgwin32_is_service(void)
|
||||||
{
|
{
|
||||||
static int _is_service = -1;
|
static int _is_service = -1;
|
||||||
HANDLE AccessToken;
|
BOOL IsMember;
|
||||||
char *InfoBuffer = NULL;
|
|
||||||
char errbuf[256];
|
|
||||||
PTOKEN_GROUPS Groups;
|
|
||||||
PTOKEN_USER User;
|
|
||||||
PSID ServiceSid;
|
PSID ServiceSid;
|
||||||
PSID LocalSystemSid;
|
PSID LocalSystemSid;
|
||||||
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
||||||
UINT x;
|
|
||||||
|
|
||||||
/* Only check the first time */
|
/* Only check the first time */
|
||||||
if (_is_service != -1)
|
if (_is_service != -1)
|
||||||
return _is_service;
|
return _is_service;
|
||||||
|
|
||||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
|
/* First check for LocalSystem */
|
||||||
{
|
|
||||||
fprintf(stderr, "could not open process token: error code %lu\n",
|
|
||||||
GetLastError());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First check for local system */
|
|
||||||
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer,
|
|
||||||
errbuf, sizeof(errbuf)))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s", errbuf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
User = (PTOKEN_USER) InfoBuffer;
|
|
||||||
|
|
||||||
if (!AllocateAndInitializeSid(&NtAuthority, 1,
|
if (!AllocateAndInitializeSid(&NtAuthority, 1,
|
||||||
SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
|
SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
|
||||||
&LocalSystemSid))
|
&LocalSystemSid))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "could not get SID for local system account\n");
|
fprintf(stderr, "could not get SID for local system account\n");
|
||||||
CloseHandle(AccessToken);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EqualSid(LocalSystemSid, User->User.Sid))
|
if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember))
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "could not check access token membership: error code %lu\n",
|
||||||
|
GetLastError());
|
||||||
FreeSid(LocalSystemSid);
|
FreeSid(LocalSystemSid);
|
||||||
free(InfoBuffer);
|
return -1;
|
||||||
CloseHandle(AccessToken);
|
}
|
||||||
|
FreeSid(LocalSystemSid);
|
||||||
|
|
||||||
|
if (IsMember)
|
||||||
|
{
|
||||||
_is_service = 1;
|
_is_service = 1;
|
||||||
return _is_service;
|
return _is_service;
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeSid(LocalSystemSid);
|
/* Check for service group membership */
|
||||||
free(InfoBuffer);
|
|
||||||
|
|
||||||
/* Now check for group SID */
|
|
||||||
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer,
|
|
||||||
errbuf, sizeof(errbuf)))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s", errbuf);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Groups = (PTOKEN_GROUPS) InfoBuffer;
|
|
||||||
|
|
||||||
if (!AllocateAndInitializeSid(&NtAuthority, 1,
|
if (!AllocateAndInitializeSid(&NtAuthority, 1,
|
||||||
SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
|
SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
|
||||||
&ServiceSid))
|
&ServiceSid))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "could not get SID for service group\n");
|
fprintf(stderr, "could not get SID for service group: error code %lu\n",
|
||||||
free(InfoBuffer);
|
GetLastError());
|
||||||
CloseHandle(AccessToken);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_is_service = 0;
|
if (!CheckTokenMembership(NULL, ServiceSid, &IsMember))
|
||||||
for (x = 0; x < Groups->GroupCount; x++)
|
|
||||||
{
|
{
|
||||||
if (EqualSid(ServiceSid, Groups->Groups[x].Sid))
|
fprintf(stderr, "could not check access token membership: error code %lu\n",
|
||||||
{
|
GetLastError());
|
||||||
_is_service = 1;
|
FreeSid(ServiceSid);
|
||||||
break;
|
return -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(InfoBuffer);
|
|
||||||
FreeSid(ServiceSid);
|
FreeSid(ServiceSid);
|
||||||
|
|
||||||
CloseHandle(AccessToken);
|
if (IsMember)
|
||||||
|
_is_service = 1;
|
||||||
|
else
|
||||||
|
_is_service = 0;
|
||||||
|
|
||||||
return _is_service;
|
return _is_service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call GetTokenInformation() on a token and return a dynamically sized
|
|
||||||
* buffer with the information in it. This buffer must be free():d by
|
|
||||||
* the calling function!
|
|
||||||
*/
|
|
||||||
static BOOL
|
|
||||||
pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
|
|
||||||
char **InfoBuffer, char *errbuf, int errsize)
|
|
||||||
{
|
|
||||||
DWORD InfoBufferSize;
|
|
||||||
|
|
||||||
if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize))
|
|
||||||
{
|
|
||||||
snprintf(errbuf, errsize,
|
|
||||||
"could not get token information buffer size: got zero size\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
||||||
{
|
|
||||||
snprintf(errbuf, errsize,
|
|
||||||
"could not get token information buffer size: error code %lu\n",
|
|
||||||
GetLastError());
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
*InfoBuffer = malloc(InfoBufferSize);
|
|
||||||
if (*InfoBuffer == NULL)
|
|
||||||
{
|
|
||||||
snprintf(errbuf, errsize,
|
|
||||||
"could not allocate %d bytes for token information\n",
|
|
||||||
(int) InfoBufferSize);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GetTokenInformation(token, class, *InfoBuffer,
|
|
||||||
InfoBufferSize, &InfoBufferSize))
|
|
||||||
{
|
|
||||||
snprintf(errbuf, errsize,
|
|
||||||
"could not get token information: error code %lu\n",
|
|
||||||
GetLastError());
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user