/*++ Copyright (c) 1998 Microsoft Corporation Module Name: LSAWMI.C Abstract: Implement LSA Server event tracing by using WMI trace infrastructure. Author: 16-March-1999 kumarp Revision History: --*/ #include #include #define INITGUID #include // // Globals // ULONG LsapEventTraceFlag = FALSE; TRACEHANDLE LsapTraceRegistrationHandle = (TRACEHANDLE) 0; TRACEHANDLE LsapTraceLoggerHandle = (TRACEHANDLE) 0; // // Forward declaration // ULONG LsapTraceControlCallBack( IN WMIDPREQUESTCODE RequestCode, IN PVOID RequestContext, IN OUT ULONG *InOutBufferSize, IN OUT PVOID Buffer ); LPWSTR LsapMakeNullTerminatedString( IN PUNICODE_STRING u ); // // before you change the elements of the following structure, // read notes in lsawmi.h file // TRACE_GUID_REGISTRATION LsapTraceGuids[] = { {&LsapTraceEventGuid_QuerySecret, NULL}, {&LsaTraceEventGuid_Close, NULL}, {&LsaTraceEventGuid_OpenPolicy, NULL}, {&LsaTraceEventGuid_QueryInformationPolicy, NULL}, {&LsaTraceEventGuid_SetInformationPolicy, NULL}, {&LsaTraceEventGuid_EnumerateTrustedDomains, NULL}, {&LsaTraceEventGuid_LookupNames, NULL}, {&LsaTraceEventGuid_LookupSids, NULL}, {&LsaTraceEventGuid_OpenTrustedDomain, NULL}, {&LsaTraceEventGuid_QueryInfoTrustedDomain, NULL}, {&LsaTraceEventGuid_SetInformationTrustedDomain, NULL}, {&LsaTraceEventGuid_QueryTrustedDomainInfoByName, NULL}, {&LsaTraceEventGuid_SetTrustedDomainInfoByName, NULL}, {&LsaTraceEventGuid_EnumerateTrustedDomainsEx, NULL}, {&LsaTraceEventGuid_CreateTrustedDomainEx, NULL}, {&LsaTraceEventGuid_QueryDomainInformationPolicy, NULL}, {&LsaTraceEventGuid_SetDomainInformationPolicy, NULL}, {&LsaTraceEventGuid_OpenTrustedDomainByName, NULL}, {&LsaTraceEventGuid_QueryForestTrustInformation, NULL}, {&LsaTraceEventGuid_SetForestTrustInformation, NULL}, {&LsaTraceEventGuid_LookupIsolatedNameInTrustedDomains, NULL}, }; #define LsapTraceGuidCount (sizeof(LsapTraceGuids) / sizeof(TRACE_GUID_REGISTRATION)) ULONG _stdcall LsapInitializeWmiTrace( LPVOID ThreadParams ) /*++ Routine Description: Register WMI Trace Guids. This routine is called during LSA initialization. LSA gets initialized before WMI therefore we call this from a seaprate thread. This thread can then wait on WMI. Parameters: ThreadParams - Currently ignored. Reture Values: NTSTATUS - Standard Nt Result Code --*/ { ULONG Status = ERROR_SUCCESS; HMODULE hModule; TCHAR FileName[MAX_PATH+1]; DWORD nLen = 0; #define RESOURCE_NAME TEXT("LsaMofResource") #define IMAGE_PATH TEXT("lsass.exe") LsapEnterFunc("LsapInitializeWmiTrace"); hModule = GetModuleHandle(IMAGE_PATH); if (hModule != NULL) { nLen = GetModuleFileName(hModule, FileName, MAX_PATH); } if (nLen == 0) { lstrcpy(FileName, IMAGE_PATH); } // // Register Trace GUIDs // Status = RegisterTraceGuids( LsapTraceControlCallBack, NULL, &LsapTraceControlGuid, LsapTraceGuidCount, LsapTraceGuids, FileName, RESOURCE_NAME, &LsapTraceRegistrationHandle); #if DBG if (Status != ERROR_SUCCESS) { DebugLog(( DEB_ERROR, "LsapInitializeWmiTrace failed: 0x%x\n", Status)); } #endif // DBG return Status; } ULONG LsapTraceControlCallBack( IN WMIDPREQUESTCODE RequestCode, IN PVOID RequestContext, IN OUT ULONG *InOutBufferSize, IN OUT PVOID Buffer ) /*++ Routine Description: Call back function called by the WMI module to enable or disable LSA tracing. Arguments: RequestCode - WMI_ENABLE_EVENTS or WMI_DISABLE_EVENTS RequestContext - currently ignored InOutBufferSize - size of data returned by this call back. Currently always set to 0. Buffer - pointer to data received. In case of WMI_ENABLE_EVENTS, this is a pointer to the trace handle. Return Value: Win32 error code. Notes: --*/ { ULONG Status = ERROR_SUCCESS; LsapEnterFunc("LsapTraceControlCallBack"); switch (RequestCode) { case WMI_ENABLE_EVENTS: { LsapTraceLoggerHandle = GetTraceLoggerHandle(Buffer); LsapEventTraceFlag = TRUE; // enable flag break; } case WMI_DISABLE_EVENTS: { LsapTraceLoggerHandle = (TRACEHANDLE) 0; LsapEventTraceFlag = FALSE; // disable flag break; } default: { Status = ERROR_INVALID_PARAMETER; break; } } *InOutBufferSize = 0; return Status; } NTSTATUS LsapStartWmiTraceInitThread(void) /*++ Routine Description: Start the thread that registers WMI trace guids. Parameters: None Return Values: NTSTATUS - Standard Nt Result Code --*/ { NTSTATUS Status=STATUS_SUCCESS; HANDLE ThreadHandle; ULONG ThreadId = 0; ULONG WinError; ThreadHandle = CreateThread(NULL, 0, LsapInitializeWmiTrace, NULL, 0, &ThreadId); if (NULL == ThreadHandle) { Status = STATUS_UNSUCCESSFUL; WinError = GetLastError(); DebugLog((DEB_ERROR, "Failed to create thread for LsapInitializeWmiTrace: 0x%x", WinError)); } else { CloseHandle(ThreadHandle); } return Status; } VOID LsapTraceEvent( IN ULONG WmiEventType, IN LSA_TRACE_EVENT_TYPE LsaTraceEventType ) /*++ Routine Description: This routine will do a WMI event trace. Parameters: WmiEventType - Event Type, valid values are: EVENT_TRACE_TYPE_START EVENT_TRACE_TYPE_END TraceGuid - Index in LsapTraceGuids[] Return Values: None. --*/ { LsapTraceEventWithData(WmiEventType, LsaTraceEventType, 0, NULL); } VOID LsapTraceEventWithData( IN ULONG WmiEventType, IN LSA_TRACE_EVENT_TYPE LsaTraceEventType, IN ULONG ItemCount, IN PUNICODE_STRING Items OPTIONAL ) /*++ Routine Description: This routine will do a WMI event trace. Parameters: WmiEventType - Event Type, valid values are: EVENT_TRACE_TYPE_START EVENT_TRACE_TYPE_END EVENT_TRACE_TYPE_INFO TraceGuid - Index in LsapTraceGuids[] ItemCount - the number of elements in Items Items - an array of information. The unicode strings don't have to represent strings -- can be binary data whose length is denoted by the Length field. Return Values: None. --*/ { #if DBG ULONG WinError; #endif WCHAR NullChar = UNICODE_NULL; PVOID BuffersToFree[10]; ULONG BuffersToFreeCount = 0; ULONG i; struct { EVENT_TRACE_HEADER EventTrace; MOF_FIELD EventInfo[2]; } Event; // // Theoretically, only test LsapEventTraceFlag would be enough, since // LsapEventTraceFlag will remain FALSE in Registry Mode, because // LsapInitializeTrace() will never been called in Registry Mode. // Thus nobody will change the value of LsapEventTraceFlag // if (!LsapEventTraceFlag) { return; } // // Fill the event information. // ZeroMemory(&Event, sizeof(Event)); Event.EventTrace.GuidPtr = (ULONGLONG) LsapTraceGuids[LsaTraceEventType].Guid; Event.EventTrace.Class.Type = (UCHAR) WmiEventType; Event.EventTrace.Flags |= (WNODE_FLAG_USE_GUID_PTR | // GUID is actually a pointer WNODE_FLAG_TRACED_GUID); // denotes a trace Event.EventTrace.Size = sizeof(Event.EventTrace); // no other parameters/information if ( (LsaTraceEventType == LsaTraceEvent_LookupIsolatedNameInTrustedDomains) ) { // // Add the flag that indicates that there is more data // Event.EventTrace.Flags |= WNODE_FLAG_USE_MOF_PTR; // // Make sure enough space has been allocated on the stack for us // ASSERT(sizeof(Event.EventInfo) >= (sizeof(MOF_FIELD) * 2)); ASSERT( (ItemCount == 2) && (Items != NULL) ); // // Fill in the data requested // for (i = 0; i < ItemCount; i++) { LPWSTR String = NULL; ULONG Length; // // Re'alloc to get a NULL terminated string // String = LsapMakeNullTerminatedString(&Items[i]); if (NULL == String) { String = &NullChar; Length = sizeof(NullChar); } else { Length = Items[i].Length + sizeof(WCHAR); } Event.EventInfo[i].Length = Length; Event.EventInfo[i].DataPtr = (ULONGLONG)String; Event.EventTrace.Size += sizeof(Event.EventInfo[i]); if (&NullChar != String) { ASSERT(BuffersToFreeCount < sizeof(BuffersToFree)/sizeof(BuffersToFree[0])); BuffersToFree[BuffersToFreeCount++] = String; } } } #if DBG WinError = #endif TraceEvent(LsapTraceLoggerHandle, (PEVENT_TRACE_HEADER) &Event); #if DBG if (WinError != ERROR_SUCCESS) { DebugLog(( DEB_ERROR, "WMI TraceEvent failed, status %x\n", WinError)); } #endif for (i = 0; i < BuffersToFreeCount; i++) { LsapFreeLsaHeap(BuffersToFree[i]); } } LPWSTR LsapGetClientNetworkAddress( VOID ) /*++ Routine Description: This routine returns a NULL terminated string that represents the network address of the client. If the address cannot be obtained, NULL is returned. If the return value is non-NULL, the string must be freed with RpcStringFreeW. Parameters: None. Return Values: See description. --*/ { ULONG RpcStatus; RPC_BINDING_HANDLE ServerBinding = NULL; PWSTR StringBinding = NULL; LPWSTR NetworkAddr = NULL; RpcStatus = RpcBindingServerFromClient(NULL, &ServerBinding); if (RPC_S_OK == RpcStatus) { RpcStatus = RpcBindingToStringBindingW(ServerBinding, &StringBinding); if (RPC_S_OK == RpcStatus) { RpcStatus = RpcStringBindingParseW(StringBinding, NULL, NULL, &NetworkAddr, NULL, NULL ); RpcStringFreeW(&StringBinding); } RpcBindingFree(&ServerBinding); } return NetworkAddr; } LPWSTR LsapMakeNullTerminatedString( IN PUNICODE_STRING u ) /*++ Routine Description: This routine returns a NULL terminated string composed of the data in u. The string must be freed with LsapFreeLsaHeap(). If u->Length is 0, a non-NULL string with the NULL character as the first character is returned. Parameters: u -- a unicode string Return Values: See description. --*/ { LPWSTR String = NULL; ULONG Length; if (u) { Length = u->Length + sizeof(WCHAR); String = LsapAllocateLsaHeap(Length); if (String != NULL) { RtlCopyMemory(String, u->Buffer, u->Length); String[u->Length / sizeof(WCHAR)] = UNICODE_NULL; } } return String; }