#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
* message.
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))
+ {
+ 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,
SECURITY_BUILTIN_DOMAIN_RID,
exit(1);
}
- if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) ||
- !CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
+ success = FALSE;
+
+ for (x = 0; x < Groups->GroupCount; x++)
{
- log_error(_("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
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;
+ free(InfoBuffer);
+ CloseHandle(AccessToken);
+ _is_service = 1;
+ return _is_service;
}
+
FreeSid(LocalSystemSid);
+ free(InfoBuffer);
- if (IsMember)
+ /* Now check for group SID */
+ if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer,
+ errbuf, sizeof(errbuf)))
{
- _is_service = 1;
- return _is_service;
+ fprintf(stderr, "%s", errbuf);
+ return -1;
}
- /* Check for service group membership */
+ 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 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;
+}