Skip to content

Commit e0e1ef4

Browse files
committed
Revert Windows service check refactoring, and replace with a different fix.
This reverts commit 38bdba5, "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
1 parent 5fdc708 commit e0e1ef4

File tree

1 file changed

+136
-38
lines changed

1 file changed

+136
-38
lines changed

src/backend/port/win32/security.c

Lines changed: 136 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
#include "postgres.h"
1515

1616

17+
static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
18+
TOKEN_INFORMATION_CLASS class, char **InfoBuffer,
19+
char *errbuf, int errsize);
20+
1721
/*
1822
* Returns nonzero if the current user has administrative privileges,
1923
* or zero if not.
@@ -24,11 +28,33 @@
2428
int
2529
pgwin32_is_admin(void)
2630
{
31+
HANDLE AccessToken;
32+
char *InfoBuffer = NULL;
33+
char errbuf[256];
34+
PTOKEN_GROUPS Groups;
2735
PSID AdministratorsSid;
2836
PSID PowerUsersSid;
2937
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
30-
BOOL IsAdministrators;
31-
BOOL IsPowerUsers;
38+
UINT x;
39+
BOOL success;
40+
41+
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
42+
{
43+
write_stderr("could not open process token: error code %lu\n",
44+
GetLastError());
45+
exit(1);
46+
}
47+
48+
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
49+
&InfoBuffer, errbuf, sizeof(errbuf)))
50+
{
51+
write_stderr("%s", errbuf);
52+
exit(1);
53+
}
54+
55+
Groups = (PTOKEN_GROUPS) InfoBuffer;
56+
57+
CloseHandle(AccessToken);
3258

3359
if (!AllocateAndInitializeSid(&NtAuthority, 2,
3460
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
@@ -48,35 +74,32 @@ pgwin32_is_admin(void)
4874
exit(1);
4975
}
5076

51-
if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) ||
52-
!CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
77+
success = FALSE;
78+
79+
for (x = 0; x < Groups->GroupCount; x++)
5380
{
54-
write_stderr("could not check access token membership: error code %lu\n",
55-
GetLastError());
56-
exit(1);
81+
if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
82+
(EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
83+
{
84+
success = TRUE;
85+
break;
86+
}
5787
}
5888

89+
free(InfoBuffer);
5990
FreeSid(AdministratorsSid);
6091
FreeSid(PowerUsersSid);
61-
62-
if (IsAdministrators || IsPowerUsers)
63-
return 1;
64-
else
65-
return 0;
92+
return success;
6693
}
6794

6895
/*
6996
* We consider ourselves running as a service if one of the following is
7097
* true:
7198
*
72-
* 1) We are running as LocalSystem (only used by services)
99+
* 1) We are running as Local System (only used by services)
73100
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
74101
* process token by the SCM when starting a service)
75102
*
76-
* The check for LocalSystem is needed, because surprisingly, if a service
77-
* is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
78-
* process token.
79-
*
80103
* Return values:
81104
* 0 = Not service
82105
* 1 = Service
@@ -90,62 +113,137 @@ int
90113
pgwin32_is_service(void)
91114
{
92115
static int _is_service = -1;
93-
BOOL IsMember;
116+
HANDLE AccessToken;
117+
char *InfoBuffer = NULL;
118+
char errbuf[256];
119+
PTOKEN_GROUPS Groups;
120+
PTOKEN_USER User;
94121
PSID ServiceSid;
95122
PSID LocalSystemSid;
96123
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
124+
UINT x;
97125

98126
/* Only check the first time */
99127
if (_is_service != -1)
100128
return _is_service;
101129

102-
/* First check for LocalSystem */
130+
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
131+
{
132+
fprintf(stderr, "could not open process token: error code %lu\n",
133+
GetLastError());
134+
return -1;
135+
}
136+
137+
/* First check for local system */
138+
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer,
139+
errbuf, sizeof(errbuf)))
140+
{
141+
fprintf(stderr, "%s", errbuf);
142+
return -1;
143+
}
144+
145+
User = (PTOKEN_USER) InfoBuffer;
146+
103147
if (!AllocateAndInitializeSid(&NtAuthority, 1,
104148
SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
105149
&LocalSystemSid))
106150
{
107151
fprintf(stderr, "could not get SID for local system account\n");
152+
CloseHandle(AccessToken);
108153
return -1;
109154
}
110155

111-
if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember))
156+
if (EqualSid(LocalSystemSid, User->User.Sid))
112157
{
113-
fprintf(stderr, "could not check access token membership: error code %lu\n",
114-
GetLastError());
115158
FreeSid(LocalSystemSid);
116-
return -1;
159+
free(InfoBuffer);
160+
CloseHandle(AccessToken);
161+
_is_service = 1;
162+
return _is_service;
117163
}
164+
118165
FreeSid(LocalSystemSid);
166+
free(InfoBuffer);
119167

120-
if (IsMember)
168+
/* Now check for group SID */
169+
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer,
170+
errbuf, sizeof(errbuf)))
121171
{
122-
_is_service = 1;
123-
return _is_service;
172+
fprintf(stderr, "%s", errbuf);
173+
return -1;
124174
}
125175

126-
/* Check for service group membership */
176+
Groups = (PTOKEN_GROUPS) InfoBuffer;
177+
127178
if (!AllocateAndInitializeSid(&NtAuthority, 1,
128179
SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
129180
&ServiceSid))
130181
{
131-
fprintf(stderr, "could not get SID for service group: error code %lu\n",
132-
GetLastError());
182+
fprintf(stderr, "could not get SID for service group\n");
183+
free(InfoBuffer);
184+
CloseHandle(AccessToken);
133185
return -1;
134186
}
135187

136-
if (!CheckTokenMembership(NULL, ServiceSid, &IsMember))
188+
_is_service = 0;
189+
for (x = 0; x < Groups->GroupCount; x++)
137190
{
138-
fprintf(stderr, "could not check access token membership: error code %lu\n",
139-
GetLastError());
140-
FreeSid(ServiceSid);
141-
return -1;
191+
if (EqualSid(ServiceSid, Groups->Groups[x].Sid) &&
192+
(Groups->Groups[x].Attributes & SE_GROUP_ENABLED))
193+
{
194+
_is_service = 1;
195+
break;
196+
}
142197
}
198+
199+
free(InfoBuffer);
143200
FreeSid(ServiceSid);
144201

145-
if (IsMember)
146-
_is_service = 1;
147-
else
148-
_is_service = 0;
202+
CloseHandle(AccessToken);
149203

150204
return _is_service;
151205
}
206+
207+
208+
/*
209+
* Call GetTokenInformation() on a token and return a dynamically sized
210+
* buffer with the information in it. This buffer must be free():d by
211+
* the calling function!
212+
*/
213+
static BOOL
214+
pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
215+
char **InfoBuffer, char *errbuf, int errsize)
216+
{
217+
DWORD InfoBufferSize;
218+
219+
if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize))
220+
{
221+
snprintf(errbuf, errsize, "could not get token information: got zero size\n");
222+
return FALSE;
223+
}
224+
225+
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
226+
{
227+
snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
228+
GetLastError());
229+
return FALSE;
230+
}
231+
232+
*InfoBuffer = malloc(InfoBufferSize);
233+
if (*InfoBuffer == NULL)
234+
{
235+
snprintf(errbuf, errsize, "could not allocate %d bytes for token information\n",
236+
(int) InfoBufferSize);
237+
return FALSE;
238+
}
239+
240+
if (!GetTokenInformation(token, class, *InfoBuffer,
241+
InfoBufferSize, &InfoBufferSize))
242+
{
243+
snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
244+
GetLastError());
245+
return FALSE;
246+
}
247+
248+
return TRUE;
249+
}

0 commit comments

Comments
 (0)