/*++ Copyright (c) 1997-1999 Microsoft Corporation Module Name: datastr.c Abstract: WMI data structure management Author: 16-Jan-1997 AlanWar Revision History: --*/ #include "wmiump.h" GUID WmipBinaryMofGuid = BINARY_MOF_GUID; ULONG WmipLinkDataSourceToList( PBDATASOURCE DataSource, BOOLEAN AddDSToList ); ULONG WmipMangleInstanceName( LPGUID Guid, PWCHAR Name, ULONG MaxMangledNameSize, PWCHAR MangledName ); BOOLEAN WmipIsNumber( LPCWSTR String ); VOID WmipSaveTraceGuidMap( LPGUID Guid, PBINSTANCESET InstanceSet ); ULONG WmipDetermineInstanceBaseIndex( LPGUID Guid, PWCHAR InstanceBaseName, ULONG InstanceCount ); ULONG WmipBuildInstanceSet( PWMIREGGUIDW RegGuid, PWMIREGINFOW RegisrationInfo, PBINSTANCESET InstanceSet, LPCTSTR MofImagePath ); BOOLEAN WmipValidateStringInRegInfo( PWMIREGINFOW RegistrationInfo, ULONG Offset, ULONG RegistrationInfoSize ) { PUSHORT StringCount; if (Offset == 0) { return(TRUE); } else if (Offset >= 0x80000000) { return(FALSE); } StringCount = (PUSHORT)OffsetToPtr(RegistrationInfo, Offset); Offset += sizeof(USHORT); if (Offset > RegistrationInfoSize) { return(FALSE); } if ((Offset + *StringCount) > RegistrationInfoSize) { return(FALSE); } return(TRUE); } BOOLEAN WmipValidateRegistrationInfo( PWMIREGINFOW RegistrationInfo, ULONG RegistrationInfoSize ) { ULONG i,j; ULONG Offset, Size; PUSHORT StringCount; PWMIREGGUIDW RegGuid; // // Validate that RegistrationInfo is correct // 1. ->BufferSize is <= Actual buffer size // 2. ->RegistryPath is <= Actual buffer size // 3. ->MofResourceName is <= Actual buffer size // 4. All WmiRegGuid structures would fit into the buffer // 5. Any offsets within the WmiRegGuid structure are within // the buffer if (RegistrationInfoSize < FIELD_OFFSET(WMIREGINFOW, WmiRegGuid)) { WmipDebugPrint(("WMI: RegistrationInfoSize is bogus\n")); return(FALSE); } if (RegistrationInfo->BufferSize > RegistrationInfoSize) { WmipDebugPrint(("WMI: RegistrationInfo->BufferSize is bogus\n")); return(FALSE); } if (! WmipValidateStringInRegInfo(RegistrationInfo, RegistrationInfo->RegistryPath, RegistrationInfoSize)) { WmipDebugPrint(("WMI: RegistrationInfo->RegistrationInfo is bogus\n")); return(FALSE); } if (! WmipValidateStringInRegInfo(RegistrationInfo, RegistrationInfo->MofResourceName, RegistrationInfoSize)) { WmipDebugPrint(("WMI: RegistrationInfo->MofResourceName is bogus\n")); return(FALSE); } if (RegistrationInfo->GuidCount >= 0x80000000) { return(FALSE); } Size = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) + (RegistrationInfo->GuidCount * sizeof(WMIREGGUIDW)); if (Size > RegistrationInfoSize) { WmipDebugPrint(("WMI: RegistrationInfo->GuidCount is bogus\n")); return(FALSE); } for (i = 0; i < RegistrationInfo->GuidCount; i++) { RegGuid = &RegistrationInfo->WmiRegGuid[i]; if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_LIST) { Offset = RegGuid->InstanceNameList; if (Offset >= 0x80000000) { return(FALSE); } for (j = 0; j < RegGuid->InstanceCount; j++) { if (! WmipValidateStringInRegInfo(RegistrationInfo, Offset, RegistrationInfoSize)) { WmipDebugPrint(("WMI: InstanceList bogus for RegGuid[%d]\n", i)); return(FALSE); } StringCount = (PUSHORT)OffsetToPtr(RegistrationInfo, Offset); Offset += *StringCount + sizeof(USHORT); } } else if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_BASENAME) { if (! WmipValidateStringInRegInfo(RegistrationInfo, RegGuid->BaseNameOffset, RegistrationInfoSize)) { WmipDebugPrint(("WMI: BaseName for RegGuid[%d] is bogus\n", i)); return(FALSE); } } } return(TRUE); } ULONG WmipAddDataSource( PTCHAR QueryBinding, ULONG RequestAddress, ULONG RequestContext, LPCTSTR MofImagePath, PWMIREGINFOW RegistrationInfo, ULONG RegistrationInfoSize, ULONG_PTR *ProviderId, BOOLEAN IsAnsi ) /*++ Routine Description: Adds a new data source to WMI data source list Arguments: QueryBinding is the binding string of the data providers RPC server RequestAddress is the request callback address in data provider's process to call with WMI requests. RequestContext is the request context to pass to data provider's WMI request callback. MofImagePath is a pointer to an image that contains the MOF resource RegistrationInfo is a pointer to a data structure that has registration information RegistrationInfoSize is the number of bytes passed in the registration information parameter RegistrationInfo. ProviderId is a pointer to a ULONG_PTR that on entry contains the provider id for kernel mode providers. On return it contains the assigned provider id for user mode data providers. IsAnsi is TRUE then data provider is expecting all dynamic instance names to be Ansi and will put dynamic instance names in as ansi Return Value: Error or success code --*/ { PBDATASOURCE DataSource, DataSource2; ULONG Status; PWMIREGGUIDW RegGuid; PINSTANCESET BinaryMofInstanceSet = NULL; ULONG i,j; ULONG InstanceCount; PBINSTANCESET InstanceSet; PBGUIDENTRY GuidEntry; PWCHAR RegistryPath, RegistryPathTemp; BOOLEAN KmDataSource, AppendToDS; BYTE WnodeBuffer[sizeof(WNODE_HEADER) + AVGGUIDSPERDS * sizeof(GUID)]; PWNODE_HEADER Wnode; LPWSTR MofResourceName, MofImagePathUnicode; LPWSTR MofResourceNamePtr; ULONG MofResourceNameLen; BOOLEAN NewMofResource; #ifdef MEMPHIS LPSTR MofResourceNameAnsi; #endif #ifdef HEAPVALIDATION WmipDebugPrint(("WMI: Adding data source %x\n", *ProviderId)); WmipAssert(RtlValidateProcessHeaps()); #endif if (! WmipValidateRegistrationInfo(RegistrationInfo, RegistrationInfoSize)) { WmipDebugPrint(("WMI: Invalid Registration Info buffer for %ws\n", MofImagePath ? MofImagePath : TEXT("Unknown"))); WmipReportEventLog(EVENT_WMI_INVALID_REGINFO, EVENTLOG_WARNING_TYPE, 0, sizeof(ULONG), RegistrationInfo, 1, MofImagePath ? MofImagePath : TEXT("Unknown")); return(ERROR_WMI_INVALID_REGINFO); } DataSource = WmipAllocDataSource(); if (DataSource == NULL) { WmipDebugPrint(("WMI: WmipAddDataSource: WmipAllocDataSource failed\n")); return(ERROR_NOT_ENOUGH_MEMORY); } if (*ProviderId == 0) { // // User mode data provider specific initialization *ProviderId = (ULONG_PTR)DataSource; KmDataSource = FALSE; AppendToDS = FALSE; if ((QueryBinding != NULL) && (RequestAddress != 0)) { DataSource->BindingString = WmipAlloc((_tcslen(QueryBinding) + 1) * sizeof(TCHAR)); if (DataSource->BindingString != NULL) { _tcscpy(DataSource->BindingString, QueryBinding); DataSource->RequestAddress = RequestAddress; DataSource->RequestContext = RequestContext; } else { WmipUnreferenceDS(DataSource); return(ERROR_NOT_ENOUGH_MEMORY); } } else { // // All data sources must supply a query binding WmipUnreferenceDS(DataSource); return(ERROR_INVALID_PARAMETER); } } else if (*ProviderId == INTERNAL_PROVIDER_ID) { DataSource->Flags |= DS_INTERNAL; KmDataSource = FALSE; AppendToDS = FALSE; } else { // // Kernel mode specific initialization // // We allow multiple registrations to use the same KM provider id. Any // new guids will be just added to the end of the current data source // and after that it will look as though they all came from a single // registration. WmipAssert(*ProviderId != 0); DataSource2 = WmipFindDSByProviderId(*ProviderId); if (DataSource2 != NULL) { WmipUnreferenceDS(DataSource2); WmipUnreferenceDS(DataSource); DataSource = DataSource2; AppendToDS = TRUE; } else { AppendToDS = FALSE; } KmDataSource = TRUE; DataSource->Flags |= DS_KERNEL_MODE; } if (! AppendToDS) { // // This is the first registration for the data source so do any // one time data source initialization now DataSource->ProviderId = *ProviderId; } // // Loop over each guid being registered and build instance sets and // guid entries. RegGuid = RegistrationInfo->WmiRegGuid; for (i = 0; i < RegistrationInfo->GuidCount; i++, RegGuid++) { if (! (RegGuid->Flags & WMIREG_FLAG_REMOVE_GUID)) { // // Allocate an instance set for this new set of instances InstanceSet = WmipAllocInstanceSet(); if (InstanceSet == NULL) { WmipUnreferenceDS(DataSource); WmipDebugPrint(("WMI: WmipAddDataSource: WmipAllocInstanceSet failed\n")); return(ERROR_NOT_ENOUGH_MEMORY); } // // We will allocate a proper guid entry for the instance set when // the data source gets linked into the main data source list so // we stash a pointer to the guid away now. InstanceSet->GuidEntry = (PBGUIDENTRY)&RegGuid->Guid; // // Minimally initialize the InstanceSet and add it to the DataSource's // list of InstanceSets. We do this first so that if there is any // failure below and the DataSource can'e be fully registered the // instance set and guid entry will be free when the DataSource is // freed. InstanceSet->DataSource = DataSource; InstanceSet->Flags |= IS_NEWLY_REGISTERED; if (IsAnsi) { InstanceSet->Flags |= IS_ANSI_INSTANCENAMES; } if (DataSource->Flags & DS_INTERNAL) { InstanceSet->Flags |= IS_INTERNAL_PROVIDER; } Status = WmipBuildInstanceSet(RegGuid, RegistrationInfo, InstanceSet, MofImagePath); // // If this is the guid that represents the binary mof data // then remember the InstanceSet for later if (IsEqualGUID(&RegGuid->Guid, &WmipBinaryMofGuid)) { BinaryMofInstanceSet = InstanceSet; } InsertHeadList(&DataSource->ISHead, &InstanceSet->DSISList); if (Status != ERROR_SUCCESS) { WmipUnreferenceDS(DataSource); return(Status); } } } if (! AppendToDS) { // // If this is the first time the data provider has registered then // Build registry path in data source RegistryPath = (LPWSTR)OffsetToPtr(RegistrationInfo, RegistrationInfo->RegistryPath); if ( (RegistrationInfo->RegistryPath != 0) && (WmipValidateCountedString(RegistryPath)) ) { RegistryPathTemp = WmipAlloc((*RegistryPath+1) * sizeof(WCHAR)); if (RegistryPathTemp == NULL) { WmipDebugPrint(("WMI: WmipAddDataSource: Couldn't allocate RegistryPath\n")); WmipUnreferenceDS(DataSource); return(ERROR_NOT_ENOUGH_MEMORY); } memcpy(RegistryPathTemp, RegistryPath+1, *RegistryPath); RegistryPathTemp[*RegistryPath/sizeof(WCHAR)] = UNICODE_NULL; #ifdef MEMPHIS // // We won't worry about a failure in converting the registry path // since currently the registry path is only used for ACL checking // and there are not ACLs on memphis so who cares. If we ever // start using the registry path for anything else then we will // need to start worrying about a failure here. DataSource->RegistryPath = NULL; UnicodeToAnsi(RegistryPathTemp, &DataSource->RegistryPath, NULL); WmipFree(RegistryPathTemp); #else DataSource->RegistryPath = RegistryPathTemp; #endif } else { WmipDebugPrint(("WMI: Invalid or missing registry path passed %x\n", RegistryPath)); DataSource->RegistryPath = NULL; } WmipEnterSMCritSection(); Status = WmipLinkDataSourceToList(DataSource, TRUE); WmipLeaveSMCritSection(); if (Status != ERROR_SUCCESS) { WmipUnreferenceDS(DataSource); } } else { WmipEnterSMCritSection(); Status = WmipLinkDataSourceToList(DataSource, FALSE); WmipLeaveSMCritSection(); if (Status != ERROR_SUCCESS) { WmipUnreferenceDS(DataSource); } } if (Status != ERROR_SUCCESS) { // For some reason we could not link the data source and guids to // their lists. Note that WmipLinkDataSourceToList had already // freed the could have been DataSource. return(Status); } if (BinaryMofInstanceSet != NULL) { WmipGenerateBinaryMofNotification(BinaryMofInstanceSet, &GUID_MOF_RESOURCE_ADDED_NOTIFICATION); } MofResourceNamePtr = (LPWSTR)OffsetToPtr(RegistrationInfo, (RegistrationInfo->MofResourceName)); MofResourceNameLen = *MofResourceNamePtr++; if ((MofImagePath != NULL) && (RegistrationInfo->MofResourceName != 0) && (MofResourceNameLen != 0)) { MofResourceName = WmipAlloc(MofResourceNameLen + sizeof(WCHAR)); if (MofResourceName != NULL) { MofResourceNameLen /= sizeof(WCHAR); wcsncpy(MofResourceName, MofResourceNamePtr, MofResourceNameLen); MofResourceName[MofResourceNameLen] = UNICODE_NULL; #ifdef MEMPHIS MofImagePathUnicode = NULL; if (AnsiToUnicode(MofImagePath, &MofImagePathUnicode) == ERROR_SUCCESS) { #else MofImagePathUnicode = (LPWSTR)MofImagePath; #endif Status = WmipBuildMofClassInfo( DataSource, MofImagePathUnicode, MofResourceName, &NewMofResource); if ((Status == ERROR_SUCCESS) && NewMofResource) { WmipGenerateMofResourceNotification(MofImagePathUnicode, MofResourceName, &GUID_MOF_RESOURCE_ADDED_NOTIFICATION); } #ifdef MEMPHIS WmipFree(MofImagePathUnicode); } #endif WmipFree(MofResourceName); } else { WmipDebugPrint(("WMI: WmipAddDataSource: Couldn't alloc for MofResourcedbName\n")); } } // // Send a notification about new/changed guids Wnode = WmipGenerateRegistrationNotification(DataSource, (PWNODE_HEADER)WnodeBuffer, AVGGUIDSPERDS, RegistrationAdd); // // First fire the internal registration change notification and then for // any data consumers who are interested WmipEventNotification(Wnode, TRUE, Wnode->BufferSize); memcpy(&Wnode->Guid, &GUID_REGISTRATION_CHANGE_NOTIFICATION, sizeof(GUID)); Wnode->Flags &= ~WNODE_FLAG_INTERNAL; WmipEventNotification(Wnode, TRUE, Wnode->BufferSize); if (Wnode != (PWNODE_HEADER)WnodeBuffer) { WmipFree(Wnode); } #ifdef HEAPVALIDATION WmipAssert(RtlValidateProcessHeaps()); #endif return(ERROR_SUCCESS); } ULONG WmipBuildInstanceSet( PWMIREGGUID RegGuid, PWMIREGINFOW RegistrationInfo, PBINSTANCESET InstanceSet, LPCTSTR MofImagePath ) { PWCHAR InstanceName, InstanceNamePtr; PBISBASENAME IsBaseName; PBISSTATICNAMES IsStaticName; ULONG SizeNeeded; ULONG SuffixSize; PWCHAR StaticNames; ULONG Len; ULONG InstanceCount; ULONG j; ULONG MaxStaticInstanceNameSize; PWCHAR StaticInstanceNameBuffer; InstanceCount = RegGuid->InstanceCount; InstanceSet->Count = InstanceCount; // // Reset any flags that might be changed by a new REGGUID InstanceSet->Flags &= ~(IS_EXPENSIVE | IS_EVENT_ONLY | IS_PDO_INSTANCENAME | IS_INSTANCE_STATICNAMES | IS_INSTANCE_BASENAME); // // Finish initializing the Instance Set if (RegGuid->Flags & WMIREG_FLAG_EXPENSIVE) { InstanceSet->Flags |= IS_EXPENSIVE; } if (RegGuid->Flags & WMIREG_FLAG_TRACED_GUID) { // // This guid is not queryable, but is used for sending trace // events. We mark the InstanceSet as special InstanceSet->Flags |= IS_TRACED; if (RegGuid->Flags & WMIREG_FLAG_TRACE_CONTROL_GUID) { InstanceSet->Flags |= IS_CONTROL_GUID; } } if (RegGuid->Flags & WMIREG_FLAG_EVENT_ONLY_GUID) { // // This guid is not queryable, but is only used for sending // events. We mark the InstanceSet as special InstanceSet->Flags |= IS_EVENT_ONLY; } InstanceName = (LPWSTR)OffsetToPtr(RegistrationInfo, RegGuid->BaseNameOffset); if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_LIST) { // // We have static list of instance names that might need mangling // We assume that any name mangling that must occur can be // done with a suffix of 5 or fewer characters. This allows // up to 100,000 identical static instance names within the // same guid. SizeNeeded = FIELD_OFFSET(ISSTATICENAMES, StaticNamePtr); SuffixSize = MAXBASENAMESUFFIXSIZE; InstanceNamePtr = InstanceName; MaxStaticInstanceNameSize = 0; for (j = 0; j < InstanceCount; j++) { if (! WmipValidateCountedString(InstanceNamePtr)) { WmipDebugPrint(("WMI: WmipAddDataSource: bad static instance name %x\n", InstanceNamePtr)); WmipReportEventLog(EVENT_WMI_INVALID_REGINFO, EVENTLOG_WARNING_TYPE, 0, RegistrationInfo->BufferSize, RegistrationInfo, 1, MofImagePath ? MofImagePath : TEXT("Unknown")); return(ERROR_WMI_INVALID_REGINFO); } if (*InstanceNamePtr > MaxStaticInstanceNameSize) { MaxStaticInstanceNameSize = *InstanceNamePtr; } SizeNeeded += *InstanceNamePtr + 1 + SuffixSize + (sizeof(PWCHAR) / sizeof(WCHAR)); InstanceNamePtr += (*((USHORT *)InstanceNamePtr) + 2) / sizeof(WCHAR); } IsStaticName = (PBISSTATICNAMES)WmipAllocString(SizeNeeded); if (IsStaticName == NULL) { WmipDebugPrint(("WMI: WmipAddDataSource: alloc static instance names\n")); return(ERROR_NOT_ENOUGH_MEMORY); } InstanceSet->Flags |= IS_INSTANCE_STATICNAMES; InstanceSet->IsStaticNames = IsStaticName; StaticNames = (PWCHAR) ((PBYTE)IsStaticName + (InstanceCount * sizeof(PWCHAR))); InstanceNamePtr = InstanceName; StaticInstanceNameBuffer = WmipAlloc(MaxStaticInstanceNameSize + sizeof(WCHAR)); if (StaticInstanceNameBuffer == NULL) { WmipDebugPrint(("WMI: WmipAddDataSource: couldn't alloc StaticInstanceNameBuffer\n")); return(ERROR_NOT_ENOUGH_MEMORY); } for (j = 0; j < InstanceCount; j++) { IsStaticName->StaticNamePtr[j] = StaticNames; memcpy(StaticInstanceNameBuffer, InstanceNamePtr+1, *InstanceNamePtr); StaticInstanceNameBuffer[*InstanceNamePtr/sizeof(WCHAR)] = UNICODE_NULL; Len = WmipMangleInstanceName(&RegGuid->Guid, StaticInstanceNameBuffer, *InstanceNamePtr + SuffixSize + 1, StaticNames); StaticNames += Len; InstanceNamePtr += (*((USHORT *)InstanceNamePtr) + 2)/sizeof(WCHAR); } WmipFree(StaticInstanceNameBuffer); } else if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_BASENAME) { // // We have static instance names built from a base name if (! WmipValidateCountedString(InstanceName)) { WmipDebugPrint(("WMI: WmipAddDataSource: Invalid instance base name %x\n", InstanceName)); WmipReportEventLog(EVENT_WMI_INVALID_REGINFO, EVENTLOG_WARNING_TYPE, 0, RegistrationInfo->BufferSize, RegistrationInfo, 1, MofImagePath ? MofImagePath : TEXT("Unknown")); return(ERROR_WMI_INVALID_REGINFO); } InstanceSet->Flags |= IS_INSTANCE_BASENAME; if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_PDO) { InstanceSet->Flags |= IS_PDO_INSTANCENAME; } IsBaseName = (PBISBASENAME)WmipAlloc(*InstanceName + sizeof(WCHAR) + FIELD_OFFSET(ISBASENAME, BaseName)); if (IsBaseName == NULL) { WmipDebugPrint(("WMI: WmipAddDataSource: alloc ISBASENAME failed\n")); return(ERROR_NOT_ENOUGH_MEMORY); } InstanceSet->IsBaseName = IsBaseName; memcpy(IsBaseName->BaseName, InstanceName+1, *InstanceName); IsBaseName->BaseName[*InstanceName/sizeof(WCHAR)] = UNICODE_NULL; IsBaseName->BaseIndex = WmipDetermineInstanceBaseIndex( &RegGuid->Guid, IsBaseName->BaseName, RegGuid->InstanceCount); } return(ERROR_SUCCESS); } ULONG WmipLinkDataSourceToList( PBDATASOURCE DataSource, BOOLEAN AddDSToList ) /*++ Routine Description: This routine will take a DataSource that was just registered or updated and link any new InstanceSets to an appropriate GuidEntry. Then if the AddDSToList is TRUE the DataSource itself will be added to the main data source list. This routine will do all of the linkages within a critical section so the data source and its new instances are added atomically. The routine will also determine if the guid entry associated with a InstanceSet is a duplicate of another that is already on the main guid entry list and if so will use the preexisting guid entry. This routine assumes that the SM critical section has been taken Arguments: DataSource is a based pointer to a DataSource structure AddDSToList is TRUE then data source will be added to the main list of data sources Return Value: ERROR_SUCCESS or an error code --*/ { PBINSTANCESET InstanceSet; PLIST_ENTRY InstanceSetList; PBGUIDENTRY GuidEntry; InstanceSetList = DataSource->ISHead.Flink; while (InstanceSetList != &DataSource->ISHead) { InstanceSet = CONTAINING_RECORD(InstanceSetList, INSTANCESET, DSISList); // // If this instance set has just been registered then we need to // get it on a GuidEntry list. if (InstanceSet->Flags & IS_NEWLY_REGISTERED) { // // See if there is already a GUID entry for the instance set. // If not go allocate a new guid entry and place it on the // main guid list. If there already is a GuidEntry for the // InstanceSet we will assign the ref count that was given by // the WmipFindGEByGuid to the DataSource which will unreference // the GuidEntry when the DataSource is unregistered. GuidEntry = WmipFindGEByGuid((LPGUID)InstanceSet->GuidEntry, FALSE); if (GuidEntry == NULL) { GuidEntry = WmipAllocGuidEntry(); if (GuidEntry == NULL) { WmipDebugPrint(("WMI: WmipLinkDataSourceToList: WmipAllocGuidEntry failed\n")); return(ERROR_NOT_ENOUGH_MEMORY); } // // Initialize the new GuidEntry and place it on the master // GuidEntry list. memcpy(&GuidEntry->Guid, (LPGUID)InstanceSet->GuidEntry, sizeof(GUID)); InsertHeadList(GEHeadPtr, &GuidEntry->MainGEList); } InstanceSet->GuidEntry = GuidEntry; InstanceSet->Flags &= ~IS_NEWLY_REGISTERED; InsertTailList(&GuidEntry->ISHead, &InstanceSet->GuidISList); GuidEntry->ISCount++; } InstanceSetList = InstanceSetList->Flink; } if (AddDSToList) { WmipAssert(! (DataSource->Flags & FLAG_ENTRY_ON_INUSE_LIST)); DataSource->Flags |= FLAG_ENTRY_ON_INUSE_LIST; InsertTailList(DSHeadPtr, &DataSource->MainDSList); } return(ERROR_SUCCESS); } ULONG WmipDetermineInstanceBaseIndex( LPGUID Guid, PWCHAR BaseName, ULONG InstanceCount ) /*++ Routine Description: Figure out the base index for the instance names specified by a base instance name. We walk the list of instances sets for the guid and if there is a match in the base instance name we set the base instance index above that used by the previously registered instance set. Arguments: Guid points at guid for the instance names BaseName points at the base name for the instances InstanceCount is the count of instance names Return Value: Base index for instance name --*/ { PBGUIDENTRY GuidEntry; ULONG BaseIndex = 0; PLIST_ENTRY InstanceSetList; PBINSTANCESET InstanceSet; ULONG LastBaseIndex; GuidEntry = WmipFindGEByGuid(Guid, FALSE); if (GuidEntry != NULL) { InstanceSetList = GuidEntry->ISHead.Flink; while (InstanceSetList != &GuidEntry->ISHead) { InstanceSet = CONTAINING_RECORD(InstanceSetList, INSTANCESET, GuidISList); if (InstanceSet->Flags & IS_INSTANCE_BASENAME) { if (wcscmp(BaseName, InstanceSet->IsBaseName->BaseName) == 0) { LastBaseIndex = InstanceSet->IsBaseName->BaseIndex + InstanceSet->Count; if (BaseIndex <= LastBaseIndex) { BaseIndex = LastBaseIndex; } } } InstanceSetList = InstanceSetList->Flink; } WmipUnreferenceGE(GuidEntry); } WmipDebugPrint(("WMI: Static instance name %ws has base index %x\n", BaseName, BaseIndex)); return(BaseIndex); } ULONG WmipMangleInstanceName( LPGUID Guid, PWCHAR Name, ULONG MaxMangledNameLen, PWCHAR MangledName ) /*++ Routine Description: Copies a static instance name from the input buffer to the output buffer, mangling it if the name collides with another name for the same guid. Arguments: Guid points at guid for the instance name Name points at the proposed instance name MaxMangledNameLen has the maximum number of chars in mangled name buffer MangledName points at buffer to return mangled name Return Value: Actual length of mangled name --*/ { PBGUIDENTRY GuidEntry; WCHAR ManglingChar; ULONG ManglePos; ULONG InstanceIndex; PBINSTANCESET InstanceSet; WmipAssert(MaxMangledNameLen >= wcslen(Name)); wcsncpy(MangledName, Name, MaxMangledNameLen); GuidEntry = WmipFindGEByGuid(Guid, FALSE); if (GuidEntry != NULL) { ManglePos = wcslen(MangledName)-1; ManglingChar = L'Z'; // // Loop until we get a unique name InstanceSet = WmipFindISinGEbyName(GuidEntry, MangledName, &InstanceIndex); while (InstanceSet != NULL) { WmipUnreferenceIS(InstanceSet); WmipDebugPrint(("WMI: Need to mangle name %ws\n", MangledName)); if (ManglingChar == L'Z') { ManglingChar = L'A'; if (ManglePos++ == MaxMangledNameLen) { WmipDebugPrint(("WMI: Instance Name could not be mangled\n")); break; } MangledName[ManglePos+1] = UNICODE_NULL; } else { ManglingChar++; } MangledName[ManglePos] = ManglingChar; InstanceSet = WmipFindISinGEbyName(GuidEntry, MangledName, &InstanceIndex) ; } WmipUnreferenceGE(GuidEntry); } return(wcslen(MangledName)+1); } void WmipEnableCollectionForNewGuid( LPGUID Guid, PBINSTANCESET InstanceSet ) { WNODE_HEADER Wnode; PNOTIFICATIONENTRY NotificationEntry; PBGUIDENTRY GuidEntry; ULONG Status; BOOLEAN IsTraceLog; GuidEntry = WmipFindGEByGuid(Guid, FALSE); memset(&Wnode, 0, sizeof(WNODE_HEADER)); memcpy(&Wnode.Guid, Guid, sizeof(GUID)); Wnode.BufferSize = sizeof(WNODE_HEADER); WmipEnterSMCritSection(); NotificationEntry = WmipFindNEByGuid(Guid, FALSE); if (NotificationEntry != NULL) { if ((NotificationEntry->EventRefCount > 0) && ((InstanceSet->Flags & IS_ENABLE_EVENT) == 0)) { // Events were previously enabled for this guid, but not for this // instance set so call data source for instance set to enable // the events. First set the in progress flag and InstanceSet // set flag to denote that events have been enabled for the // instance set. InstanceSet->Flags |= IS_ENABLE_EVENT; // // If it is Tracelog, NewGuid notifications are piggybacked with // Registration call return. // IsTraceLog = ((InstanceSet->Flags & IS_TRACED) == IS_TRACED); if (IsTraceLog) { if (!(InstanceSet->DataSource->Flags & DS_KERNEL_MODE) ) { if (GuidEntry != NULL) { WmipUnreferenceGE(GuidEntry); } WmipUnreferenceNE(NotificationEntry); WmipLeaveSMCritSection(); return; } // // For the Kernel Mode Trace Providers pass on the context // Wnode.HistoricalContext = NotificationEntry->LoggerContext; } NotificationEntry->Flags |= NE_FLAG_NOTIFICATION_IN_PROGRESS; WmipLeaveSMCritSection(); WmipDeliverWnodeToDS(WMI_ENABLE_EVENTS, InstanceSet->DataSource, &Wnode); WmipEnterSMCritSection(); // // Now we need to check if events were disabled while the enable // request was in progress. If so go do the work to actually // disable them. if (NotificationEntry->EventRefCount == 0) { Status = WmipDoDisableRequest(NotificationEntry, GuidEntry, TRUE, IsTraceLog, NotificationEntry->LoggerContext, NE_FLAG_NOTIFICATION_IN_PROGRESS); } else { NotificationEntry->Flags &= ~NE_FLAG_NOTIFICATION_IN_PROGRESS; } } // // Now check to see if collection needs to be enabled for this guid if ((NotificationEntry->CollectRefCount > 0) && ((InstanceSet->Flags & IS_ENABLE_COLLECTION) == 0) && (InstanceSet->Flags & IS_EXPENSIVE) ) { // Collection was previously enabled for this guid, but not // for this instance set so call data source for instance set // to enable collection. First set the in progress flag and // InstanceSet set flag to denote that collection has been enabled // for the instance set. NotificationEntry->Flags |= NE_FLAG_COLLECTION_IN_PROGRESS; InstanceSet->Flags |= IS_ENABLE_COLLECTION; WmipLeaveSMCritSection(); WmipDeliverWnodeToDS(WMI_ENABLE_COLLECTION, InstanceSet->DataSource, &Wnode); WmipEnterSMCritSection(); // // Now we need to check if events were disabled while the enable // request was in progress. If so go do the work to actually // disable them. if (NotificationEntry->CollectRefCount == 0) { Status = WmipDoDisableRequest(NotificationEntry, GuidEntry, FALSE, FALSE, 0, NE_FLAG_COLLECTION_IN_PROGRESS); } else { NotificationEntry->Flags &= ~NE_FLAG_COLLECTION_IN_PROGRESS; // // If there are any other threads that were waiting // until all of the enable/disable work completed, we // close the event handle to release them from their wait. // if (NotificationEntry->CollectInProgress != NULL) { WmipReleaseCollectionEnabled(NotificationEntry); } } } // // Guid is already enabled so we need to enable this new one WmipUnreferenceNE(NotificationEntry); } WmipLeaveSMCritSection(); if (GuidEntry != NULL) { WmipUnreferenceGE(GuidEntry); } } void WmipDisableCollectionForRemovedGuid( LPGUID Guid, PBINSTANCESET InstanceSet ) { WNODE_HEADER Wnode; PNOTIFICATIONENTRY NotificationEntry; PBGUIDENTRY GuidEntry; ULONG Status; BOOLEAN IsTraceLog; GuidEntry = WmipFindGEByGuid(Guid, FALSE); memset(&Wnode, 0, sizeof(WNODE_HEADER)); memcpy(&Wnode.Guid, Guid, sizeof(GUID)); Wnode.BufferSize = sizeof(WNODE_HEADER); WmipEnterSMCritSection(); NotificationEntry = WmipFindNEByGuid(Guid, FALSE); if (NotificationEntry != NULL) { if ((NotificationEntry->EventRefCount > 0) && ((InstanceSet->Flags & IS_ENABLE_EVENT) != 0)) { // Events were previously enabled for this guid, but not for this // instance set so call data source for instance set to enable // the events. First set the in progress flag and InstanceSet // set flag to denote that events have been enabled for the // instance set. InstanceSet->Flags &= ~IS_ENABLE_EVENT; // // If it is Tracelog, RemoveGuid notifications are handled // through UnregisterGuids call. // IsTraceLog = ((InstanceSet->Flags & IS_TRACED) == IS_TRACED); if (IsTraceLog) { if ( !(InstanceSet->DataSource->Flags & DS_KERNEL_MODE)) { if (GuidEntry != NULL) { WmipUnreferenceGE(GuidEntry); } WmipUnreferenceNE(NotificationEntry); WmipLeaveSMCritSection(); return; } Wnode.HistoricalContext = NotificationEntry->LoggerContext; } NotificationEntry->Flags |= NE_FLAG_NOTIFICATION_IN_PROGRESS; WmipLeaveSMCritSection(); WmipDeliverWnodeToDS(WMI_DISABLE_EVENTS, InstanceSet->DataSource, &Wnode); WmipEnterSMCritSection(); // // Now we need to check if events were disabled while the enable // request was in progress. If so go do the work to actually // disable them. if (NotificationEntry->EventRefCount == 0) { Status = WmipDoDisableRequest(NotificationEntry, GuidEntry, TRUE, IsTraceLog, NotificationEntry->LoggerContext, NE_FLAG_NOTIFICATION_IN_PROGRESS); } else { NotificationEntry->Flags &= ~NE_FLAG_NOTIFICATION_IN_PROGRESS; } } // // Now check to see if collection needs to be enabled for this guid if ((NotificationEntry->CollectRefCount > 0) && ((InstanceSet->Flags & IS_ENABLE_COLLECTION) != 0)) { // Collection was previously enabled for this guid, but not // for this instance set so call data source for instance set // to enable collection. First set the in progress flag and // InstanceSet set flag to denote that collection has been enabled // for the instance set. NotificationEntry->Flags |= NE_FLAG_COLLECTION_IN_PROGRESS; InstanceSet->Flags &= ~IS_ENABLE_COLLECTION; WmipLeaveSMCritSection(); WmipDeliverWnodeToDS(WMI_DISABLE_COLLECTION, InstanceSet->DataSource, &Wnode); WmipEnterSMCritSection(); // // Now we need to check if events were disabled while the enable // request was in progress. If so go do the work to actually // disable them. if (NotificationEntry->CollectRefCount == 0) { Status = WmipDoDisableRequest(NotificationEntry, GuidEntry, FALSE, FALSE, 0, NE_FLAG_COLLECTION_IN_PROGRESS); } else { NotificationEntry->Flags &= ~NE_FLAG_COLLECTION_IN_PROGRESS; // // If there are any other threads that were waiting // until all of the enable/disable work completed, we // close the event handle to release them from their wait. // if (NotificationEntry->CollectInProgress != NULL) { WmipReleaseCollectionEnabled(NotificationEntry); } } } // // Guid is already enabled so we need to enable this new one WmipUnreferenceNE(NotificationEntry); } WmipLeaveSMCritSection(); if (GuidEntry != NULL) { WmipUnreferenceGE(GuidEntry); } } PWNODE_HEADER WmipGenerateRegistrationNotification( PBDATASOURCE DataSource, PWNODE_HEADER WnodeBuffer, ULONG GuidMax, ULONG NotificationCode ) { PWNODE_HEADER Wnode2; LPGUID GuidPtr; ULONG GuidCount; PLIST_ENTRY InstanceSetList; PBINSTANCESET InstanceSet; PWNODE_HEADER Wnode = WnodeBuffer; LPGUID Guid; // // Build notification containing all guids that are going to being // removed. We build it now and then send it after the data source // is removed. WmipReferenceDS(DataSource); GuidCount = 0; GuidPtr = (LPGUID)((PBYTE)Wnode + sizeof(WNODE_HEADER)); InstanceSetList = DataSource->ISHead.Flink; while (InstanceSetList != &DataSource->ISHead) { if (GuidCount == GuidMax) { GuidMax = GuidMax + AVGGUIDSPERDS; Wnode2 = WmipAlloc(sizeof(WNODE_HEADER) + GuidMax * sizeof(GUID)); if (Wnode2 == NULL) { WmipDebugPrint(("WMI: GenerateRegistrationNotification couldn't alloc extra guids\n")); break; } memcpy(Wnode2, Wnode, sizeof(WNODE_HEADER) + GuidCount * sizeof(GUID)); if (Wnode != WnodeBuffer) { WmipFree(Wnode); } Wnode = Wnode2; GuidPtr = (LPGUID)((PBYTE)Wnode + sizeof(WNODE_HEADER)); GuidPtr += GuidCount; } InstanceSet = CONTAINING_RECORD(InstanceSetList, INSTANCESET, DSISList); Guid = &InstanceSet->GuidEntry->Guid; *GuidPtr++ = *Guid; if (NotificationCode == RegistrationAdd) { WmipEnableCollectionForNewGuid(Guid, InstanceSet); } else if (NotificationCode == RegistrationDelete) { WmipDisableCollectionForRemovedGuid(Guid, InstanceSet); } // // If this is a Trace Provider, then add the Unregistering Guids // to the GuidMapList if a logger session is active. // If there is a notification entry for this Guid, then we take // it that there is a logger session active. // if ( (NotificationCode == RegistrationDelete) && (InstanceSet->Flags & IS_TRACED) ) { WmipSaveTraceGuidMap(Guid, InstanceSet); } InstanceSetList = InstanceSetList->Flink; GuidCount++; } WmipUnreferenceDS(DataSource); WmipBuildRegistrationNotification(Wnode, sizeof(WNODE_HEADER) + GuidCount * sizeof(GUID), NotificationCode, GuidCount); return(Wnode); } void WmipRemoveDataSource( ULONG_PTR ProviderId ) { PBDATASOURCE DataSource; DataSource = WmipFindDSByProviderId(ProviderId); if (DataSource != NULL) { WmipRemoveDataSourceByDS(DataSource); WmipUnreferenceDS(DataSource); } else { WmipDebugPrint(("WMI: Attempt to remove non existant data source %x\n", ProviderId)); } } void WmipRemoveDataSourceByDS( PBDATASOURCE DataSource ) { BYTE WnodeBuffer[sizeof(WNODE_HEADER) + AVGGUIDSPERDS * sizeof(GUID)]; PWNODE_HEADER Wnode; PLIST_ENTRY MofResourceList; #ifdef WMI_USER_MODE PLIST_ENTRY MofClassList; PMOFCLASS MofClass; #endif PMOFRESOURCE MofResource; Wnode = WmipGenerateRegistrationNotification(DataSource, (PWNODE_HEADER)WnodeBuffer, AVGGUIDSPERDS, RegistrationDelete); WmipUnreferenceDS(DataSource); WmipEventNotification(Wnode, TRUE, Wnode->BufferSize); memcpy(&Wnode->Guid, &GUID_REGISTRATION_CHANGE_NOTIFICATION, sizeof(GUID)); Wnode->Flags &= ~WNODE_FLAG_INTERNAL; WmipEventNotification(Wnode, TRUE, Wnode->BufferSize); if (Wnode != (PWNODE_HEADER)WnodeBuffer) { WmipFree(Wnode); } } void WmipGenerateBinaryMofNotification( PBINSTANCESET BinaryMofInstanceSet, LPCGUID Guid ) { PWNODE_SINGLE_INSTANCE Wnode; ULONG ImagePathLen, ResourceNameLen, InstanceNameLen, BufferSize; PWCHAR Ptr; ULONG i; if (BinaryMofInstanceSet->Count == 0) { return; } for (i = 0; i < BinaryMofInstanceSet->Count; i++) { ImagePathLen = sizeof(USHORT); InstanceNameLen = (sizeof(USHORT) + 7) & ~7; if (BinaryMofInstanceSet->Flags & IS_INSTANCE_STATICNAMES) { ResourceNameLen = ((wcslen(BinaryMofInstanceSet->IsStaticNames->StaticNamePtr[i])+1) * sizeof(WCHAR)) + sizeof(USHORT); } else if (BinaryMofInstanceSet->Flags & IS_INSTANCE_BASENAME) { ResourceNameLen = (((wcslen(BinaryMofInstanceSet->IsBaseName->BaseName) + MAXBASENAMESUFFIXSIZE) * sizeof(WCHAR)) + sizeof(USHORT)); } else { return; } BufferSize = FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData) + InstanceNameLen + ImagePathLen + ResourceNameLen; Wnode = (PWNODE_SINGLE_INSTANCE)WmipAlloc(BufferSize); if (Wnode != NULL) { Wnode->WnodeHeader.BufferSize = BufferSize; Wnode->WnodeHeader.ProviderId = 0; Wnode->WnodeHeader.Version = 1; Wnode->WnodeHeader.Linkage = 0; Wnode->WnodeHeader.Flags = (WNODE_FLAG_EVENT_ITEM | WNODE_FLAG_SINGLE_INSTANCE); memcpy(&Wnode->WnodeHeader.Guid, Guid, sizeof(GUID)); WmiInsertTimestamp(&Wnode->WnodeHeader); Wnode->OffsetInstanceName = FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData); Wnode->DataBlockOffset = Wnode->OffsetInstanceName + InstanceNameLen; Wnode->SizeDataBlock = ImagePathLen + ResourceNameLen; Ptr = (PWCHAR)&Wnode->VariableData; *Ptr++ = 0; // Empty instance name Ptr = (PWCHAR)OffsetToPtr(Wnode, Wnode->DataBlockOffset); *Ptr++ = 0; // Empty image path // Instance name for binary mof resource if (BinaryMofInstanceSet->Flags & IS_INSTANCE_STATICNAMES) { *Ptr++ = (USHORT)(ResourceNameLen - sizeof(USHORT)); wcscpy(Ptr, BinaryMofInstanceSet->IsStaticNames->StaticNamePtr[i]); } else if (BinaryMofInstanceSet->Flags & IS_INSTANCE_BASENAME) { #ifdef MEMPHIS *Ptr = swprintf(Ptr+1, L"%ws%d", BinaryMofInstanceSet->IsBaseName->BaseName, BinaryMofInstanceSet->IsBaseName->BaseIndex+i) * sizeof(WCHAR); #else *Ptr = (USHORT)wsprintfW(Ptr+1, L"%ws%d", BinaryMofInstanceSet->IsBaseName->BaseName, BinaryMofInstanceSet->IsBaseName->BaseIndex+i) * sizeof(WCHAR); #endif } WmipEventNotification((PWNODE_HEADER)Wnode, TRUE, ((PWNODE_HEADER)Wnode)->BufferSize); WmipFree(Wnode); } } } void WmipGenerateMofResourceNotification( LPWSTR ImagePath, LPWSTR ResourceName, LPCGUID Guid ) { PWNODE_SINGLE_INSTANCE Wnode; ULONG ImagePathLen, ResourceNameLen, InstanceNameLen, BufferSize; PWCHAR Ptr; ImagePathLen = (wcslen(ImagePath) + 2) * sizeof(WCHAR); ResourceNameLen = (wcslen(ResourceName) + 2) * sizeof(WCHAR); InstanceNameLen = ( sizeof(USHORT)+7 ) & ~7; BufferSize = FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData) + InstanceNameLen + ImagePathLen + ResourceNameLen; Wnode = (PWNODE_SINGLE_INSTANCE)WmipAlloc(BufferSize); if (Wnode != NULL) { Wnode->WnodeHeader.BufferSize = BufferSize; Wnode->WnodeHeader.ProviderId = 0; Wnode->WnodeHeader.Version = 1; Wnode->WnodeHeader.Linkage = 0; Wnode->WnodeHeader.Flags = (WNODE_FLAG_EVENT_ITEM | WNODE_FLAG_SINGLE_INSTANCE); memcpy(&Wnode->WnodeHeader.Guid, Guid, sizeof(GUID)); WmiInsertTimestamp(&Wnode->WnodeHeader); Wnode->OffsetInstanceName = FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData); Wnode->DataBlockOffset = Wnode->OffsetInstanceName + InstanceNameLen; Wnode->SizeDataBlock = ImagePathLen + ResourceNameLen; Ptr = (PWCHAR)&Wnode->VariableData; *Ptr = 0; // Empty instance name // ImagePath name Ptr = (PWCHAR)OffsetToPtr(Wnode, Wnode->DataBlockOffset); ImagePathLen -= sizeof(USHORT); *Ptr++ = (USHORT)ImagePathLen; memcpy(Ptr, ImagePath, ImagePathLen); Ptr += (ImagePathLen / sizeof(WCHAR)); // MofResource Name ResourceNameLen -= sizeof(USHORT); *Ptr++ = (USHORT)ResourceNameLen; memcpy(Ptr, ResourceName, ResourceNameLen); WmipEventNotification((PWNODE_HEADER)Wnode, TRUE, ((PWNODE_HEADER)Wnode)->BufferSize); WmipFree(Wnode); } } void WmipSendGuidUpdateNotifications( NOTIFICATIONTYPES NotificationType, ULONG GuidCount, PTRCACHE *GuidList ) { PBYTE WnodeBuffer; PWNODE_HEADER Wnode; ULONG WnodeSize; LPGUID WnodeGuidPtr; ULONG i; WnodeSize = sizeof(WNODE_HEADER) + GuidCount*sizeof(GUID); WnodeBuffer = WmipAlloc(WnodeSize); if (WnodeBuffer != NULL) { Wnode = (PWNODE_HEADER)WnodeBuffer; WmipBuildRegistrationNotification(Wnode, WnodeSize, NotificationType, GuidCount); WnodeGuidPtr = (LPGUID)(WnodeBuffer + sizeof(WNODE_HEADER)); for (i = 0; i < GuidCount; i++) { *WnodeGuidPtr++ = *GuidList[i].Guid; } WmipEventNotification(Wnode, TRUE, Wnode->BufferSize); memcpy(&Wnode->Guid, &GUID_REGISTRATION_CHANGE_NOTIFICATION, sizeof(GUID)); Wnode->Flags &= ~WNODE_FLAG_INTERNAL; WmipEventNotification(Wnode, TRUE, Wnode->BufferSize); WmipFree(WnodeBuffer); } } PBINSTANCESET WmipFindISInDSByGuid( PBDATASOURCE DataSource, LPGUID Guid ) /*++ Routine Description: This routine will find the InstanceSet in the passed DataSource for the guid passed. This routine assumes that the SM critical section is held before it is called. Arguments: DataSource is the data source from which the guid is to be removed Guid has the Guid for the InstanceSet to find Return Value: --*/ { PLIST_ENTRY InstanceSetList; PBINSTANCESET InstanceSet; InstanceSetList = DataSource->ISHead.Flink; while (InstanceSetList != &DataSource->ISHead) { InstanceSet = CONTAINING_RECORD(InstanceSetList, INSTANCESET, DSISList); if ((InstanceSet->GuidEntry != NULL) && (IsEqualGUID(Guid, &InstanceSet->GuidEntry->Guid))) { WmipReferenceIS(InstanceSet); return(InstanceSet); } InstanceSetList = InstanceSetList->Flink; } return(NULL); } ULONG WmipUpdateAddGuid( PBDATASOURCE DataSource, PWMIREGGUID RegGuid, PWMIREGINFO RegistrationInfo, PBINSTANCESET *AddModInstanceSet ) /*++ Routine Description: This routine will add a new guid for the data source and send notification This routine assumes that the SM critical section is held before it is called. Arguments: DataSource is the data source from which the guid is to be removed RegGuid has the Guid update data structure RegistrationInfo points at the beginning of the registration update info Return Value: 1 if guid was added or 0 --*/ { PBINSTANCESET InstanceSet; LPGUID Guid = &RegGuid->Guid; ULONG Status; // // Allocate an instance set for this new set of instances InstanceSet = WmipAllocInstanceSet(); if (InstanceSet == NULL) { WmipDebugPrint(("WMI: WmipUpdateAddGuid: WmipAllocInstanceSet failed\n")); return(0); } // // We will allocate a proper guid entry for the instance set when // the data source gets linked into the main data source list so // we stash a pointer to the guid away now. InstanceSet->GuidEntry = (PBGUIDENTRY)Guid; // // Minimally initialize the InstanceSet and add it to the DataSource's // list of InstanceSets. We do this first so that if there is any // failure below and the DataSource can'e be fully registered the // instance set and guid entry will be free when the DataSource is // freed. InstanceSet->DataSource = DataSource; InstanceSet->Flags |= IS_NEWLY_REGISTERED; InsertHeadList(&DataSource->ISHead, &InstanceSet->DSISList); Status = WmipBuildInstanceSet(RegGuid, RegistrationInfo, InstanceSet, DataSource->RegistryPath); if (Status != ERROR_SUCCESS) { WmipUnreferenceIS(InstanceSet); return(0); } Status = WmipLinkDataSourceToList(DataSource, FALSE); *AddModInstanceSet = InstanceSet; return( (Status == ERROR_SUCCESS) ? 1 : 0); } BOOLEAN WmipUpdateRemoveGuid( PBDATASOURCE DataSource, PWMIREGGUID RegGuid, PBINSTANCESET *AddModInstanceSet ) /*++ Routine Description: This routine will remove the guid for the data source and send notification This routine assumes that the SM critical section is held before it is called. Arguments: DataSource is the data source from which the guid is to be removed RegGuid has the Guid update data structure Return Value: TRUE if guid was removed else FALSE --*/ { PBINSTANCESET InstanceSet; LPGUID Guid = &RegGuid->Guid; BOOLEAN SendNotification; InstanceSet = WmipFindISInDSByGuid(DataSource, Guid); if (InstanceSet != NULL) { WmipUnreferenceIS(InstanceSet); *AddModInstanceSet = InstanceSet; SendNotification = TRUE; } else { #if DBG TCHAR s[256]; WmipDebugPrint(("WMI: UpdateRemoveGuid %ws not registered by %ws\n", GuidToString(s, Guid), DataSource->RegistryPath)); #endif SendNotification = FALSE; } return(SendNotification); } BOOLEAN WmipIsEqualInstanceSets( PBINSTANCESET InstanceSet1, PBINSTANCESET InstanceSet2 ) { ULONG i; ULONG Flags1, Flags2; Flags1 = InstanceSet1->Flags & ~(IS_ENABLE_EVENT | IS_ENABLE_COLLECTION); Flags2 = InstanceSet2->Flags & ~(IS_ENABLE_EVENT | IS_ENABLE_COLLECTION); if (Flags1 == Flags2) { if (InstanceSet1->Flags & IS_INSTANCE_BASENAME) { if ((InstanceSet1->Count == InstanceSet2->Count) && (wcscmp(InstanceSet1->IsBaseName->BaseName, InstanceSet1->IsBaseName->BaseName) == 0)) { return(TRUE); } } else if (InstanceSet1->Flags & IS_INSTANCE_BASENAME) { if (InstanceSet1->Count == InstanceSet2->Count) { for (i = 0; i < InstanceSet1->Count; i++) { if (wcscmp(InstanceSet1->IsStaticNames->StaticNamePtr[i], InstanceSet2->IsStaticNames->StaticNamePtr[i]) != 0) { return(FALSE); } } return(TRUE); } } else { return(TRUE); } } return(FALSE); } ULONG WmipUpdateModifyGuid( PBDATASOURCE DataSource, PWMIREGGUID RegGuid, PWMIREGINFO RegistrationInfo, PBINSTANCESET *AddModInstanceSet ) /*++ Routine Description: This routine will modify an existing guid for the data source and send notification This routine assumes that the SM critical section is held before it is called. BUGBUG: If a guid was opened when it was registered as cheap, but closed when the guid was registered expensive a disable collection will NOT be sent. Conversely if a guid was opened when it was registered as expensive and is closed when registed as cheap a disable collection may be sent. Arguments: DataSource is the data source from which the guid is to be removed RegGuid has the Guid update data structure RegistrationInfo points at the beginning of the registration update info Return Value: 1 if guid was added or 2 if guid was modified else 0 --*/ { PBINSTANCESET InstanceSet; LPGUID Guid = &RegGuid->Guid; ULONG SendNotification; PBINSTANCESET InstanceSetNew; PVOID ToFree; InstanceSet = WmipFindISInDSByGuid(DataSource, Guid); if (InstanceSet != NULL) { // // See if anything has changed with the instance names and if not // then don't bother to recreate the instance set InstanceSetNew = WmipAllocInstanceSet(); if (InstanceSetNew == NULL) { WmipDebugPrint(("WMI: UpdateModifyGuid Not enough memory to alloc InstanceSet\n")); WmipUnreferenceIS(InstanceSet); return(0); } WmipBuildInstanceSet(RegGuid, RegistrationInfo, InstanceSetNew, DataSource->RegistryPath); if (! WmipIsEqualInstanceSets(InstanceSet, InstanceSetNew)) { ToFree = NULL; if (InstanceSet->IsBaseName != NULL) { ToFree = (PVOID)InstanceSet->IsBaseName; } RemoveEntryList(&InstanceSet->GuidISList); WmipBuildInstanceSet(RegGuid, RegistrationInfo, InstanceSet, DataSource->RegistryPath); InsertHeadList(&InstanceSet->GuidEntry->ISHead, &InstanceSet->GuidISList); WmipFree(ToFree); *AddModInstanceSet = InstanceSet; SendNotification = 2; } else { // // The InstanceSets are identical so just delete the new one SendNotification = 0; } WmipUnreferenceIS(InstanceSetNew); WmipUnreferenceIS(InstanceSet); } else { // // Guid not already registered so try to add it SendNotification = WmipUpdateAddGuid(DataSource, RegGuid, RegistrationInfo, AddModInstanceSet); } return(SendNotification); } void WmipCachePtrs( LPGUID Ptr1, PBINSTANCESET Ptr2, ULONG *PtrCount, ULONG *PtrMax, PTRCACHE **PtrArray ) { PTRCACHE *NewPtrArray; PTRCACHE *OldPtrArray; PTRCACHE *ActualPtrArray; if (*PtrCount == *PtrMax) { NewPtrArray = WmipAlloc((*PtrMax + PTRCACHEGROWSIZE) * sizeof(PTRCACHE)); if (NewPtrArray != NULL) { OldPtrArray = *PtrArray; memcpy(NewPtrArray, OldPtrArray, *PtrMax * sizeof(PTRCACHE)); *PtrMax += PTRCACHEGROWSIZE; if (*PtrArray != NULL) { WmipFree(PtrArray); } *PtrArray = NewPtrArray; } else { WmipDebugPrint(("WMI: Couldn't alloc memory for pointer cache\n")); return; } } ActualPtrArray = *PtrArray; ActualPtrArray[*PtrCount].Guid = Ptr1; ActualPtrArray[*PtrCount].InstanceSet = Ptr2; (*PtrCount)++; } void WmipUpdateDataSource( ULONG_PTR ProviderId, PWMIREGINFOW RegistrationInfo, ULONG RetSize ) /*++ Routine Description: This routine will update a data source with changes to already registered guids. Arguments: ProviderId is the provider id of the DataSource whose guids are being updated. RegistrationInfo has the registration update information RetSize has the size of the registration information returned from kernel mode. Return Value: --*/ { PBDATASOURCE DataSource; PBYTE RegInfo; ULONG RetSizeLeft; ULONG i; PWMIREGGUID RegGuid; ULONG NextWmiRegInfo; PTRCACHE *RemovedGuids; PTRCACHE *AddedGuids; PTRCACHE *ModifiedGuids; ULONG RemovedGuidCount; ULONG AddedGuidCount; ULONG ModifiedGuidCount; ULONG RemovedGuidMax; ULONG AddedGuidMax; ULONG ModifiedGuidMax; PBINSTANCESET InstanceSet; ULONG Action; DataSource = WmipFindDSByProviderId(ProviderId); if (DataSource == NULL) { WmipDebugPrint(("WMI: ProviderId %x requested update but is not registered\n", ProviderId)); return; } if ((RetSize < FIELD_OFFSET(WMIREGINFOW, WmiRegGuid)) || (RetSize < (FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) + RegistrationInfo->GuidCount * sizeof(WMIREGGUIDW)))) { WmipDebugPrint(("WMI: REGINFO Update block for %ws (%x) is too small\n", DataSource->RegistryPath, ProviderId)); WmipUnreferenceDS(DataSource); return; } AddedGuidCount = 0; ModifiedGuidCount = 0; RemovedGuidCount = 0; AddedGuidMax = 0; ModifiedGuidMax = 0; RemovedGuidMax = 0; ModifiedGuids = NULL; AddedGuids = NULL; RemovedGuids = NULL; NextWmiRegInfo = 0; RetSizeLeft = RetSize; WmipEnterSMCritSection(); do { RegInfo = (PBYTE)RegistrationInfo; if ((RegistrationInfo->NextWmiRegInfo > RetSizeLeft) || (RegistrationInfo->BufferSize > RetSizeLeft) || (RetSize < (FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) + RegistrationInfo->GuidCount * sizeof(WMIREGGUIDW)))) { WmipDebugPrint(("WMI: REGINFO update block for %ws (%x) has wrong size\n", DataSource->RegistryPath, ProviderId)); break; } for (i = 0; i < RegistrationInfo->GuidCount; i++) { RegGuid = &RegistrationInfo->WmiRegGuid[i]; if (RegGuid->Flags & WMIREG_FLAG_REMOVE_GUID) { if (WmipUpdateRemoveGuid(DataSource, RegGuid, &InstanceSet)) { WmipCachePtrs(&RegGuid->Guid, InstanceSet, &RemovedGuidCount, &RemovedGuidMax, &RemovedGuids); } } else { Action = WmipUpdateModifyGuid(DataSource, RegGuid, RegistrationInfo, &InstanceSet); if (Action == 1) { WmipCachePtrs(&RegGuid->Guid, InstanceSet, &AddedGuidCount, &AddedGuidMax, &AddedGuids); } else if (Action == 2) { WmipCachePtrs(&RegGuid->Guid, InstanceSet, &ModifiedGuidCount, &ModifiedGuidMax, &ModifiedGuids); } } } NextWmiRegInfo = RegistrationInfo->NextWmiRegInfo; RegistrationInfo = (PWMIREGINFOW)(RegInfo + NextWmiRegInfo); } while (NextWmiRegInfo != 0); WmipLeaveSMCritSection(); WmipUnreferenceDS(DataSource); if (RemovedGuidCount > 0) { for (i = 0; i < RemovedGuidCount; i++) { if (IsEqualGUID(RemovedGuids[i].Guid, &WmipBinaryMofGuid)) { WmipGenerateBinaryMofNotification(RemovedGuids[i].InstanceSet, &GUID_MOF_RESOURCE_REMOVED_NOTIFICATION); } InstanceSet = RemovedGuids[i].InstanceSet; WmipDisableCollectionForRemovedGuid(RemovedGuids[i].Guid, InstanceSet); WmipEnterSMCritSection(); // // If IS is on the GE list then remove it if (InstanceSet->GuidISList.Flink != NULL) { RemoveEntryList(&InstanceSet->GuidISList); InstanceSet->GuidEntry->ISCount--; } if (! (InstanceSet->Flags & IS_NEWLY_REGISTERED)) { WmipUnreferenceGE(InstanceSet->GuidEntry); } InstanceSet->GuidEntry = NULL; // // Remove IS from the DS List RemoveEntryList(&InstanceSet->DSISList); WmipUnreferenceIS(InstanceSet); WmipLeaveSMCritSection(); } WmipSendGuidUpdateNotifications(RegistrationDelete, RemovedGuidCount, RemovedGuids); WmipFree(RemovedGuids); } if (ModifiedGuidCount > 0) { for (i = 0; i < ModifiedGuidCount; i++) { if (IsEqualGUID(ModifiedGuids[i].Guid, &WmipBinaryMofGuid)) { WmipGenerateBinaryMofNotification(ModifiedGuids[i].InstanceSet, &GUID_MOF_RESOURCE_ADDED_NOTIFICATION); } } WmipSendGuidUpdateNotifications(RegistrationUpdate, ModifiedGuidCount, ModifiedGuids); WmipFree(ModifiedGuids); } if (AddedGuidCount > 0) { for (i = 0; i < AddedGuidCount; i++) { if (IsEqualGUID(AddedGuids[i].Guid, &WmipBinaryMofGuid)) { WmipGenerateBinaryMofNotification(AddedGuids[i].InstanceSet, &GUID_MOF_RESOURCE_ADDED_NOTIFICATION); } WmipEnableCollectionForNewGuid(AddedGuids[i].Guid, AddedGuids[i].InstanceSet); } WmipSendGuidUpdateNotifications(RegistrationAdd, AddedGuidCount, AddedGuids); WmipFree(AddedGuids); } } BOOLEAN WmipIsControlGuid( PBGUIDENTRY GuidEntry ) /*++ Routine Description: This routine determines whether a GUID is registered as a Traceable Guid and a Trace Control Guid. If any one of the instancesets for this Guid has the trace flag, then it is traceable Guid. Arguments: GuidEntry Pointer to the Guid Entry structure. Return Value: --*/ { PLIST_ENTRY InstanceSetList; PBINSTANCESET InstanceSet; if (GuidEntry != NULL) { WmipEnterSMCritSection(); InstanceSetList = GuidEntry->ISHead.Flink; while (InstanceSetList != &GuidEntry->ISHead) { InstanceSet = CONTAINING_RECORD(InstanceSetList, INSTANCESET, GuidISList); if ( (InstanceSet->Flags & IS_TRACED) && (InstanceSet->Flags & IS_CONTROL_GUID) ) { WmipLeaveSMCritSection(); return (TRUE); } InstanceSetList = InstanceSetList->Flink; } WmipLeaveSMCritSection(); } return (FALSE); } VOID WmipSaveTraceGuidMap( LPGUID Guid, PBINSTANCESET ControlInstanceSet ) /*++ Routine Description: This routine is called for an TRACE CONTROL GUID that's being Unregistered. If a logger session is on, then we save the GuidMap information so that at the end of logger stop, we can dump it to the logfile at the end. Arguments: Guid Guid that's getting unregistered. ControlInstanceSet InstanceSet that's going away. Return Value: --*/ { PNOTIFICATIONENTRY NotificationEntry; NotificationEntry = WmipFindNEByGuid(Guid, FALSE); if (NotificationEntry != NULL) { PBDATASOURCE DataSource; PLIST_ENTRY InstanceSetList; PBINSTANCESET InstanceSet; PGUIDMAPENTRY GuidMap; ULONGLONG SystemTime; GetSystemTimeAsFileTime((struct _FILETIME *)&SystemTime); WmipEnterSMCritSection(); DataSource = ControlInstanceSet->DataSource; // // From the DataSource of this Trace Control Instance, get // all the Trace Guids that's a part of this DataSource. // InstanceSetList = DataSource->ISHead.Flink; while (InstanceSetList != &DataSource->ISHead) { InstanceSet = CONTAINING_RECORD(InstanceSetList, INSTANCESET, DSISList); if (InstanceSet->Flags & IS_TRACED) { GuidMap = (PGUIDMAPENTRY) WmipAlloc(sizeof(GUIDMAPENTRY)); if (GuidMap != NULL) { GuidMap->GuidMap.Guid = (InstanceSet->GuidEntry->Guid); GuidMap->GuidMap.GuidMapHandle = (ULONG_PTR)InstanceSet; GuidMap->LoggerContext = NotificationEntry->LoggerContext; GuidMap->GuidMap.SystemTime = SystemTime; InsertTailList(GMHeadPtr, &GuidMap->Entry); } } InstanceSetList = InstanceSetList->Flink; } WmipLeaveSMCritSection(); WmipUnreferenceNE(NotificationEntry); } } #if DBG PTCHAR GuidToString( PTCHAR s, LPGUID piid ) { wsprintf(s, TEXT("%x-%x-%x-%x%x%x%x%x%x%x%x"), piid->Data1, piid->Data2, piid->Data3, piid->Data4[0], piid->Data4[1], piid->Data4[2], piid->Data4[3], piid->Data4[4], piid->Data4[5], piid->Data4[6], piid->Data4[7]); return(s); } #endif ULONG WmipRegisterInternalDataSource( void ) /*++ Routine Description: This routine will update the WMI internal data source by discovering all of the data sources that registered a guid using the PDO. Arguments: Return Value: --*/ { ULONG Status; ULONG_PTR ProviderId; UCHAR RegInfoBuffer[sizeof(WMIREGINFOW) + 2 * sizeof(WMIREGGUIDW)]; PWMIREGINFOW RegInfo = (PWMIREGINFOW)RegInfoBuffer; GUID InstanceInfoGuid = INSTANCE_INFO_GUID; GUID EnumerateGuidsGuid = ENUMERATE_GUIDS_GUID; memset(RegInfo, 0, sizeof(RegInfoBuffer)); RegInfo->BufferSize = sizeof(RegInfoBuffer); RegInfo->GuidCount = 2; RegInfo->WmiRegGuid[0].Guid = InstanceInfoGuid; RegInfo->WmiRegGuid[1].Guid = EnumerateGuidsGuid; ProviderId = INTERNAL_PROVIDER_ID; Status = WmipAddDataSource(NULL, 0, 0, NULL, RegInfo, RegInfo->BufferSize, &ProviderId, FALSE); return(Status); }