/* Benjamin DELPY `gentilkiwi` http://blog.gentilkiwi.com benjamin@gentilkiwi.com Licence : https://creativecommons.org/licenses/by/4.0/ */ #include "kull_m_token.h" BOOL kull_m_token_getNameDomainFromToken(HANDLE hToken, PWSTR * pName, PWSTR * pDomain, PWSTR * pSid, PSID_NAME_USE pSidNameUse) { BOOL result = FALSE; PTOKEN_USER pTokenUser; DWORD szNeeded; if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &szNeeded) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { if(pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, szNeeded)) { if(GetTokenInformation(hToken, TokenUser, pTokenUser, szNeeded, &szNeeded)) { if((result = kull_m_token_getNameDomainFromSID(pTokenUser->User.Sid, pName, pDomain, pSidNameUse, NULL)) && pSid) result = ConvertSidToStringSid(pTokenUser->User.Sid, pSid); } LocalFree(pTokenUser); } } return result; } BOOL kull_m_token_CheckTokenMembership(__in_opt HANDLE TokenHandle, __in PSID SidToCheck, __out PBOOL IsMember) { BOOL status = FALSE, isDupp = FALSE; TOKEN_TYPE type; DWORD szNeeded; HANDLE effHandle; if(GetTokenInformation(TokenHandle, TokenType, &type, sizeof(TOKEN_TYPE), &szNeeded)) { if(type == TokenPrimary) { isDupp = DuplicateTokenEx(TokenHandle, TOKEN_QUERY, NULL, SecurityIdentification, TokenImpersonation, &effHandle); if(!isDupp) PRINT_ERROR_AUTO(L"DuplicateTokenEx"); } else effHandle = TokenHandle; if(isDupp || (type != TokenPrimary)) { if(!(status = CheckTokenMembership(effHandle, SidToCheck, IsMember))) PRINT_ERROR_AUTO(L"CheckTokenMembership"); if(isDupp) CloseHandle(effHandle); } } else PRINT_ERROR_AUTO(L"GetTokenInformation"); return status; } PCWCHAR SidNameUses[] = {L"User", L"Group", L"Domain", L"Alias", L"WellKnownGroup", L"DeletedAccount", L"Invalid", L"Unknown", L"Computer", L"Label"}; PCWCHAR kull_m_token_getSidNameUse(SID_NAME_USE SidNameUse) { return (SidNameUse > 0 && SidNameUse <= SidTypeLabel) ? SidNameUses[SidNameUse - 1] : L"unk!"; } BOOL kull_m_token_getNameDomainFromSID(PSID pSid, PWSTR * pName, PWSTR * pDomain, PSID_NAME_USE pSidNameUse, LPCWSTR system) { BOOL result = FALSE; SID_NAME_USE sidNameUse; PSID_NAME_USE peUse = pSidNameUse ? pSidNameUse : &sidNameUse; DWORD cchName = 0, cchReferencedDomainName = 0; if(!LookupAccountSid(system, pSid, NULL, &cchName, NULL, &cchReferencedDomainName, peUse) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { if(*pName = (PWSTR) LocalAlloc(LPTR, cchName * sizeof(wchar_t))) { if(*pDomain = (PWSTR) LocalAlloc(LPTR, cchReferencedDomainName * sizeof(wchar_t))) { result = LookupAccountSid(system, pSid, *pName, &cchName, *pDomain, &cchReferencedDomainName, peUse); if(!result) *pDomain = (PWSTR) LocalFree(*pDomain); } if(!result) *pName = (PWSTR) LocalFree(*pName); } } return result; } BOOL kull_m_token_getSidDomainFromName(PCWSTR pName, PSID * pSid, PWSTR * pDomain, PSID_NAME_USE pSidNameUse, LPCWSTR system) { BOOL result = FALSE; SID_NAME_USE sidNameUse; PSID_NAME_USE peUse = pSidNameUse ? pSidNameUse : &sidNameUse; DWORD cbSid = 0, cchReferencedDomainName = 0; if(!LookupAccountName(system, pName, NULL, &cbSid, NULL, &cchReferencedDomainName, peUse) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { if(*pSid = (PSID) LocalAlloc(LPTR, cbSid * sizeof(wchar_t))) { if(*pDomain = (PWSTR) LocalAlloc(LPTR, cchReferencedDomainName * sizeof(wchar_t))) { result = LookupAccountName(system, pName, *pSid, &cbSid, *pDomain, &cchReferencedDomainName, peUse); if(!result) *pDomain = (PWSTR) LocalFree(*pDomain); } if(!result) *pSid = (PSID) LocalFree(*pSid); } } return result; } BOOL kull_m_token_getTokens(PKULL_M_TOKEN_ENUM_CALLBACK callBack, PVOID pvArg) { BOOL status = FALSE; KULL_M_TOKEN_ENUM_DATA data = {callBack, pvArg, TRUE}; if(status = NT_SUCCESS(kull_m_process_getProcessInformation(kull_m_token_getTokens_process_callback, &data))) if(data.mustContinue) status = NT_SUCCESS(kull_m_handle_getHandlesOfType(kull_m_token_getTokens_handles_callback, L"Token", TOKEN_QUERY | TOKEN_DUPLICATE, 0, &data)); return status; } BOOL kull_m_token_getTokensUnique(PKULL_M_TOKEN_ENUM_CALLBACK callBack, PVOID pvArg) { BOOL status = FALSE, mustContinue = TRUE; KULL_M_TOKEN_LIST list = {0}, *cur, *tmp; if(status = kull_m_token_getTokens(kull_m_token_getTokensUnique_callback, &list)) { for(cur = &list; cur && mustContinue; cur = cur->next) mustContinue = callBack(cur->hToken, cur->ptid, pvArg); for(cur = &list; cur; cur = tmp) { if(cur->hToken) CloseHandle(cur->hToken); tmp = cur->next; if(cur != &list) LocalFree(cur); } } return status; } BOOL CALLBACK kull_m_token_getTokensUnique_callback(HANDLE hToken, DWORD ptid, PVOID pvArg) { PKULL_M_TOKEN_LIST list = (PKULL_M_TOKEN_LIST) pvArg, cur, old = NULL; HANDLE my = GetCurrentProcess(); if(list->hToken) { for(cur = list; cur; old = cur, cur = cur->next) if(kull_m_token_equal(hToken, cur->hToken)) break; if(!cur && old) if(old->next = (PKULL_M_TOKEN_LIST) LocalAlloc(LPTR, sizeof(KULL_M_TOKEN_LIST))) { old->next->ptid = ptid; if(!DuplicateHandle(my, hToken, (HANDLE) my, &old->next->hToken, 0, FALSE, DUPLICATE_SAME_ACCESS)) PRINT_ERROR_AUTO(L"DuplicateHandle"); } } else { list->ptid = ptid; if(!DuplicateHandle(my, hToken, my, &list->hToken, 0, FALSE, DUPLICATE_SAME_ACCESS)) PRINT_ERROR_AUTO(L"DuplicateHandle"); } return TRUE; } BOOL CALLBACK kull_m_token_getTokens_process_callback(PSYSTEM_PROCESS_INFORMATION pSystemProcessInformation, PVOID pvArg) { BOOL status = TRUE; HANDLE hProcess, hToken; if(hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, PtrToUlong(pSystemProcessInformation->UniqueProcessId))) { if(OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_DUPLICATE, &hToken)) { status = ((PKULL_M_TOKEN_ENUM_DATA) pvArg)->callback(hToken, PtrToUlong(pSystemProcessInformation->UniqueProcessId), ((PKULL_M_TOKEN_ENUM_DATA) pvArg)->pvArg); CloseHandle(hToken); } CloseHandle(hProcess); } return (((PKULL_M_TOKEN_ENUM_DATA) pvArg)->mustContinue = status); } BOOL CALLBACK kull_m_token_getTokens_handles_callback(HANDLE handle, PSYSTEM_HANDLE pSystemHandle, PVOID pvArg) { return (((PKULL_M_TOKEN_ENUM_DATA) pvArg)->mustContinue = ((PKULL_M_TOKEN_ENUM_DATA) pvArg)->callback(handle, pSystemHandle->ProcessId, ((PKULL_M_TOKEN_ENUM_DATA) pvArg)->pvArg)); } BOOL kull_m_token_equal(IN HANDLE First, IN HANDLE Second) { BOOL status = FALSE; BOOLEAN lit; NTSTATUS ntStatus; DWORD s1, s2, szRet; ntStatus = NtCompareTokens(First, Second, &lit); if(NT_SUCCESS(ntStatus)) { if(status = lit) if(GetTokenInformation(First, TokenSessionId, &s1, sizeof(DWORD), &szRet) && GetTokenInformation(Second, TokenSessionId, &s2, sizeof(DWORD), &szRet)) status = (s1 == s2); } else PRINT_ERROR(L"NtCompareTokens: %08x\n", ntStatus); return status; }