//+----------------------------------------------------------------------- // // Microsoft Windows // // Copyright (c) Microsoft Corporation 1991 - 1992 // // File: util.c // // Contents: General Purpose functions for the security interface // // Functions: SPException -- Handler for exceptions in packages // WLsaControlFunction -- Worker for SecurityPackageControl() // LsaControlFunction -- User mode stub // LsaQueryPackage -- User mode stub // // // History: 14 Aug 92 RichardW Created // //------------------------------------------------------------------------ #include extern "C" { #include "sesmgr.h" #include "spdebug.h" #include "perf.hxx" } NTSTATUS GetMemStats(PUCHAR, DWORD *); #if DBG SpmExceptDbg ExceptDebug; DWORD FaultingTid; extern SpmDbg_MemoryFailure MemFail; #endif // DBG typedef SecurityUserData SECURITY_USER_DATA, *PSECURITY_USER_DATA; //+--------------------------------------------------------------------------- // // Function: SpExceptionFilter // // Synopsis: General Exception filter, invoked by the SP_EXCEPTION macro. // // Arguments: [pSession] -- // [pException] -- // // // History: 8-09-95 RichardW Created // // Notes: // //---------------------------------------------------------------------------- LONG SpExceptionFilter( PVOID pSession, EXCEPTION_POINTERS * pException) { DWORD_PTR CurrentPackage; PLSAP_SECURITY_PACKAGE pPackage = NULL; UNICODE_STRING LsaString = { 3 * sizeof( WCHAR ), 4 * sizeof( WCHAR ), L"LSA" }; #if DBG DsysException(pException); PSpmExceptDbg pExcept; pExcept = (PSpmExceptDbg) TlsGetValue(dwExceptionInfo); if (!pExcept) { pExcept = &ExceptDebug; TlsSetValue(dwExceptionInfo, pExcept); } FaultingTid = GetCurrentThreadId(); pExcept->ThreadId = GetCurrentThreadId(); pExcept->pInstruction = pException->ExceptionRecord->ExceptionAddress; pExcept->Access = pException->ExceptionRecord->ExceptionInformation[0]; pExcept->pMemory = (void *) pException->ExceptionRecord->ExceptionInformation[1]; #endif CurrentPackage = GetCurrentPackageId(); if (CurrentPackage != SPMGR_ID) { pPackage = SpmpLocatePackage( CurrentPackage ); } SpmpReportEventU( EVENTLOG_ERROR_TYPE, SPMEVENT_PACKAGE_FAULT, CATEGORY_SPM, sizeof(EXCEPTION_RECORD), pException->ExceptionRecord, 1, ((CurrentPackage == SPMGR_ID || pPackage == NULL) ? &LsaString : &pPackage->Name ) ); return(EXCEPTION_EXECUTE_HANDLER); } //+------------------------------------------------------------------------- // // Function: SPException // // Synopsis: Handles an exception in a security package // // Effects: Varies, but may force an unload of a package. // // Arguments: // // Requires: // // Returns: // // Notes: // //-------------------------------------------------------------------------- NTSTATUS SPException(NTSTATUS scRet, ULONG_PTR dwPackageID) { PSession pSession; PLSAP_SECURITY_PACKAGE pPackage; #if DBG PSpmExceptDbg pException = (PSpmExceptDbg) TlsGetValue(dwExceptionInfo); #endif pSession = GetCurrentSession(); DebugLog((DEB_ERROR, "[%x] Exception in a package, code %x\n", pSession->dwProcessID, scRet)); DebugLog((DEB_ERROR, "[%x] Address was @%x, %s address %x\n", pSession->dwProcessID, pException->pInstruction, (pException->Access ? "write" : "read"), pException->pMemory)); if (dwPackageID == SPMGR_ID) { DebugLog((DEB_ERROR, " LSA itself hit a fault, thread %d\n", GetCurrentThreadId())); DebugLog((DEB_ERROR, " (ExceptionInfo @%x)\n", TlsGetValue(dwExceptionInfo))); #if DBG DsysAssertMsg( 0, "exception in LSA" ); #endif return(scRet); } pPackage = SpmpLocatePackage( dwPackageID ); if (!pPackage) { DebugLog((DEB_ERROR, " Invalid package ID passed\n")); return(scRet); } if ((scRet == STATUS_ACCESS_VIOLATION) || (scRet == E_POINTER)) { DebugLog((DEB_ERROR, " Package %ws created an access violation\n", pPackage->Name.Buffer)); // Flag package as invalid pPackage->fPackage |= SP_INVALID; } if ((scRet == STATUS_NO_MEMORY) || (scRet == STATUS_INSUFFICIENT_RESOURCES)) { DebugLog((DEB_ERROR, " Out of memory situation exists\n")); DebugLog((DEB_ERROR, " Further requests may fail unless memory is freed\n")); } // // if the code is a success code, it is probably a WIN32 error so we // map it as such return(scRet); } //+------------------------------------------------------------------------- // // Function: WLsaQueryPackage // // Synopsis: Get info on a package (short enum), copy to client's address // space // // Effects: none // // Arguments: // // Requires: // // Returns: // // Notes: // //-------------------------------------------------------------------------- NTSTATUS WLsaQueryPackageInfo( PSECURITY_STRING pPackageName, PSecPkgInfo * ppInfo ) { NTSTATUS scRet; PLSAP_SECURITY_PACKAGE pPackage; WCHAR * pszString; PSession pSession = GetCurrentSession(); ULONG cbData; PSecPkgInfo pClientInfo = NULL; PBYTE Where; UNICODE_STRING CommentString; UNICODE_STRING NameString; PSecPkgInfo pLocalInfo = NULL; SecPkgInfo PackageInfo = { 0 }; LONG_PTR ClientOffset; ULONG ulStructureSize = sizeof(SecPkgInfo); DebugLog((DEB_TRACE, "QueryPackage\n")); *ppInfo = NULL; pPackage = SpmpLookupPackage(pPackageName); if (!pPackage) { return(STATUS_NO_SUCH_PACKAGE); } SetCurrentPackageId(pPackage->dwPackageID); StartCallToPackage( pPackage ); __try { scRet = pPackage->FunctionTable.GetInfo(&PackageInfo); } __except (SP_EXCEPTION) { scRet = GetExceptionCode(); scRet = SPException(scRet, pPackage->dwPackageID); } EndCallToPackage( pPackage ); if (FAILED(scRet)) { return(scRet); } // // Marshall the data to copy to the client // RtlInitUnicodeString( &NameString, PackageInfo.Name ); RtlInitUnicodeString( &CommentString, PackageInfo.Comment ); cbData = ulStructureSize + NameString.MaximumLength + CommentString.MaximumLength; pLocalInfo = (PSecPkgInfo) LsapAllocatePrivateHeap(cbData); if (pLocalInfo == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); } pClientInfo = (PSecPkgInfo) LsapClientAllocate(cbData); if (pClientInfo == NULL) { LsapFreePrivateHeap(pLocalInfo); return(STATUS_INSUFFICIENT_RESOURCES); } ClientOffset = (LONG_PTR) ((PBYTE) pClientInfo - (PBYTE) pLocalInfo); Where = (PBYTE) (pLocalInfo + 1); *pLocalInfo = PackageInfo; pLocalInfo->Name = (LPWSTR) (Where + ClientOffset); RtlCopyMemory( Where, NameString.Buffer, NameString.MaximumLength ); Where += NameString.MaximumLength; pLocalInfo->Comment = (LPWSTR) (Where + ClientOffset); RtlCopyMemory( Where, CommentString.Buffer, CommentString.MaximumLength ); Where += CommentString.MaximumLength; DsysAssert(Where - (PBYTE) pLocalInfo == (LONG) cbData); scRet = LsapCopyToClient( pLocalInfo, pClientInfo, cbData); LsapFreePrivateHeap(pLocalInfo); if (FAILED(scRet)) { LsapClientFree(pClientInfo); } *ppInfo = pClientInfo; return(scRet); } //+------------------------------------------------------------------------- // // Function: WLsaGetSecurityUserInfo // // Synopsis: worker function to get info about a logon session // // Effects: // // Arguments: // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- NTSTATUS WLsaGetSecurityUserInfo( IN PLUID pLogonId, IN ULONG fFlags, OUT PSECURITY_USER_DATA * pUserInfo ) { PLSAP_LOGON_SESSION pSession; NTSTATUS Status; PSECURITY_USER_DATA LocalUserData = NULL; PSECURITY_USER_DATA ClientBuffer = NULL; SECPKG_CLIENT_INFO ClientInfo; ULONG BufferSize; PUCHAR Where; LONG_PTR Offset; ULONG ulStructureSize = sizeof(SECURITY_USER_DATA); DebugLog((DEB_TRACE_WAPI,"WLsaGetSecurityUserInfo called\n")); // // if the logon ID is null, it is for the caller // so we know to go to the primary package. // if (pLogonId == NULL) { Status = LsapGetClientInfo(&ClientInfo); if (!NT_SUCCESS(Status)) { return(Status); } pLogonId = &ClientInfo.LogonId; } pSession = LsapLocateLogonSession( pLogonId ); if (!pSession) { DebugLog((DEB_WARN,"WLsaGetSecurityUserInfo called for non-existent LUID 0x%x:0x%x\n", pLogonId->LowPart,pLogonId->HighPart)); Status = STATUS_NO_SUCH_LOGON_SESSION; goto Cleanup; } BufferSize = ulStructureSize + pSession->AccountName.Length + pSession->AuthorityName.Length + pSession->LogonServer.Length + RtlLengthSid(pSession->UserSid); LocalUserData = (PSECURITY_USER_DATA) LsapAllocatePrivateHeap(BufferSize); if (LocalUserData == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } ClientBuffer = (PSECURITY_USER_DATA) LsapClientAllocate(BufferSize); if (ClientBuffer == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } Offset = (LONG_PTR) ((PUCHAR) ClientBuffer - (PUCHAR) LocalUserData); Where = (PUCHAR) (LocalUserData + 1); // // Copy in all the fields from the logon session. // LocalUserData->pSid = (PSID) (Where + Offset); RtlCopyMemory( Where, pSession->UserSid, RtlLengthSid(pSession->UserSid) ); Where += RtlLengthSid(pSession->UserSid); // // Copy in the user name // LocalUserData->UserName.Length = LocalUserData->UserName.MaximumLength = pSession->AccountName.Length; LocalUserData->UserName.Buffer = (LPWSTR) (Where + Offset); RtlCopyMemory( Where, pSession->AccountName.Buffer, pSession->AccountName.Length ); Where += pSession->AccountName.Length; // // Copy in the domain name // LocalUserData->LogonDomainName.Length = LocalUserData->LogonDomainName.MaximumLength = pSession->AuthorityName.Length; LocalUserData->LogonDomainName.Buffer = (LPWSTR) (Where + Offset); RtlCopyMemory( Where, pSession->AuthorityName.Buffer, pSession->AuthorityName.Length ); Where += pSession->AuthorityName.Length; // // Copy in the logon server // LocalUserData->LogonServer.Length = LocalUserData->LogonServer.MaximumLength = pSession->LogonServer.Length; LocalUserData->LogonServer.Buffer = (LPWSTR) (Where + Offset); RtlCopyMemory( Where, pSession->LogonServer.Buffer, pSession->LogonServer.Length ); Where += pSession->LogonServer.Length; // // Copy this to the client // LsapReleaseLogonSession( pSession ); Status = LsapCopyToClient( LocalUserData, ClientBuffer, BufferSize ); if (!NT_SUCCESS(Status)) { goto Cleanup; } *pUserInfo = ClientBuffer; ClientBuffer = NULL; Cleanup: if (LocalUserData != NULL) { LsapFreePrivateHeap(LocalUserData); } if (ClientBuffer != NULL) { LsapClientFree(ClientBuffer); } DebugLog((DEB_TRACE_WAPI,"GetUserInfo returned %x\n",Status)); return(Status); } HANDLE hEventLog = INVALID_HANDLE_VALUE; DWORD LoggingLevel = (1 << EVENTLOG_ERROR_TYPE) | (1 << EVENTLOG_WARNING_TYPE) | (1 << EVENTLOG_INFORMATION_TYPE) ; WCHAR EventSourceName[] = TEXT("LsaSrv"); #define MAX_EVENT_STRINGS 8 //+--------------------------------------------------------------------------- // // Function: SpmpInitializeEvents // // Synopsis: Connects to event log service // // Arguments: (none) // // History: 1-03-95 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL SpmpInitializeEvents(void) { HKEY hKey; int err; DWORD disp; err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\EventLog\\System\\LsaSrv"), 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &disp); if (err) { return(FALSE); } if (disp == REG_CREATED_NEW_KEY) { RegSetValueEx( hKey, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (PBYTE) TEXT("%SystemRoot%\\system32\\lsasrv.dll"), sizeof(TEXT("%SystemRoot%\\system32\\lsasrv.dll")) ); RegSetValueEx( hKey, TEXT("CategoryMessageFile"), 0, REG_EXPAND_SZ, (PBYTE) TEXT("%SystemRoot%\\system32\\lsasrv.dll"), sizeof(TEXT("%SystemRoot%\\system32\\lsasrv.dll")) ); disp = 7; RegSetValueEx( hKey, TEXT("TypesSupported"), 0, REG_DWORD, (PBYTE) &disp, sizeof(DWORD) ); disp = CATEGORY_MAX_CATEGORY - 1; RegSetValueEx( hKey, TEXT("CategoryCount"), 0, REG_DWORD, (PBYTE) &disp, sizeof(DWORD) ); } RegCloseKey(hKey); hEventLog = RegisterEventSource(NULL, EventSourceName); if (hEventLog) { return(TRUE); } hEventLog = INVALID_HANDLE_VALUE; DebugLog((DEB_ERROR, "Could not open event log, error %d\n", GetLastError())); return(FALSE); } //+--------------------------------------------------------------------------- // // Function: ReportServiceEvent // // Synopsis: Reports an event to the event log // // Arguments: [EventType] -- EventType (ERROR, WARNING, etc.) // [EventId] -- Event ID // [SizeOfRawData] -- Size of raw data // [RawData] -- Raw data // [NumberOfStrings] -- number of strings // ... -- PWSTRs to string data // // History: 1-03-95 RichardW Created // // Notes: // //---------------------------------------------------------------------------- DWORD SpmpReportEvent( IN BOOL Unicode, IN WORD EventType, IN DWORD EventId, IN DWORD Category, IN DWORD SizeOfRawData, IN PVOID RawData, IN DWORD NumberOfStrings, ... ) { va_list arglist; ULONG i; PWSTR Strings[ MAX_EVENT_STRINGS ]; PSTR StringsA[ MAX_EVENT_STRINGS ]; DWORD rv; if (hEventLog == INVALID_HANDLE_VALUE) { if (!SpmpInitializeEvents()) { return((DWORD) -1); } } // // We're not supposed to be logging this, so nuke it // if ((LoggingLevel & (1 << EventType)) == 0) { return(0); } // // Look at the strings, if they were provided // va_start( arglist, NumberOfStrings ); if (NumberOfStrings > MAX_EVENT_STRINGS) { NumberOfStrings = MAX_EVENT_STRINGS; } for (i=0; i MAX_EVENT_STRINGS ) { NumberOfStrings = MAX_EVENT_STRINGS; } for ( i = 0 ; i < NumberOfStrings ; i++ ) { Strings[ i ] = va_arg( arglist, PUNICODE_STRING ); } // // Report the event to the eventlog service // rv = ElfReportEventW( hEventLog, EventType, ( USHORT )Category, EventId, NULL, ( USHORT )NumberOfStrings, SizeOfRawData, Strings, RawData, 0, NULL, NULL ); if ( !NT_SUCCESS( rv )) { DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, rv )); goto Cleanup; } rv = ERROR_SUCCESS; Cleanup: return rv; } BOOL SpmpShutdownEvents(void) { return(DeregisterEventSource(hEventLog)); }