BOOL NotifyLogon( PWINDOWSTATION pwinsta, PLUID pluidCaller, DWORD dwFlags) { BOOL fNotified = FALSE; PWND pwndWinlogon; if (dwFlags & EWX_SHUTDOWN) { for (pwinsta = grpwinstaList; pwinsta != NULL; pwinsta = pwinsta->rpwinstaNext) { pwndWinlogon = pwinsta->spwndLogonNotify; if (pwndWinlogon != NULL) { _PostMessage(pwndWinlogon, WM_LOGONNOTIFY, LOGON_LOGOFF, (LONG)dwFlags); fNotified = TRUE; } } } else { LUID luidSystem = SYSTEM_LUID; pwndWinlogon = pwinsta->spwndLogonNotify; if (pwndWinlogon != NULL && (RtlEqualLuid(&pwinsta->luidUser, pluidCaller) || RtlEqualLuid(&luidSystem, pluidCaller))) { _PostMessage(pwndWinlogon, WM_LOGONNOTIFY, LOGON_LOGOFF, (LONG)dwFlags); fNotified = TRUE; } } return fNotified; }
PVOID kuhl_m_sekurlsa_utils_pFromAVLByLuidRec(PKULL_M_MEMORY_ADDRESS pTable, ULONG LUIDoffset, PLUID luidToFind) { PVOID resultat = NULL; RTL_AVL_TABLE maTable; KULL_M_MEMORY_HANDLE hBuffer = {KULL_M_MEMORY_TYPE_OWN, NULL}; KULL_M_MEMORY_ADDRESS data = {&maTable, &hBuffer}; if(kull_m_memory_copy(&data, pTable, sizeof(RTL_AVL_TABLE))) { if(pTable->address = maTable.OrderedPointer) { if(data.address = LocalAlloc(LPTR, LUIDoffset + sizeof(LUID))) { if(kull_m_memory_copy(&data, pTable, LUIDoffset + sizeof(LUID))) { if(RtlEqualLuid(luidToFind, (PLUID) ((PBYTE) (data.address) + LUIDoffset))) resultat = maTable.OrderedPointer; } LocalFree(data.address); } } if(!resultat && (pTable->address = maTable.BalancedRoot.LeftChild)) resultat = kuhl_m_sekurlsa_utils_pFromAVLByLuidRec(pTable, LUIDoffset, luidToFind); if(!resultat && (pTable->address = maTable.BalancedRoot.RightChild)) resultat = kuhl_m_sekurlsa_utils_pFromAVLByLuidRec(pTable, LUIDoffset, luidToFind); } return resultat; }
ULONG_PTR kuhl_m_sekurlsa_utils_pFromLinkedListByLuid(ULONG_PTR pSecurityStruct, ULONG LUIDoffset, PLUID luidToFind) { PVOID buffer; ULONG_PTR resultat = 0, pStruct = 0; if(buffer = LocalAlloc(LPTR, LUIDoffset + sizeof(LUID))) { if(ReadMemory(pSecurityStruct, &pStruct, sizeof(PVOID), NULL)) { while(pStruct != pSecurityStruct) { if(ReadMemory(pStruct, buffer, LUIDoffset + sizeof(LUID), NULL)) { if(RtlEqualLuid(luidToFind, (PLUID) ((PBYTE) buffer + LUIDoffset))) { resultat = pStruct; break; } pStruct = (ULONG_PTR) ((PLIST_ENTRY) buffer)->Flink; } else break; } } LocalFree(buffer); } return resultat; }
ULONG_PTR kuhl_m_sekurlsa_utils_pFromAVLByLuidRec(ULONG_PTR pTable, ULONG LUIDoffset, PLUID luidToFind) { ULONG_PTR resultat = 0; PVOID buffer; RTL_AVL_TABLE maTable; if(ReadMemory(pTable, &maTable, sizeof(RTL_AVL_TABLE), NULL)) { if(pTable = (ULONG_PTR) maTable.OrderedPointer) { if(buffer = LocalAlloc(LPTR, LUIDoffset + sizeof(LUID))) { if(ReadMemory(pTable, buffer, LUIDoffset + sizeof(LUID), NULL)) { if(RtlEqualLuid(luidToFind, (PLUID) ((PBYTE) buffer + LUIDoffset))) resultat = (ULONG_PTR) maTable.OrderedPointer; } LocalFree(buffer); } } if(!resultat && (pTable = (ULONG_PTR) maTable.BalancedRoot.LeftChild)) resultat = kuhl_m_sekurlsa_utils_pFromAVLByLuidRec(pTable, LUIDoffset, luidToFind); if(!resultat && (pTable = (ULONG_PTR) maTable.BalancedRoot.RightChild)) resultat = kuhl_m_sekurlsa_utils_pFromAVLByLuidRec(pTable, LUIDoffset, luidToFind); } return resultat; }
bool WINAPI mod_mimikatz_sekurlsa_ssp::getSSPLogonData(__in PLUID logId, __in bool justSecurity) { if(searchSSPEntryList()) { KIWI_SSP_CREDENTIAL_LIST_ENTRY mesCredentials; DWORD monNb = 0; if(mod_memory::readMemory(SspCredentialList, &mesCredentials, sizeof(LIST_ENTRY), mod_mimikatz_sekurlsa::hLSASS)) { while(mesCredentials.Flink != SspCredentialList) { if(mod_memory::readMemory(mesCredentials.Flink, &mesCredentials, sizeof(KIWI_SSP_CREDENTIAL_LIST_ENTRY), mod_mimikatz_sekurlsa::hLSASS)) { if(RtlEqualLuid(logId, &(mesCredentials.LogonId))) { mod_mimikatz_sekurlsa::genericCredsToStream(&mesCredentials.credentials, justSecurity, true, &monNb); monNb++; } } } } } else (*outputStream) << L"n.a. (SSP KO)"; return true; }
void CALLBACK kuhl_m_sekurlsa_enum_logon_callback_ssp(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN OPTIONAL PKUHL_M_SEKURLSA_EXTERNAL externalCallback, IN OPTIONAL LPVOID externalCallbackData) { KIWI_SSP_CREDENTIAL_LIST_ENTRY mesCredentials; KULL_M_MEMORY_HANDLE hBuffer = {KULL_M_MEMORY_TYPE_OWN, NULL}; KULL_M_MEMORY_ADDRESS aBuffer = {&mesCredentials, &hBuffer}, aLsass = {NULL, pData->cLsass->hLsassMem}; ULONG monNb = 0; if(kuhl_m_sekurlsa_ssp_package.Module.isInit || kuhl_m_sekurlsa_utils_search_generic(pData->cLsass, &kuhl_m_sekurlsa_ssp_package.Module, SspReferences, sizeof(SspReferences) / sizeof(KULL_M_PATCH_GENERIC), (PVOID *) &SspCredentialList, NULL, NULL)) { aLsass.address = SspCredentialList; if(kull_m_memory_copy(&aBuffer, &aLsass, sizeof(LIST_ENTRY))) { aLsass.address = mesCredentials.Flink; while(aLsass.address != SspCredentialList) { if(kull_m_memory_copy(&aBuffer, &aLsass, sizeof(KIWI_SSP_CREDENTIAL_LIST_ENTRY))) { if(RtlEqualLuid(pData->LogonId, &mesCredentials.LogonId) && (mesCredentials.credentials.UserName.Buffer || mesCredentials.credentials.Domaine.Buffer || mesCredentials.credentials.Password.Buffer)) { kprintf(L"\n\t [%08x]", monNb++); kuhl_m_sekurlsa_genericCredsOutput(&mesCredentials.credentials, pData->LogonId, KUHL_SEKURLSA_CREDS_DISPLAY_SSP | KUHL_SEKURLSA_CREDS_DISPLAY_DOMAIN, externalCallback, externalCallbackData); } aLsass.address = mesCredentials.Flink; } else break; } } } else kprintf(L"KO"); }
PVOID kuhl_m_sekurlsa_utils_pFromLinkedListByLuid(PKULL_M_MEMORY_ADDRESS pSecurityStruct, ULONG LUIDoffset, PLUID luidToFind) { PVOID resultat = NULL, pStruct; KULL_M_MEMORY_HANDLE hBuffer = {KULL_M_MEMORY_TYPE_OWN, NULL}; KULL_M_MEMORY_ADDRESS data = {&pStruct, &hBuffer}, aBuffer = {NULL, &hBuffer}; if(aBuffer.address = LocalAlloc(LPTR, LUIDoffset + sizeof(LUID))) { if(kull_m_memory_copy(&data, pSecurityStruct, sizeof(PVOID))) { data.address = pStruct; data.hMemory = pSecurityStruct->hMemory; while(data.address != pSecurityStruct->address) { if(kull_m_memory_copy(&aBuffer, &data, LUIDoffset + sizeof(LUID))) { if(RtlEqualLuid(luidToFind, (PLUID) ((PBYTE)(aBuffer.address) + LUIDoffset))) { resultat = data.address; break; } data.address = ((PLIST_ENTRY) (aBuffer.address))->Flink; } else break; } } LocalFree(aBuffer.address); } return resultat; }
BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_dpapi(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN OPTIONAL LPVOID pOptionalData) { KIWI_MASTERKEY_CACHE_ENTRY mesCredentials; KULL_M_MEMORY_HANDLE hLocalMemory = {KULL_M_MEMORY_TYPE_OWN, NULL}; KULL_M_MEMORY_ADDRESS aBuffer = {&mesCredentials, &hLocalMemory}, aKey = {NULL, &hLocalMemory}, aLsass = {NULL, pData->cLsass->hLsassMem}; PKUHL_M_SEKURLSA_PACKAGE pPackage = (pData->cLsass->osContext.BuildNumber >= KULL_M_WIN_MIN_BUILD_8) ? &kuhl_m_sekurlsa_dpapi_svc_package : &kuhl_m_sekurlsa_dpapi_lsa_package; BYTE dgst[SHA_DIGEST_LENGTH]; DWORD monNb = 0; if(pData->LogonType != Network) { kuhl_m_sekurlsa_printinfos_logonData(pData); if(pPackage->Module.isInit || kuhl_m_sekurlsa_utils_search_generic(pData->cLsass, &pPackage->Module, MasterKeyCacheReferences, ARRAYSIZE(MasterKeyCacheReferences), (PVOID *) &pMasterKeyCacheList, NULL, NULL, NULL)) { aLsass.address = pMasterKeyCacheList; if(kull_m_memory_copy(&aBuffer, &aLsass, sizeof(LIST_ENTRY))) { aLsass.address = mesCredentials.Flink; while(aLsass.address != pMasterKeyCacheList) { if(kull_m_memory_copy(&aBuffer, &aLsass, sizeof(KIWI_MASTERKEY_CACHE_ENTRY))) { if(RtlEqualLuid(pData->LogonId, &mesCredentials.LogonId)) { kprintf(L"\t [%08x]\n\t * GUID :\t", monNb++); kull_m_string_displayGUID(&mesCredentials.KeyUid); kprintf(L"\n\t * Time :\t"); kull_m_string_displayLocalFileTime(&mesCredentials.insertTime); if(aKey.address = LocalAlloc(LPTR, mesCredentials.keySize)) { aLsass.address = (PBYTE) aLsass.address + FIELD_OFFSET(KIWI_MASTERKEY_CACHE_ENTRY, key); if(kull_m_memory_copy(&aKey, &aLsass, mesCredentials.keySize)) { (*pData->lsassLocalHelper->pLsaUnprotectMemory)(aKey.address, mesCredentials.keySize); kprintf(L"\n\t * MasterKey :\t"); kull_m_string_wprintf_hex(aKey.address, mesCredentials.keySize, 0); if(kull_m_crypto_hash(CALG_SHA1, aKey.address, mesCredentials.keySize, dgst, SHA_DIGEST_LENGTH)) { kprintf(L"\n\t * sha1(key) :\t"); kull_m_string_wprintf_hex(dgst, SHA_DIGEST_LENGTH, 0); kuhl_m_dpapi_oe_masterkey_add(&mesCredentials.KeyUid, dgst, SHA_DIGEST_LENGTH); } } LocalFree(aKey.address); } kprintf(L"\n"); } aLsass.address = mesCredentials.Flink; } else break; } } } else kprintf(L"\n\tKO"); kprintf(L"\n"); } return TRUE; }
BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_msv_pth(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN OPTIONAL LPVOID pOptionalData) { PSEKURLSA_PTH_DATA pthData = (PSEKURLSA_PTH_DATA) pOptionalData; MSV1_0_PTH_DATA_CRED credData = {pData, pthData}; if(RtlEqualLuid(pData->LogonId, pthData->LogonId)) { kuhl_m_sekurlsa_msv_enum_cred(pData->cLsass, pData->pCredentials, kuhl_m_sekurlsa_msv_enum_cred_callback_pth, &credData); return FALSE; } else return TRUE; }
BOOL CALLBACK kuhl_m_sekurlsa_enum_callback_kerberos_pth(IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData, IN OPTIONAL LPVOID pOptionalData) { PSEKURLSA_PTH_DATA pthData = (PSEKURLSA_PTH_DATA) pOptionalData; KIWI_KERBEROS_ENUM_DATA data = {kuhl_m_sekurlsa_enum_kerberos_callback_pth, pthData}; if(RtlEqualLuid(pData->LogonId, pthData->LogonId)) { kuhl_m_sekurlsa_enum_generic_callback_kerberos(pData, &data); return FALSE; } else return TRUE; }
PLIST_ENTRY getPtrFromLinkedListByLuid(PLIST_ENTRY pSecurityStruct, unsigned long LUIDoffset, PLUID luidToFind) { PLIST_ENTRY resultat = NULL; for(PLIST_ENTRY pStruct = pSecurityStruct->Flink ; pStruct != pSecurityStruct ; pStruct = pStruct->Flink) { if(RtlEqualLuid(luidToFind, reinterpret_cast<PLUID>(reinterpret_cast<PBYTE>(pStruct) + LUIDoffset))) { resultat = pStruct; break; } } return resultat; }
static PLSAP_LOGON_SESSION LsapGetLogonSession(IN PLUID LogonId) { PLIST_ENTRY SessionEntry; PLSAP_LOGON_SESSION CurrentSession; SessionEntry = SessionListHead.Flink; while (SessionEntry != &SessionListHead) { CurrentSession = CONTAINING_RECORD(SessionEntry, LSAP_LOGON_SESSION, Entry); if (RtlEqualLuid(&CurrentSession->LogonId, LogonId)) return CurrentSession; SessionEntry = SessionEntry->Flink; } return NULL; }
PLIST_ENTRY mod_mimikatz_sekurlsa::getPtrFromLinkedListByLuid(PLIST_ENTRY pSecurityStruct, unsigned long LUIDoffset, PLUID luidToFind) { PLIST_ENTRY resultat = NULL; BYTE * monBuffer = new BYTE[LUIDoffset + sizeof(LUID)]; PLIST_ENTRY pStruct = NULL; if(mod_memory::readMemory(pSecurityStruct, &pStruct, sizeof(pStruct), hLSASS)) { while(pStruct != pSecurityStruct) { if(mod_memory::readMemory(pStruct, monBuffer, LUIDoffset + sizeof(LUID), hLSASS)) { if(RtlEqualLuid(luidToFind, reinterpret_cast<PLUID>(reinterpret_cast<PBYTE>(monBuffer) + LUIDoffset))) { resultat = pStruct; break; } } else break; pStruct = reinterpret_cast<PLIST_ENTRY>(monBuffer)->Flink; } } delete [] monBuffer; return resultat; }
void CALLBACK kuhl_m_sekurlsa_enum_logon_callback_masterkeys(IN ULONG_PTR pMasterKeyCacheList, IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData) { KIWI_MASTERKEY_CACHE_ENTRY mesCredentials; ULONG_PTR ptr; ULONG monNb = 0; PBYTE buffer; if(ReadMemory(pMasterKeyCacheList, &mesCredentials, sizeof(LIST_ENTRY), NULL)) { ptr = (ULONG_PTR) mesCredentials.Flink; while(ptr != pMasterKeyCacheList) { if(ReadMemory(ptr, &mesCredentials, sizeof(KIWI_MASTERKEY_CACHE_ENTRY), NULL)) { if(RtlEqualLuid(pData->LogonId, &mesCredentials.LogonId)) { dprintf("\n\t [%08x]\n\t * GUID :\t", monNb++); kull_m_string_displayGUID(&mesCredentials.KeyUid); dprintf("\n\t * Time :\t"); kull_m_string_displayFileTime(&mesCredentials.insertTime); if(buffer = (PBYTE) LocalAlloc(LPTR, mesCredentials.keySize)) { if(ReadMemory(ptr + FIELD_OFFSET(KIWI_MASTERKEY_CACHE_ENTRY, key), buffer, mesCredentials.keySize, NULL)) { kuhl_m_sekurlsa_nt6_LsaUnprotectMemory(buffer, mesCredentials.keySize); dprintf("\n\t * MasterKey :\t"); kull_m_string_dprintf_hex(buffer, mesCredentials.keySize, 0); } LocalFree(buffer); } } ptr = (ULONG_PTR) mesCredentials.Flink; } else break; } } else dprintf("KO"); }
PVOID mod_mimikatz_sekurlsa::getPtrFromAVLByLuidRec(PRTL_AVL_TABLE pTable, unsigned long LUIDoffset, PLUID luidToFind) { PVOID resultat = NULL; RTL_AVL_TABLE maTable; if(mod_memory::readMemory(pTable, &maTable, sizeof(RTL_AVL_TABLE), hLSASS)) { if(maTable.OrderedPointer) { BYTE * monBuffer = new BYTE[LUIDoffset + sizeof(LUID)]; if(mod_memory::readMemory(maTable.OrderedPointer, monBuffer, LUIDoffset + sizeof(LUID), hLSASS)) { if(RtlEqualLuid(luidToFind, reinterpret_cast<PLUID>(reinterpret_cast<PBYTE>(monBuffer) + LUIDoffset))) resultat = maTable.OrderedPointer; } delete [] monBuffer; } if(!resultat && maTable.BalancedRoot.LeftChild) resultat = getPtrFromAVLByLuidRec(reinterpret_cast<PRTL_AVL_TABLE>(maTable.BalancedRoot.LeftChild), LUIDoffset, luidToFind); if(!resultat && maTable.BalancedRoot.RightChild) resultat = getPtrFromAVLByLuidRec(reinterpret_cast<PRTL_AVL_TABLE>(maTable.BalancedRoot.RightChild), LUIDoffset, luidToFind); } return resultat; }
void CALLBACK kuhl_m_sekurlsa_enum_logon_callback_ssp(IN ULONG_PTR pSspCredentialList, IN PKIWI_BASIC_SECURITY_LOGON_SESSION_DATA pData) { KIWI_SSP_CREDENTIAL_LIST_ENTRY mesCredentials; ULONG_PTR ptr; ULONG monNb = 0; if(ReadMemory(pSspCredentialList, &mesCredentials, sizeof(LIST_ENTRY), NULL)) { ptr = (ULONG_PTR) mesCredentials.Flink; while(ptr != pSspCredentialList) { if(ReadMemory(ptr, &mesCredentials, sizeof(KIWI_SSP_CREDENTIAL_LIST_ENTRY), NULL)) { if(RtlEqualLuid(pData->LogonId, &mesCredentials.LogonId) && (mesCredentials.credentials.UserName.Buffer || mesCredentials.credentials.Domaine.Buffer || mesCredentials.credentials.Password.Buffer)) { dprintf("\n\t [%08x]", monNb++); kuhl_m_sekurlsa_genericCredsOutput(&mesCredentials.credentials, pData->LogonId, KUHL_SEKURLSA_CREDS_DISPLAY_SSP | KUHL_SEKURLSA_CREDS_DISPLAY_DOMAIN); } ptr = (ULONG_PTR) mesCredentials.Flink; } else break; } } else dprintf("KO"); }
BOOLEAN RtlPrivilegeCheck( IN OUT PPRIVILEGE_SET RequiredPrivileges, IN PACCESS_TOKEN AccessToken ) { PLUID_AND_ATTRIBUTES pPrivileges = AccessToken->Privileges; BOOLEAN isLocked = FALSE; ULONG privilegesNeeded = 0; ULONG iAssigned = 0; ULONG iRequired = 0; privilegesNeeded = RequiredPrivileges->PrivilegeCount; SHARED_LOCK_RWLOCK(&AccessToken->RwLock, isLocked); for (iRequired = 0; iRequired < RequiredPrivileges->PrivilegeCount; iRequired++) { for (iAssigned = 0; iAssigned < AccessToken->PrivilegeCount; iAssigned++) { if (RtlEqualLuid(&RequiredPrivileges->Privilege[iRequired].Luid, &pPrivileges[iAssigned].Luid)) { if (pPrivileges[iAssigned].Attributes & SE_PRIVILEGE_ENABLED) { if (privilegesNeeded > 0) { privilegesNeeded--; } if (!(RequiredPrivileges->Control & PRIVILEGE_SET_ALL_NECESSARY)) { // Turn off counting the privileges needed to grant // access. It's no longer necessary as at least one // of them has to be enabled and it's just been // found. privilegesNeeded = 0; } RequiredPrivileges->Privilege[iRequired].Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS; } else if (RequiredPrivileges->Control & PRIVILEGE_SET_ALL_NECESSARY) { // Further privilege check is pointless since all of // the privileges are required and one of them turns // out disabled. GOTO_CLEANUP(); } } } } cleanup: UNLOCK_RWLOCK(&AccessToken->RwLock, isLocked); return (privilegesNeeded == 0); }
NTSTATUS EndShutdown( PETHREAD Thread, NTSTATUS StatusShutdown) { PWINDOWSTATION pwinsta = gpwinstaLogoff; PDESKTOP pdesk; LUID luidCaller; UserAssert(gpwinstaLogoff); gpwinstaLogoff = NULL; dwThreadEndSession = 0; pwinsta->dwFlags &= ~WSF_SHUTDOWN; if (!NT_SUCCESS(GetProcessLuid(Thread, &luidCaller))) { luidCaller = RtlConvertUlongToLuid(0); // null luid } if (!NT_SUCCESS(StatusShutdown)) { /* * We need to notify the process that called ExitWindows that * the logoff was aborted. */ if (gptiShutdownNotify) { _PostThreadMessage(gptiShutdownNotify, WM_ENDSESSION, FALSE, 0); gptiShutdownNotify = NULL; } /* * Reset the windowstation lock flags so apps can start * again. */ pwinsta->dwFlags = (pwinsta->dwFlags & ~WSF_OPENLOCK) | gdwLocks; return STATUS_SUCCESS; } gptiShutdownNotify = NULL; /* * If logoff is occuring for the user set by winlogon, perform * the normal logoff cleanup. Otherwise, clear the open lock * and continue. */ if (((pwinsta->luidUser.LowPart != 0) || (pwinsta->luidUser.HighPart != 0)) && RtlEqualLuid(&pwinsta->luidUser, &luidCaller)) { /* * Save the current user's NumLock state */ if (FastOpenProfileUserMapping()) { RegisterPerUserKeyboardIndicators(); FastCloseProfileUserMapping(); } /* * Zero out the free blocks in all desktop heaps. */ for (pdesk = pwinsta->rpdeskList; pdesk != NULL; pdesk = pdesk->rpdeskNext) { RtlZeroHeap(pdesk->hheapDesktop, 0); } /* * Logoff/shutdown was successful. In case this is a logoff, remove * everything from the clipboard so the next logged on user can't get * at this stuff. */ ForceEmptyClipboard(pwinsta); /* * Destroy all non-pinned atoms in the global atom table. User can't * create pinned atoms. Currently only the OLE atoms are pinned. */ RtlEmptyAtomTable(pwinsta->pGlobalAtomTable, FALSE); // this code path is hit only on logoff and also on shutdown // We do not want to unload fonts twice when we attempt shutdown // so we mark that the fonts have been unloaded at a logoff time if (bFontsAreLoaded) { LeaveCrit(); GreRemoveAllButPermanentFonts(); EnterCrit(); bFontsAreLoaded = FALSE; } } else { pwinsta->dwFlags &= ~WSF_OPENLOCK; } /* * Tell winlogon that we successfully shutdown/logged off. */ NotifyLogon(pwinsta, &luidCaller, gdwShutdownFlags); return STATUS_SUCCESS; }
NTSTATUS InitiateShutdown( PETHREAD Thread, PULONG lpdwFlags) { static PRIVILEGE_SET psShutdown = { 1, PRIVILEGE_SET_ALL_NECESSARY, { SE_SHUTDOWN_PRIVILEGE, 0 } }; PEPROCESS Process; LUID luidCaller; LUID luidSystem = SYSTEM_LUID; PPROCESSINFO ppi; PWINDOWSTATION pwinsta; HWINSTA hwinsta; PTHREADINFO ptiClient; NTSTATUS Status; DWORD dwFlags; /* * Find out the callers sid. Only want to shutdown processes in the * callers sid. */ Process = THREAD_TO_PROCESS(Thread); ptiClient = PtiFromThread(Thread); Status = GetProcessLuid(Thread, &luidCaller); if (!NT_SUCCESS(Status)) { return Status; } /* * Set the system flag if the caller is a system process. * Winlogon uses this to determine in which context to perform * a shutdown operation. */ dwFlags = *lpdwFlags; if (RtlEqualLuid(&luidCaller, &luidSystem)) { dwFlags |= EWX_SYSTEM_CALLER; } else { dwFlags &= ~EWX_SYSTEM_CALLER; } /* * Find a windowstation. If the process does not have one * assigned, use the standard one. */ ppi = PpiFromProcess(Process); if (ppi == NULL) { /* * We ran into a case where the thread was terminated and had already * been cleaned up by USER. Thus, the ppi and ptiClient was NULL. */ return STATUS_INVALID_HANDLE; } pwinsta = ppi->rpwinsta; hwinsta = ppi->hwinsta; /* * If we're not being called by Winlogon, validate the call and * notify the logon process to do the actual shutdown. */ if (Thread->Cid.UniqueProcess != gpidLogon) { dwFlags &= ~EWX_WINLOGON_CALLER; *lpdwFlags = dwFlags; if (pwinsta == NULL) { #ifndef LATER return STATUS_INVALID_HANDLE; #else hwinsta = ppi->pOpenObjectTable[HI_WINDOWSTATION].h; if (hwinsta == NULL) { return STATUS_INVALID_HANDLE; } pwinsta = (PWINDOWSTATION)ppi->pOpenObjectTable[HI_WINDOWSTATION].phead; #endif } /* * Check security first - does this thread have access? */ if (!RtlAreAllAccessesGranted(ppi->amwinsta, WINSTA_EXITWINDOWS)) { return STATUS_ACCESS_DENIED; } /* * If the client requested shutdown, reboot, or poweroff they must have * the shutdown privilege. */ if (dwFlags & EWX_SHUTDOWN) { if (!IsPrivileged(&psShutdown) ) { return STATUS_PRIVILEGE_NOT_HELD; } } else { /* * If this is a non-IO windowstation and we are not shutting down, * fail the call. */ if (pwinsta->dwFlags & WSF_NOIO) { return STATUS_INVALID_DEVICE_REQUEST; } } } /* * Is there a shutdown already in progress? */ if (dwThreadEndSession != 0) { DWORD dwNew; /* * Calculate new flags */ dwNew = dwFlags & OPTIONMASK & (~gdwShutdownFlags); /* * Should we override the other shutdown? Make sure * winlogon does not recurse. */ if (dwNew && (DWORD)PsGetCurrentThread()->Cid.UniqueThread != dwThreadEndSession) { /* * Only one windowstation can be logged off at a time. */ if (!(dwFlags & EWX_SHUTDOWN) && pwinsta != gpwinstaLogoff) { return STATUS_DEVICE_BUSY; } /* * Set the new flags */ gdwShutdownFlags = dwFlags; if (dwNew & EWX_FORCE) { return STATUS_RETRY; } else { return STATUS_PENDING; } } else { /* * Don't override */ return STATUS_PENDING; } } /* * If the caller is not winlogon, signal winlogon to start * the real shutdown. */ if (Thread->Cid.UniqueProcess != gpidLogon) { if (dwFlags & EWX_NOTIFY) { if (ptiClient && ptiClient->TIF_flags & TIF_16BIT) gptiShutdownNotify = ptiClient; dwFlags &= ~EWX_NOTIFY; *lpdwFlags = dwFlags; } if (NotifyLogon(pwinsta, &luidCaller, dwFlags)) return STATUS_PENDING; else if (ptiClient && ptiClient->cWindows) return STATUS_CANT_WAIT; } /* * Mark this thread as the one that is currently processing * exit windows, and set the global saying someone is exiting */ dwFlags |= EWX_WINLOGON_CALLER; *lpdwFlags = dwFlags; gdwShutdownFlags = dwFlags; dwThreadEndSession = (DWORD)PsGetCurrentThread()->Cid.UniqueThread; gpwinstaLogoff = pwinsta; pwinsta->luidEndSession = luidCaller; /* * Lock the windowstation to prevent apps from starting * while we're doing shutdown processing. */ gdwLocks = pwinsta->dwFlags & (WSF_SWITCHLOCK | WSF_OPENLOCK); pwinsta->dwFlags |= (WSF_OPENLOCK | WSF_SHUTDOWN); return STATUS_SUCCESS; }
NTSTATUS RtlAdjustTokenPrivileges( IN PACCESS_TOKEN AccessToken, IN BOOLEAN DisableAll, IN OPTIONAL PTOKEN_PRIVILEGES NewState, IN ULONG BufferLength, OUT OPTIONAL PTOKEN_PRIVILEGES PreviousState, OUT OPTIONAL PULONG pReturnedLength ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN isLocked = FALSE; PLUID_AND_ATTRIBUTES pPrivileges = AccessToken->Privileges; ULONG assignedIndex = 0; ULONG modIndex = 0; ULONG returnedIndex = 0; ULONG BufferUsed = 0; ULONG adjustedCount = 0; if (!DisableAll && !NewState) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } if (!NewState && BufferLength > 0) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } EXCLUSIVE_LOCK_RWLOCK(&AccessToken->RwLock, isLocked); if (AccessToken->PrivilegeCount == 0) { status = STATUS_NOT_ALL_ASSIGNED; GOTO_CLEANUP(); } if (DisableAll) { for (assignedIndex = 0; assignedIndex < AccessToken->PrivilegeCount; assignedIndex++) { status = RtlpAppendTokenPrivileges( PreviousState, BufferLength, &pPrivileges[assignedIndex], returnedIndex++, &BufferUsed); if (status == STATUS_SUCCESS) { ClearFlag(pPrivileges[assignedIndex].Attributes, SE_PRIVILEGE_ENABLED); } } GOTO_CLEANUP(); } for (modIndex = 0; modIndex < NewState->PrivilegeCount; modIndex++) { for (assignedIndex = 0; assignedIndex < AccessToken->PrivilegeCount; assignedIndex++) { if (RtlEqualLuid(&NewState->Privileges[modIndex].Luid, &pPrivileges[assignedIndex].Luid)) { if (NewState->Privileges[modIndex].Attributes == 0) { status = RtlpAppendTokenPrivileges( PreviousState, BufferLength, &pPrivileges[assignedIndex], returnedIndex++, &BufferUsed); if (status == STATUS_SUCCESS) { ClearFlag(pPrivileges[assignedIndex].Attributes, SE_PRIVILEGE_ENABLED); adjustedCount++; } } if (IsSetFlag(NewState->Privileges[modIndex].Attributes, SE_PRIVILEGE_ENABLED)) { status = RtlpAppendTokenPrivileges( PreviousState, BufferLength, &pPrivileges[assignedIndex], returnedIndex++, &BufferUsed); if (status == STATUS_SUCCESS) { SetFlag(pPrivileges[assignedIndex].Attributes, SE_PRIVILEGE_ENABLED); adjustedCount++; } } if (IsSetFlag(NewState->Privileges[modIndex].Attributes, SE_PRIVILEGE_REMOVED)) { if (assignedIndex + 1 < AccessToken->PrivilegeCount) { RtlMoveMemory( &pPrivileges[assignedIndex], &pPrivileges[assignedIndex + 1], sizeof(pPrivileges[0]) * AccessToken->PrivilegeCount - assignedIndex - 1); } RtlZeroMemory( &pPrivileges[AccessToken->PrivilegeCount - 1], sizeof(pPrivileges[0])); AccessToken->PrivilegeCount--; adjustedCount++; } break; } } } cleanup: if (PreviousState && (BufferUsed > BufferLength)) { // There was not enough space in PreviousState buffer so roll // the changes back and return STATUS_BUFFER_TOO_SMALL for (returnedIndex = 0; returnedIndex < PreviousState->PrivilegeCount; returnedIndex++) { for (assignedIndex = 0; assignedIndex < AccessToken->PrivilegeCount; assignedIndex++) { if (RtlEqualLuid(&PreviousState->Privileges[returnedIndex].Luid, &pPrivileges[assignedIndex].Luid)) { pPrivileges[assignedIndex].Attributes = PreviousState->Privileges[returnedIndex].Attributes; } } } status = STATUS_BUFFER_TOO_SMALL; } UNLOCK_RWLOCK(&AccessToken->RwLock, isLocked); if (status == STATUS_SUCCESS && !DisableAll && adjustedCount < NewState->PrivilegeCount) { status = STATUS_NOT_ALL_ASSIGNED; } if (pReturnedLength && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_NOT_ALL_ASSIGNED)) { *pReturnedLength = BufferUsed; } else { *pReturnedLength = 0; } return status; }
/*++ * @name FindProcessForShutdown * * The FindProcessForShutdown routine returns a CSR Process which is ready * to be shutdown, and sets the appropriate shutdown flags for it. * * @param CallerLuid * Pointer to the LUID of the CSR Process calling this routine. * * @return Pointer to a CSR Process which is ready to be shutdown. * * @remarks None. * *--*/ PCSR_PROCESS NTAPI FindProcessForShutdown(IN PLUID CallerLuid) { PCSR_PROCESS CsrProcess, ReturnCsrProcess = NULL; PCSR_THREAD CsrThread; NTSTATUS Status; ULONG Level = 0; LUID ProcessLuid; LUID SystemLuid = SYSTEM_LUID; PLIST_ENTRY NextEntry; /* Set the List Pointers */ NextEntry = CsrRootProcess->ListLink.Flink; while (NextEntry != &CsrRootProcess->ListLink) { /* Get the process */ CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); /* Move to the next entry */ NextEntry = NextEntry->Flink; /* Skip this process if it's already been processed */ if (CsrProcess->Flags & CsrProcessSkipShutdown) continue; /* Get the LUID of this process */ Status = CsrGetProcessLuid(CsrProcess->ProcessHandle, &ProcessLuid); /* Check if we didn't get access to the LUID */ if (Status == STATUS_ACCESS_DENIED) { /* Check if we have any threads */ if (CsrProcess->ThreadCount) { /* Impersonate one of the threads and retry */ CsrThread = CONTAINING_RECORD(CsrProcess->ThreadList.Flink, CSR_THREAD, Link); if (CsrImpersonateClient(CsrThread)) { Status = CsrGetProcessLuid(NULL, &ProcessLuid); CsrRevertToSelf(); } else { Status = STATUS_BAD_IMPERSONATION_LEVEL; } } } if (!NT_SUCCESS(Status)) { /* We didn't have access, so skip it */ CsrProcess->Flags |= CsrProcessSkipShutdown; continue; } /* Check if this is the System LUID */ if (RtlEqualLuid(&ProcessLuid, &SystemLuid)) { /* Mark this process */ CsrProcess->ShutdownFlags |= CsrShutdownSystem; } else if (!RtlEqualLuid(&ProcessLuid, CallerLuid)) { /* Our LUID doesn't match with the caller's */ CsrProcess->ShutdownFlags |= CsrShutdownOther; } /* Check if we're past the previous level */ if ((CsrProcess->ShutdownLevel > Level) || !ReturnCsrProcess) { /* Update the level */ Level = CsrProcess->ShutdownLevel; /* Set the final process */ ReturnCsrProcess = CsrProcess; } } /* Check if we found a process */ if (ReturnCsrProcess) { /* Skip this one next time */ ReturnCsrProcess->Flags |= CsrProcessSkipShutdown; } return ReturnCsrProcess; }
BOOLEAN SepPrivilegeCheck( IN PTOKEN Token, IN OUT PLUID_AND_ATTRIBUTES RequiredPrivileges, IN ULONG RequiredPrivilegeCount, IN ULONG PrivilegeSetControl, IN KPROCESSOR_MODE PreviousMode ) /*++ Routine Description: Worker routine for SePrivilegeCheck Arguments: Token - The user's effective token. RequiredPrivileges - A privilege set describing the required privileges. The UsedForAccess bits will be set in any privilege that is actually used (usually all of them). RequiredPrivilegeCount - How many privileges are in the RequiredPrivileges set. PrivilegeSetControl - Describes how many privileges are required. PreviousMode - The previous processor mode. Return Value: Returns TRUE if requested privileges are granted, FALSE otherwise. --*/ { PLUID_AND_ATTRIBUTES CurrentRequiredPrivilege; PLUID_AND_ATTRIBUTES CurrentTokenPrivilege; BOOLEAN RequiredAll; ULONG TokenPrivilegeCount; ULONG MatchCount = 0; ULONG i; ULONG j; PAGED_CODE(); // // Take care of kernel callers first // if (PreviousMode == KernelMode) { return(TRUE); } TokenPrivilegeCount = Token->PrivilegeCount; // // Save whether we require ALL of them or ANY // RequiredAll = (BOOLEAN)(PrivilegeSetControl & PRIVILEGE_SET_ALL_NECESSARY); SepAcquireTokenReadLock( Token ); for ( i = 0 , CurrentRequiredPrivilege = RequiredPrivileges ; i < RequiredPrivilegeCount ; i++, CurrentRequiredPrivilege++ ) { for ( j = 0, CurrentTokenPrivilege = Token->Privileges; j < TokenPrivilegeCount ; j++, CurrentTokenPrivilege++ ) { if ((CurrentTokenPrivilege->Attributes & SE_PRIVILEGE_ENABLED) && (RtlEqualLuid(&CurrentTokenPrivilege->Luid, &CurrentRequiredPrivilege->Luid)) ) { CurrentRequiredPrivilege->Attributes |= SE_PRIVILEGE_USED_FOR_ACCESS; MatchCount++; break; // start looking for next one } } } SepReleaseTokenReadLock( Token ); // // If we wanted ANY and didn't get any, return failure. // if (!RequiredAll && (MatchCount == 0)) { return (FALSE); } // // If we wanted ALL and didn't get all, return failure. // if (RequiredAll && (MatchCount != RequiredPrivilegeCount)) { return(FALSE); } return(TRUE); }