mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-01 19:45:33 +08:00
Revert Windows service check refactoring, and replace with a different fix.
This reverts commit 38bdba54a6
, "Fix and
simplify check for whether we're running as Windows service". It turns out
that older versions of MinGW - like that on buildfarm member narwhal - do
not support the CheckTokenMembership() function. This replaces the
refactoring with a much smaller fix, to add a check for SE_GROUP_ENABLED to
pgwin32_is_service().
Only apply to back-branches, and keep the refactoring in HEAD. It's
unlikely that anyone is still really using such an old version of MinGW -
aside from narwhal - but let's not change the minimum requirements in
minor releases.
Discussion: https://www.postgresql.org/message-id/16609.1489773427@sss.pgh.pa.us
Patch: https://www.postgresql.org/message-id/CAB7nPqSvfu%3DKpJ%3DNX%2BYAHmgAmQdzA7N5h31BjzXeMgczhGCC%2BQ%40mail.gmail.com
This commit is contained in:
parent
5fdc70826f
commit
e0e1ef46d8
@ -14,6 +14,10 @@
|
||||
#include "postgres.h"
|
||||
|
||||
|
||||
static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
|
||||
TOKEN_INFORMATION_CLASS class, char **InfoBuffer,
|
||||
char *errbuf, int errsize);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the current user has administrative privileges,
|
||||
* or zero if not.
|
||||
@ -24,11 +28,33 @@
|
||||
int
|
||||
pgwin32_is_admin(void)
|
||||
{
|
||||
HANDLE AccessToken;
|
||||
char *InfoBuffer = NULL;
|
||||
char errbuf[256];
|
||||
PTOKEN_GROUPS Groups;
|
||||
PSID AdministratorsSid;
|
||||
PSID PowerUsersSid;
|
||||
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
||||
BOOL IsAdministrators;
|
||||
BOOL IsPowerUsers;
|
||||
UINT x;
|
||||
BOOL success;
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
|
||||
{
|
||||
write_stderr("could not open process token: error code %lu\n",
|
||||
GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
|
||||
&InfoBuffer, errbuf, sizeof(errbuf)))
|
||||
{
|
||||
write_stderr("%s", errbuf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Groups = (PTOKEN_GROUPS) InfoBuffer;
|
||||
|
||||
CloseHandle(AccessToken);
|
||||
|
||||
if (!AllocateAndInitializeSid(&NtAuthority, 2,
|
||||
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
|
||||
@ -48,35 +74,32 @@ pgwin32_is_admin(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) ||
|
||||
!CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
|
||||
success = FALSE;
|
||||
|
||||
for (x = 0; x < Groups->GroupCount; x++)
|
||||
{
|
||||
write_stderr("could not check access token membership: error code %lu\n",
|
||||
GetLastError());
|
||||
exit(1);
|
||||
if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
|
||||
(EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
|
||||
{
|
||||
success = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(InfoBuffer);
|
||||
FreeSid(AdministratorsSid);
|
||||
FreeSid(PowerUsersSid);
|
||||
|
||||
if (IsAdministrators || IsPowerUsers)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* We consider ourselves running as a service if one of the following is
|
||||
* true:
|
||||
*
|
||||
* 1) We are running as LocalSystem (only used by services)
|
||||
* 1) We are running as Local System (only used by services)
|
||||
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
|
||||
* 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:
|
||||
* 0 = Not service
|
||||
* 1 = Service
|
||||
@ -90,62 +113,137 @@ int
|
||||
pgwin32_is_service(void)
|
||||
{
|
||||
static int _is_service = -1;
|
||||
BOOL IsMember;
|
||||
HANDLE AccessToken;
|
||||
char *InfoBuffer = NULL;
|
||||
char errbuf[256];
|
||||
PTOKEN_GROUPS Groups;
|
||||
PTOKEN_USER User;
|
||||
PSID ServiceSid;
|
||||
PSID LocalSystemSid;
|
||||
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
|
||||
UINT x;
|
||||
|
||||
/* Only check the first time */
|
||||
if (_is_service != -1)
|
||||
return _is_service;
|
||||
|
||||
/* First check for LocalSystem */
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
|
||||
{
|
||||
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,
|
||||
SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
|
||||
&LocalSystemSid))
|
||||
{
|
||||
fprintf(stderr, "could not get SID for local system account\n");
|
||||
CloseHandle(AccessToken);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember))
|
||||
if (EqualSid(LocalSystemSid, User->User.Sid))
|
||||
{
|
||||
fprintf(stderr, "could not check access token membership: error code %lu\n",
|
||||
GetLastError());
|
||||
FreeSid(LocalSystemSid);
|
||||
return -1;
|
||||
}
|
||||
FreeSid(LocalSystemSid);
|
||||
|
||||
if (IsMember)
|
||||
{
|
||||
free(InfoBuffer);
|
||||
CloseHandle(AccessToken);
|
||||
_is_service = 1;
|
||||
return _is_service;
|
||||
}
|
||||
|
||||
/* Check for service group membership */
|
||||
FreeSid(LocalSystemSid);
|
||||
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,
|
||||
SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
|
||||
&ServiceSid))
|
||||
{
|
||||
fprintf(stderr, "could not get SID for service group: error code %lu\n",
|
||||
GetLastError());
|
||||
fprintf(stderr, "could not get SID for service group\n");
|
||||
free(InfoBuffer);
|
||||
CloseHandle(AccessToken);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!CheckTokenMembership(NULL, ServiceSid, &IsMember))
|
||||
_is_service = 0;
|
||||
for (x = 0; x < Groups->GroupCount; x++)
|
||||
{
|
||||
fprintf(stderr, "could not check access token membership: error code %lu\n",
|
||||
GetLastError());
|
||||
FreeSid(ServiceSid);
|
||||
return -1;
|
||||
if (EqualSid(ServiceSid, Groups->Groups[x].Sid) &&
|
||||
(Groups->Groups[x].Attributes & SE_GROUP_ENABLED))
|
||||
{
|
||||
_is_service = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(InfoBuffer);
|
||||
FreeSid(ServiceSid);
|
||||
|
||||
if (IsMember)
|
||||
_is_service = 1;
|
||||
else
|
||||
_is_service = 0;
|
||||
CloseHandle(AccessToken);
|
||||
|
||||
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: got zero size\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
snprintf(errbuf, errsize, "could not get token information: 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…
Reference in New Issue
Block a user