Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2559 lines
78 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. ds.c
  5. Abstract:
  6. WMI data provider registration code
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel Mode
  11. Revision History:
  12. --*/
  13. #include "wmikmp.h"
  14. void WmipEnableCollectionForNewGuid(
  15. LPGUID Guid,
  16. PBINSTANCESET InstanceSet
  17. );
  18. void WmipDisableCollectionForRemovedGuid(
  19. LPGUID Guid,
  20. PBINSTANCESET InstanceSet
  21. );
  22. VOID
  23. WmipSaveTraceGuidMap(
  24. LPGUID Guid,
  25. PBINSTANCESET ControlInstanceSet
  26. );
  27. ULONG WmipDetermineInstanceBaseIndex(
  28. LPGUID Guid,
  29. PWCHAR BaseName,
  30. ULONG InstanceCount
  31. );
  32. ULONG WmipMangleInstanceName(
  33. LPGUID Guid,
  34. PWCHAR Name,
  35. ULONG MaxMangledNameLen,
  36. PWCHAR MangledName
  37. );
  38. NTSTATUS WmipBuildInstanceSet(
  39. PWMIREGGUID RegGuid,
  40. PWMIREGINFOW WmiRegInfo,
  41. ULONG BufferSize,
  42. PBINSTANCESET InstanceSet,
  43. ULONG ProviderId,
  44. LPCTSTR MofImagePath
  45. );
  46. NTSTATUS WmipLinkDataSourceToList(
  47. PBDATASOURCE DataSource,
  48. BOOLEAN AddDSToList
  49. );
  50. void WmipSendGuidUpdateNotifications(
  51. NOTIFICATIONTYPES NotificationType,
  52. ULONG GuidCount,
  53. PTRCACHE *GuidList
  54. );
  55. void WmipGenerateBinaryMofNotification(
  56. PBINSTANCESET BinaryMofInstanceSet,
  57. LPCGUID Guid
  58. );
  59. void WmipGenerateRegistrationNotification(
  60. PBDATASOURCE DataSource,
  61. ULONG NotificationCode
  62. );
  63. NTSTATUS WmipAddMofResource(
  64. PBDATASOURCE DataSource,
  65. LPWSTR ImagePath,
  66. BOOLEAN IsImagePath,
  67. LPWSTR MofResourceName,
  68. PBOOLEAN NewMofResource
  69. );
  70. PBINSTANCESET WmipFindISInDSByGuid(
  71. PBDATASOURCE DataSource,
  72. LPGUID Guid
  73. );
  74. ULONG WmipUpdateAddGuid(
  75. PBDATASOURCE DataSource,
  76. PWMIREGGUID RegGuid,
  77. PWMIREGINFO WmiRegInfo,
  78. ULONG BufferSize,
  79. PBINSTANCESET *AddModInstanceSet
  80. );
  81. PTCHAR GuidToString(
  82. PTCHAR s,
  83. LPGUID piid
  84. );
  85. BOOLEAN WmipUpdateRemoveGuid(
  86. PBDATASOURCE DataSource,
  87. PWMIREGGUID RegGuid,
  88. PBINSTANCESET *AddModInstanceSet
  89. );
  90. BOOLEAN WmipIsEqualInstanceSets(
  91. PBINSTANCESET InstanceSet1,
  92. PBINSTANCESET InstanceSet2
  93. );
  94. ULONG WmipUpdateModifyGuid(
  95. PBDATASOURCE DataSource,
  96. PWMIREGGUID RegGuid,
  97. PWMIREGINFO WmiRegInfo,
  98. ULONG BufferSize,
  99. PBINSTANCESET *AddModInstanceSet
  100. );
  101. void WmipCachePtrs(
  102. LPGUID Ptr1,
  103. PBINSTANCESET Ptr2,
  104. ULONG *PtrCount,
  105. ULONG *PtrMax,
  106. PTRCACHE **PtrArray
  107. );
  108. NTSTATUS WmipUpdateDataSource(
  109. PREGENTRY RegEntry,
  110. PWMIREGINFOW WmiRegInfo,
  111. ULONG RetSize
  112. );
  113. void WmipRemoveDataSourceByDS(
  114. PBDATASOURCE DataSource
  115. );
  116. NTSTATUS WmipRemoveDataSource(
  117. PREGENTRY RegEntry
  118. );
  119. NTSTATUS WmipInitializeDataStructs(
  120. void
  121. );
  122. NTSTATUS WmipEnumerateMofResources(
  123. PWMIMOFLIST MofList,
  124. ULONG BufferSize,
  125. ULONG *RetSize
  126. );
  127. #ifdef ALLOC_PRAGMA
  128. #pragma alloc_text(INIT,WmipInitializeDataStructs)
  129. #pragma alloc_text(PAGE,WmipEnableCollectionForNewGuid)
  130. #pragma alloc_text(PAGE,WmipDisableCollectionForRemovedGuid)
  131. #pragma alloc_text(PAGE,WmipSaveTraceGuidMap)
  132. #pragma alloc_text(PAGE,WmipDetermineInstanceBaseIndex)
  133. #pragma alloc_text(PAGE,WmipMangleInstanceName)
  134. #pragma alloc_text(PAGE,WmipBuildInstanceSet)
  135. #pragma alloc_text(PAGE,WmipLinkDataSourceToList)
  136. #pragma alloc_text(PAGE,WmipSendGuidUpdateNotifications)
  137. #pragma alloc_text(PAGE,WmipGenerateBinaryMofNotification)
  138. #pragma alloc_text(PAGE,WmipGenerateMofResourceNotification)
  139. #pragma alloc_text(PAGE,WmipGenerateRegistrationNotification)
  140. #pragma alloc_text(PAGE,WmipAddMofResource)
  141. #pragma alloc_text(PAGE,WmipAddDataSource)
  142. #pragma alloc_text(PAGE,WmipFindISInDSByGuid)
  143. #pragma alloc_text(PAGE,WmipUpdateAddGuid)
  144. #pragma alloc_text(PAGE,WmipUpdateRemoveGuid)
  145. #pragma alloc_text(PAGE,WmipIsEqualInstanceSets)
  146. #pragma alloc_text(PAGE,WmipUpdateModifyGuid)
  147. #pragma alloc_text(PAGE,WmipCachePtrs)
  148. #pragma alloc_text(PAGE,WmipUpdateDataSource)
  149. #pragma alloc_text(PAGE,WmipRemoveDataSourceByDS)
  150. #pragma alloc_text(PAGE,WmipRemoveDataSource)
  151. #pragma alloc_text(PAGE,WmipEnumerateMofResources)
  152. #if DBG
  153. #pragma alloc_text(PAGE,GuidToString)
  154. #endif
  155. #endif
  156. #ifdef ALLOC_DATA_PRAGMA
  157. #pragma const_seg("PAGECONST")
  158. #endif
  159. const GUID WmipBinaryMofGuid = BINARY_MOF_GUID;
  160. // {4EE0B301-94BC-11d0-A4EC-00A0C9062910}
  161. const GUID RegChangeNotificationGuid =
  162. { 0x4ee0b301, 0x94bc, 0x11d0, { 0xa4, 0xec, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } };
  163. void WmipEnableCollectionForNewGuid(
  164. LPGUID Guid,
  165. PBINSTANCESET InstanceSet
  166. )
  167. {
  168. WNODE_HEADER Wnode;
  169. PBGUIDENTRY GuidEntry;
  170. ULONG Status;
  171. BOOLEAN IsTraceLog;
  172. PAGED_CODE();
  173. GuidEntry = WmipFindGEByGuid(Guid, FALSE);
  174. if (GuidEntry != NULL)
  175. {
  176. memset(&Wnode, 0, sizeof(WNODE_HEADER));
  177. memcpy(&Wnode.Guid, Guid, sizeof(GUID));
  178. Wnode.BufferSize = sizeof(WNODE_HEADER);
  179. WmipEnterSMCritSection();
  180. if ((GuidEntry->EventRefCount > 0) &&
  181. ((InstanceSet->Flags & IS_ENABLE_EVENT) == 0))
  182. {
  183. //
  184. // Events were previously enabled for this guid, but not for this
  185. // instance set so call data source for instance set to enable
  186. // the events. First set the in progress flag and InstanceSet
  187. // set flag to denote that events have been enabled for the
  188. // instance set.
  189. InstanceSet->Flags |= IS_ENABLE_EVENT;
  190. //
  191. // If it is Tracelog, NewGuid notifications are piggybacked with
  192. // Registration call return.
  193. //
  194. IsTraceLog = ((InstanceSet->Flags & IS_TRACED) == IS_TRACED);
  195. if (IsTraceLog)
  196. {
  197. if (!(InstanceSet->DataSource->Flags & DS_KERNEL_MODE) )
  198. {
  199. if (GuidEntry != NULL)
  200. {
  201. WmipUnreferenceGE(GuidEntry);
  202. }
  203. WmipLeaveSMCritSection();
  204. return;
  205. }
  206. //
  207. // For the Kernel Mode Trace Providers pass on the context
  208. //
  209. Wnode.HistoricalContext = GuidEntry->LoggerContext;
  210. }
  211. GuidEntry->Flags |= GE_FLAG_NOTIFICATION_IN_PROGRESS;
  212. WmipLeaveSMCritSection();
  213. WmipDeliverWnodeToDS(IRP_MN_ENABLE_EVENTS,
  214. InstanceSet->DataSource,
  215. &Wnode,
  216. Wnode.BufferSize);
  217. WmipEnterSMCritSection();
  218. //
  219. // Now we need to check if events were disabled while the enable
  220. // request was in progress. If so go do the work to actually
  221. // disable them.
  222. if (GuidEntry->EventRefCount == 0)
  223. {
  224. Status = WmipDoDisableRequest(GuidEntry,
  225. TRUE,
  226. IsTraceLog,
  227. GuidEntry->LoggerContext,
  228. GE_FLAG_NOTIFICATION_IN_PROGRESS);
  229. } else {
  230. GuidEntry->Flags &= ~GE_FLAG_NOTIFICATION_IN_PROGRESS;
  231. }
  232. }
  233. //
  234. // Now check to see if collection needs to be enabled for this guid
  235. //
  236. if ((GuidEntry->CollectRefCount > 0) &&
  237. ((InstanceSet->Flags & IS_ENABLE_COLLECTION) == 0) &&
  238. (InstanceSet->Flags & IS_EXPENSIVE) )
  239. {
  240. //
  241. // Collection was previously enabled for this guid, but not
  242. // for this instance set so call data source for instance set
  243. // to enable collection. First set the in progress flag and
  244. // InstanceSet set flag to denote that collection has been enabled
  245. // for the instance set.
  246. //
  247. GuidEntry->Flags |= GE_FLAG_COLLECTION_IN_PROGRESS;
  248. InstanceSet->Flags |= IS_ENABLE_COLLECTION;
  249. WmipLeaveSMCritSection();
  250. WmipDeliverWnodeToDS(IRP_MN_ENABLE_COLLECTION,
  251. InstanceSet->DataSource,
  252. &Wnode,
  253. Wnode.BufferSize);
  254. WmipEnterSMCritSection();
  255. //
  256. // Now we need to check if events were disabled while the enable
  257. // request was in progress. If so go do the work to actually
  258. // disable them.
  259. //
  260. if (GuidEntry->CollectRefCount == 0)
  261. {
  262. Status = WmipDoDisableRequest(GuidEntry,
  263. FALSE,
  264. FALSE,
  265. 0,
  266. GE_FLAG_COLLECTION_IN_PROGRESS);
  267. } else {
  268. GuidEntry->Flags &= ~GE_FLAG_COLLECTION_IN_PROGRESS;
  269. //
  270. // If there are any other threads that were waiting
  271. // until all of the enable/disable work completed, we
  272. // close the event handle to release them from their wait.
  273. //
  274. WmipReleaseCollectionEnabled(GuidEntry);
  275. }
  276. }
  277. WmipUnreferenceGE(GuidEntry);
  278. WmipLeaveSMCritSection();
  279. } else {
  280. WmipAssert(FALSE);
  281. }
  282. }
  283. void WmipDisableCollectionForRemovedGuid(
  284. LPGUID Guid,
  285. PBINSTANCESET InstanceSet
  286. )
  287. {
  288. WNODE_HEADER Wnode;
  289. PBGUIDENTRY GuidEntry;
  290. ULONG Status;
  291. BOOLEAN IsTraceLog;
  292. PAGED_CODE();
  293. GuidEntry = WmipFindGEByGuid(Guid, FALSE);
  294. if (GuidEntry != NULL)
  295. {
  296. memset(&Wnode, 0, sizeof(WNODE_HEADER));
  297. memcpy(&Wnode.Guid, Guid, sizeof(GUID));
  298. Wnode.BufferSize = sizeof(WNODE_HEADER);
  299. WmipEnterSMCritSection();
  300. if ((GuidEntry->EventRefCount > 0) &&
  301. ((InstanceSet->Flags & IS_ENABLE_EVENT) != 0))
  302. {
  303. // Events were previously enabled for this guid, but not for this
  304. // instance set so call data source for instance set to enable
  305. // the events. First set the in progress flag and InstanceSet
  306. // set flag to denote that events have been enabled for the
  307. // instance set.
  308. InstanceSet->Flags &= ~IS_ENABLE_EVENT;
  309. //
  310. // If it is Tracelog, RemoveGuid notifications are handled
  311. // through UnregisterGuids call.
  312. //
  313. IsTraceLog = ((InstanceSet->Flags & IS_TRACED) == IS_TRACED);
  314. if (IsTraceLog)
  315. {
  316. if ( !(InstanceSet->DataSource->Flags & DS_KERNEL_MODE))
  317. {
  318. WmipUnreferenceGE(GuidEntry);
  319. WmipLeaveSMCritSection();
  320. return;
  321. }
  322. Wnode.HistoricalContext = GuidEntry->LoggerContext;
  323. }
  324. GuidEntry->Flags |= GE_FLAG_NOTIFICATION_IN_PROGRESS;
  325. WmipLeaveSMCritSection();
  326. WmipDeliverWnodeToDS(IRP_MN_DISABLE_EVENTS,
  327. InstanceSet->DataSource,
  328. &Wnode,
  329. Wnode.BufferSize);
  330. WmipEnterSMCritSection();
  331. //
  332. // Now we need to check if events were disabled while the enable
  333. // request was in progress. If so go do the work to actually
  334. // disable them.
  335. if (GuidEntry->EventRefCount == 0)
  336. {
  337. Status = WmipDoDisableRequest(GuidEntry,
  338. TRUE,
  339. IsTraceLog,
  340. GuidEntry->LoggerContext,
  341. GE_FLAG_NOTIFICATION_IN_PROGRESS);
  342. } else {
  343. GuidEntry->Flags &= ~GE_FLAG_NOTIFICATION_IN_PROGRESS;
  344. }
  345. }
  346. //
  347. // Now check to see if collection needs to be enabled for this guid
  348. if ((GuidEntry->CollectRefCount > 0) &&
  349. ((InstanceSet->Flags & IS_ENABLE_COLLECTION) != 0))
  350. {
  351. // Collection was previously enabled for this guid, but not
  352. // for this instance set so call data source for instance set
  353. // to enable collection. First set the in progress flag and
  354. // InstanceSet set flag to denote that collection has been enabled
  355. // for the instance set.
  356. GuidEntry->Flags |= GE_FLAG_COLLECTION_IN_PROGRESS;
  357. InstanceSet->Flags &= ~IS_ENABLE_COLLECTION;
  358. WmipLeaveSMCritSection();
  359. WmipDeliverWnodeToDS(IRP_MN_DISABLE_COLLECTION,
  360. InstanceSet->DataSource,
  361. &Wnode,
  362. Wnode.BufferSize);
  363. WmipEnterSMCritSection();
  364. //
  365. // Now we need to check if events were disabled while the enable
  366. // request was in progress. If so go do the work to actually
  367. // disable them.
  368. if (GuidEntry->CollectRefCount == 0)
  369. {
  370. Status = WmipDoDisableRequest(GuidEntry,
  371. FALSE,
  372. FALSE,
  373. 0,
  374. GE_FLAG_COLLECTION_IN_PROGRESS);
  375. } else {
  376. GuidEntry->Flags &= ~GE_FLAG_COLLECTION_IN_PROGRESS;
  377. //
  378. // If there are any other threads that were waiting
  379. // until all of the enable/disable work completed, we
  380. // close the event handle to release them from their wait.
  381. //
  382. WmipReleaseCollectionEnabled(GuidEntry);
  383. }
  384. }
  385. WmipUnreferenceGE(GuidEntry);
  386. WmipLeaveSMCritSection();
  387. } else {
  388. WmipAssert(FALSE);
  389. }
  390. }
  391. VOID
  392. WmipSaveTraceGuidMap(
  393. LPGUID Guid,
  394. PBINSTANCESET ControlInstanceSet
  395. )
  396. /*++
  397. Routine Description:
  398. This routine is called for an TRACE CONTROL GUID that's being Unregistered.
  399. If a logger session is on, then we save the GuidMap information
  400. so that at the end of logger stop, we can dump it to the
  401. logfile at the end.
  402. Arguments:
  403. Guid Guid that's getting unregistered.
  404. ControlInstanceSet InstanceSet that's going away.
  405. Return Value:
  406. --*/
  407. {
  408. PGUIDENTRY GuidEntry;
  409. PAGED_CODE();
  410. GuidEntry = WmipFindGEByGuid(Guid, FALSE);
  411. if (GuidEntry != NULL)
  412. {
  413. PBDATASOURCE DataSource;
  414. PLIST_ENTRY InstanceSetList;
  415. PBINSTANCESET InstanceSet;
  416. PGUIDMAPENTRY GuidMap;
  417. ULONGLONG SystemTime;
  418. PTRACEGUIDMAP TraceGuidMapPtr;
  419. ULONG i;
  420. PTRACE_ENABLE_CONTEXT pContext = (PTRACE_ENABLE_CONTEXT) &GuidEntry->LoggerContext;
  421. //
  422. // If this Guid is not currently enabled for tracing, return
  423. //
  424. if ( ( (GuidEntry->Flags & GE_NOTIFICATION_TRACE_FLAG) != GE_NOTIFICATION_TRACE_FLAG ) ||
  425. ( pContext->InternalFlag & EVENT_TRACE_INTERNAL_FLAG_PRIVATE) )
  426. {
  427. WmipUnreferenceGE(GuidEntry);
  428. return;
  429. }
  430. KeQuerySystemTime((PLARGE_INTEGER)&SystemTime);
  431. WmipEnterSMCritSection();
  432. for (i=0, TraceGuidMapPtr = ControlInstanceSet->TraceGuidMap;
  433. ((i < ControlInstanceSet->TransGuidCount) && (ControlInstanceSet->TraceGuidMap != NULL));
  434. i++, TraceGuidMapPtr++) {
  435. GuidMap = (PGUIDMAPENTRY) WmipAllocWithTag(sizeof(GUIDMAPENTRY), WMI_GM_POOLTAG);
  436. if (GuidMap != NULL) {
  437. GuidMap->GuidMap.Guid = ControlInstanceSet->TraceGuidMap->Guid;
  438. GuidMap->GuidMap.GuidMapHandle = (ULONG_PTR)TraceGuidMapPtr;
  439. GuidMap->LoggerContext = GuidEntry->LoggerContext;
  440. GuidMap->GuidMap.SystemTime = SystemTime;
  441. InsertTailList(WmipGMHeadPtr, &GuidMap->Entry);
  442. }
  443. }
  444. WmipLeaveSMCritSection();
  445. WmipUnreferenceGE(GuidEntry);
  446. }
  447. }
  448. ULONG WmipDetermineInstanceBaseIndex(
  449. LPGUID Guid,
  450. PWCHAR BaseName,
  451. ULONG InstanceCount
  452. )
  453. /*++
  454. Routine Description:
  455. Figure out the base index for the instance names specified by a base
  456. instance name. We walk the list of instances sets for the guid and if
  457. there is a match in the base instance name we set the base instance index
  458. above that used by the previously registered instance set.
  459. Arguments:
  460. Guid points at guid for the instance names
  461. BaseName points at the base name for the instances
  462. InstanceCount is the count of instance names
  463. Return Value:
  464. Base index for instance name
  465. --*/
  466. {
  467. PBGUIDENTRY GuidEntry;
  468. ULONG BaseIndex = 0;
  469. PLIST_ENTRY InstanceSetList;
  470. PBINSTANCESET InstanceSet;
  471. ULONG LastBaseIndex;
  472. PAGED_CODE();
  473. WmipEnterSMCritSection();
  474. GuidEntry = WmipFindGEByGuid(Guid, FALSE);
  475. if (GuidEntry != NULL)
  476. {
  477. InstanceSetList = GuidEntry->ISHead.Flink;
  478. while (InstanceSetList != &GuidEntry->ISHead)
  479. {
  480. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  481. INSTANCESET,
  482. GuidISList);
  483. if (InstanceSet->Flags & IS_INSTANCE_BASENAME)
  484. {
  485. if (wcscmp(BaseName, InstanceSet->IsBaseName->BaseName) == 0)
  486. {
  487. LastBaseIndex = InstanceSet->IsBaseName->BaseIndex + InstanceSet->Count;
  488. if (BaseIndex <= LastBaseIndex)
  489. {
  490. BaseIndex = LastBaseIndex;
  491. }
  492. }
  493. }
  494. InstanceSetList = InstanceSetList->Flink;
  495. }
  496. WmipUnreferenceGE(GuidEntry);
  497. }
  498. WmipLeaveSMCritSection();
  499. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Static instance name %ws has base index %x\n",
  500. BaseName, BaseIndex));
  501. return(BaseIndex);
  502. }
  503. ULONG WmipMangleInstanceName(
  504. LPGUID Guid,
  505. PWCHAR Name,
  506. ULONG MaxMangledNameLen,
  507. PWCHAR MangledName
  508. )
  509. /*++
  510. Routine Description:
  511. Copies a static instance name from the input buffer to the output
  512. buffer, mangling it if the name collides with another name for the
  513. same guid.
  514. Arguments:
  515. Guid points at guid for the instance name
  516. Name points at the proposed instance name
  517. MaxMangledNameLen has the maximum number of chars in mangled name buffer
  518. MangledName points at buffer to return mangled name
  519. Return Value:
  520. Actual length of mangled name
  521. --*/
  522. {
  523. PBGUIDENTRY GuidEntry;
  524. WCHAR ManglingChar;
  525. ULONG ManglePos;
  526. ULONG InstanceIndex;
  527. PBINSTANCESET InstanceSet;
  528. PAGED_CODE();
  529. WmipAssert(MaxMangledNameLen >= wcslen(Name));
  530. wcsncpy(MangledName, Name, MaxMangledNameLen);
  531. GuidEntry = WmipFindGEByGuid(Guid, FALSE);
  532. if (GuidEntry != NULL)
  533. {
  534. ManglePos = wcslen(MangledName)-1;
  535. ManglingChar = L'Z';
  536. //
  537. // Loop until we get a unique name
  538. InstanceSet = WmipFindISinGEbyName(GuidEntry,
  539. MangledName,
  540. &InstanceIndex);
  541. while (InstanceSet != NULL)
  542. {
  543. WmipUnreferenceIS(InstanceSet);
  544. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Need to mangle name %ws\n",
  545. MangledName));
  546. if (ManglingChar == L'Z')
  547. {
  548. ManglingChar = L'A';
  549. if (++ManglePos == MaxMangledNameLen)
  550. {
  551. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Instance Name could not be mangled\n"));
  552. break;
  553. }
  554. MangledName[ManglePos+1] = UNICODE_NULL;
  555. } else {
  556. ManglingChar++;
  557. }
  558. MangledName[ManglePos] = ManglingChar;
  559. InstanceSet = WmipFindISinGEbyName(GuidEntry,
  560. MangledName,
  561. &InstanceIndex) ;
  562. }
  563. WmipUnreferenceGE(GuidEntry);
  564. }
  565. return(wcslen(MangledName)+1);
  566. }
  567. NTSTATUS WmipBuildInstanceSet(
  568. PWMIREGGUID RegGuid,
  569. PWMIREGINFOW WmiRegInfo,
  570. ULONG BufferSize,
  571. PBINSTANCESET InstanceSet,
  572. ULONG ProviderId,
  573. LPCTSTR MofImagePath
  574. )
  575. {
  576. PWCHAR InstanceName, InstanceNamePtr;
  577. PBISBASENAME IsBaseName;
  578. PBISSTATICNAMES IsStaticName;
  579. ULONG SizeNeeded;
  580. ULONG SuffixSize;
  581. PWCHAR StaticNames;
  582. ULONG Len;
  583. ULONG InstanceCount;
  584. ULONG j;
  585. ULONG MaxStaticInstanceNameSize;
  586. PWCHAR StaticInstanceNameBuffer;
  587. ULONG InstanceNameOffset;
  588. NTSTATUS Status;
  589. PAGED_CODE();
  590. //
  591. // Remember the count of instances for the guid in the DS
  592. //
  593. InstanceCount = RegGuid->InstanceCount;
  594. InstanceSet->Count = InstanceCount;
  595. InstanceSet->ProviderId = ProviderId;
  596. //
  597. // Reset any flags that might be changed by a new REGGUID
  598. //
  599. InstanceSet->Flags &= ~(IS_EXPENSIVE |
  600. IS_EVENT_ONLY |
  601. IS_PDO_INSTANCENAME |
  602. IS_INSTANCE_STATICNAMES |
  603. IS_INSTANCE_BASENAME);
  604. //
  605. // Finish initializing the Instance Set flags
  606. //
  607. if (RegGuid->Flags & WMIREG_FLAG_EXPENSIVE)
  608. {
  609. InstanceSet->Flags |= IS_EXPENSIVE;
  610. }
  611. if (RegGuid->Flags & WMIREG_FLAG_TRACED_GUID)
  612. {
  613. //
  614. // This guid is not queryable, but is used for sending trace
  615. // events. We mark the InstanceSet as special
  616. InstanceSet->Flags |= IS_TRACED;
  617. if (RegGuid->Flags & WMIREG_FLAG_TRACE_CONTROL_GUID)
  618. {
  619. InstanceSet->Flags |= IS_CONTROL_GUID;
  620. }
  621. }
  622. if (RegGuid->Flags & WMIREG_FLAG_EVENT_ONLY_GUID)
  623. {
  624. //
  625. // This guid is not queryable, but is only used for sending
  626. // events. We mark the InstanceSet as special
  627. InstanceSet->Flags |= IS_EVENT_ONLY;
  628. }
  629. InstanceName = (LPWSTR)OffsetToPtr(WmiRegInfo,
  630. RegGuid->BaseNameOffset);
  631. InstanceNameOffset = RegGuid->BaseNameOffset;
  632. if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_LIST)
  633. {
  634. //
  635. // We have static list of instance names that might need mangling
  636. // We assume that any name mangling that must occur can be
  637. // done with a suffix of 5 or fewer characters. This allows
  638. // up to 100,000 identical static instance names within the
  639. // same guid. First lets get the amount of memory we'll need
  640. //
  641. SizeNeeded = FIELD_OFFSET(ISSTATICENAMES, StaticNamePtr) + 1;
  642. SuffixSize = MAXBASENAMESUFFIXSIZE;
  643. MaxStaticInstanceNameSize = 0;
  644. for (j = 0; j < InstanceCount; j++)
  645. {
  646. Status = WmipValidateWmiRegInfoString(WmiRegInfo,
  647. BufferSize,
  648. InstanceNameOffset,
  649. &InstanceNamePtr);
  650. if ((! NT_SUCCESS(Status)) || (InstanceNamePtr == NULL))
  651. {
  652. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAddDataSource: bad static instance name %x\n", InstanceNamePtr));
  653. WmipReportEventLog(EVENT_WMI_INVALID_REGINFO,
  654. EVENTLOG_WARNING_TYPE,
  655. 0,
  656. WmiRegInfo->BufferSize,
  657. WmiRegInfo,
  658. 1,
  659. MofImagePath ? MofImagePath : TEXT("Unknown"));
  660. return(STATUS_INVALID_PARAMETER);
  661. }
  662. if (*InstanceNamePtr > MaxStaticInstanceNameSize)
  663. {
  664. MaxStaticInstanceNameSize = *InstanceNamePtr;
  665. }
  666. SizeNeeded += *InstanceNamePtr + 1 + SuffixSize +
  667. (sizeof(PWCHAR) / sizeof(WCHAR));
  668. InstanceNameOffset += *InstanceNamePtr + 2;
  669. }
  670. IsStaticName = (PBISSTATICNAMES)WmipAllocString(SizeNeeded);
  671. if (IsStaticName == NULL)
  672. {
  673. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAddDataSource: alloc static instance names\n"));
  674. return(STATUS_INSUFFICIENT_RESOURCES);
  675. }
  676. InstanceSet->Flags |= IS_INSTANCE_STATICNAMES;
  677. InstanceSet->IsStaticNames = IsStaticName;
  678. StaticNames = (PWCHAR) ((PUCHAR)IsStaticName +
  679. (InstanceCount * sizeof(PWCHAR)));
  680. InstanceNamePtr = InstanceName;
  681. StaticInstanceNameBuffer = WmipAlloc(MaxStaticInstanceNameSize + sizeof(WCHAR));
  682. if (StaticInstanceNameBuffer == NULL)
  683. {
  684. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAddDataSource: couldn't alloc StaticInstanceNameBuffer\n"));
  685. return(STATUS_INSUFFICIENT_RESOURCES);
  686. }
  687. for (j = 0; j < InstanceCount; j++)
  688. {
  689. IsStaticName->StaticNamePtr[j] = StaticNames;
  690. memcpy(StaticInstanceNameBuffer, InstanceNamePtr+1, *InstanceNamePtr);
  691. StaticInstanceNameBuffer[*InstanceNamePtr/sizeof(WCHAR)] = UNICODE_NULL;
  692. Len = WmipMangleInstanceName(&RegGuid->Guid,
  693. StaticInstanceNameBuffer,
  694. *InstanceNamePtr +
  695. SuffixSize + 1,
  696. StaticNames);
  697. StaticNames += Len;
  698. InstanceNamePtr += (*((USHORT *)InstanceNamePtr) + 2)/sizeof(WCHAR);
  699. }
  700. WmipFree(StaticInstanceNameBuffer);
  701. } else if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_BASENAME) {
  702. //
  703. // We have static instance names built from a base name
  704. Status = WmipValidateWmiRegInfoString(WmiRegInfo,
  705. BufferSize,
  706. InstanceNameOffset,
  707. &InstanceNamePtr);
  708. if (! NT_SUCCESS(Status))
  709. {
  710. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAddDataSource: Invalid instance base name %x\n",
  711. InstanceName));
  712. WmipReportEventLog(EVENT_WMI_INVALID_REGINFO,
  713. EVENTLOG_WARNING_TYPE,
  714. 0,
  715. WmiRegInfo->BufferSize,
  716. WmiRegInfo,
  717. 1,
  718. MofImagePath ? MofImagePath : TEXT("Unknown"));
  719. return(STATUS_INVALID_PARAMETER);
  720. }
  721. InstanceSet->Flags |= IS_INSTANCE_BASENAME;
  722. if (RegGuid->Flags & WMIREG_FLAG_INSTANCE_PDO)
  723. {
  724. InstanceSet->Flags |= IS_PDO_INSTANCENAME;
  725. }
  726. IsBaseName = (PBISBASENAME)WmipAlloc(*InstanceName +
  727. sizeof(WCHAR) +
  728. FIELD_OFFSET(ISBASENAME,
  729. BaseName));
  730. if (IsBaseName == NULL)
  731. {
  732. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAddDataSource: alloc ISBASENAME failed\n"));
  733. return(STATUS_INSUFFICIENT_RESOURCES);
  734. }
  735. InstanceSet->IsBaseName = IsBaseName;
  736. memcpy(IsBaseName->BaseName, InstanceName+1, *InstanceName);
  737. IsBaseName->BaseName[*InstanceName/sizeof(WCHAR)] = UNICODE_NULL;
  738. IsBaseName->BaseIndex = WmipDetermineInstanceBaseIndex(
  739. &RegGuid->Guid,
  740. IsBaseName->BaseName,
  741. RegGuid->InstanceCount);
  742. }
  743. return(STATUS_SUCCESS);
  744. }
  745. NTSTATUS WmipLinkDataSourceToList(
  746. PBDATASOURCE DataSource,
  747. BOOLEAN AddDSToList
  748. )
  749. /*++
  750. Routine Description:
  751. This routine will take a DataSource that was just registered or updated
  752. and link any new InstanceSets to an appropriate GuidEntry. Then if the
  753. AddDSToList is TRUE the DataSource itself will be added to the main
  754. data source list.
  755. This routine will do all of the linkages within a critical section so the
  756. data source and its new instances are added atomically. The routine will
  757. also determine if the guid entry associated with a InstanceSet is a
  758. duplicate of another that is already on the main guid entry list and if
  759. so will use the preexisting guid entry.
  760. This routine assumes that the SM critical section has been taken
  761. Arguments:
  762. DataSource is a based pointer to a DataSource structure
  763. AddDSToList is TRUE then data source will be added to the main list
  764. of data sources
  765. Return Value:
  766. ERROR_SUCCESS or an error code
  767. --*/
  768. {
  769. PBINSTANCESET InstanceSet;
  770. PLIST_ENTRY InstanceSetList;
  771. PBGUIDENTRY GuidEntry;
  772. PAGED_CODE();
  773. InstanceSetList = DataSource->ISHead.Flink;
  774. while (InstanceSetList != &DataSource->ISHead)
  775. {
  776. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  777. INSTANCESET,
  778. DSISList);
  779. //
  780. // If this instance set has just been registered then we need to
  781. // get it on a GuidEntry list.
  782. if (InstanceSet->Flags & IS_NEWLY_REGISTERED)
  783. {
  784. //
  785. // See if there is already a GUID entry for the instance set.
  786. // If not go allocate a new guid entry and place it on the
  787. // main guid list. If there already is a GuidEntry for the
  788. // InstanceSet we will assign the ref count that was given by
  789. // the WmipFindGEByGuid to the DataSource which will unreference
  790. // the GuidEntry when the DataSource is unregistered.
  791. GuidEntry = WmipFindGEByGuid((LPGUID)InstanceSet->GuidEntry,
  792. FALSE);
  793. if (GuidEntry == NULL)
  794. {
  795. GuidEntry = WmipAllocGuidEntry();
  796. if (GuidEntry == NULL)
  797. {
  798. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipLinkDataSourceToList: WmipAllocGuidEntry failed\n"));
  799. return(STATUS_INSUFFICIENT_RESOURCES);
  800. }
  801. //
  802. // Initialize the new GuidEntry and place it on the master
  803. // GuidEntry list.
  804. memcpy(&GuidEntry->Guid,
  805. (LPGUID)InstanceSet->GuidEntry,
  806. sizeof(GUID));
  807. InsertHeadList(WmipGEHeadPtr, &GuidEntry->MainGEList);
  808. }
  809. InstanceSet->GuidEntry = GuidEntry;
  810. InstanceSet->Flags &= ~IS_NEWLY_REGISTERED;
  811. InsertTailList(&GuidEntry->ISHead, &InstanceSet->GuidISList);
  812. GuidEntry->ISCount++;
  813. }
  814. InstanceSetList = InstanceSetList->Flink;
  815. }
  816. if (AddDSToList)
  817. {
  818. WmipAssert(! (DataSource->Flags & FLAG_ENTRY_ON_INUSE_LIST));
  819. DataSource->Flags |= FLAG_ENTRY_ON_INUSE_LIST;
  820. InsertTailList(WmipDSHeadPtr, &DataSource->MainDSList);
  821. }
  822. return(STATUS_SUCCESS);
  823. }
  824. void WmipSendGuidUpdateNotifications(
  825. NOTIFICATIONTYPES NotificationType,
  826. ULONG GuidCount,
  827. PTRCACHE *GuidList
  828. )
  829. {
  830. PUCHAR WnodeBuffer;
  831. PWNODE_SINGLE_INSTANCE Wnode;
  832. ULONG WnodeSize;
  833. LPGUID GuidPtr;
  834. ULONG i;
  835. PWCHAR InstanceName;
  836. PMSWmi_GuidRegistrationInfo RegInfo;
  837. ULONG DataBlockSize;
  838. GUID RegChangeGuid = MSWmi_GuidRegistrationInfoGuid;
  839. #define REGUPDATENAME L"REGUPDATEINFO"
  840. PAGED_CODE();
  841. DataBlockSize = sizeof(MSWmi_GuidRegistrationInfo) +
  842. GuidCount*sizeof(GUID) - sizeof(GUID);
  843. WnodeSize = sizeof(WNODE_SINGLE_INSTANCE) +
  844. sizeof(USHORT) + sizeof(REGUPDATENAME) + 8 + DataBlockSize;
  845. WnodeBuffer = WmipAlloc(WnodeSize);
  846. if (WnodeBuffer != NULL)
  847. {
  848. Wnode = (PWNODE_SINGLE_INSTANCE)WnodeBuffer;
  849. //
  850. // Setup a WNODE_SINGLE_INSTANCE event with the updated guid
  851. // registration information
  852. //
  853. memset(Wnode, 0, sizeof(WNODE_HEADER));
  854. Wnode->WnodeHeader.Guid = RegChangeGuid;
  855. Wnode->WnodeHeader.BufferSize = WnodeSize;
  856. Wnode->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  857. WNODE_FLAG_EVENT_ITEM;
  858. Wnode->OffsetInstanceName = sizeof(WNODE_SINGLE_INSTANCE);
  859. Wnode->DataBlockOffset = ((Wnode->OffsetInstanceName +
  860. sizeof(USHORT) + sizeof(REGUPDATENAME) + 7) & ~7);
  861. Wnode->SizeDataBlock = DataBlockSize;
  862. InstanceName = (PWCHAR)OffsetToPtr(Wnode, Wnode->OffsetInstanceName);
  863. *InstanceName++ = sizeof(REGUPDATENAME);
  864. wcscpy(InstanceName, REGUPDATENAME);
  865. RegInfo = (PMSWmi_GuidRegistrationInfo)OffsetToPtr(Wnode,
  866. Wnode->DataBlockOffset);
  867. RegInfo->Operation = NotificationType;
  868. RegInfo->GuidCount = GuidCount;
  869. GuidPtr = (LPGUID)RegInfo->GuidList;
  870. for (i = 0; i < GuidCount; i++)
  871. {
  872. *GuidPtr++ = *GuidList[i].Guid;
  873. }
  874. WmipProcessEvent((PWNODE_HEADER)Wnode, TRUE, FALSE);
  875. WmipFree(WnodeBuffer);
  876. }
  877. }
  878. void WmipGenerateBinaryMofNotification(
  879. PBINSTANCESET BinaryMofInstanceSet,
  880. LPCGUID Guid
  881. )
  882. {
  883. PWNODE_SINGLE_INSTANCE Wnode;
  884. ULONG ImagePathLen, ResourceNameLen, InstanceNameLen, BufferSize;
  885. PWCHAR Ptr;
  886. ULONG i;
  887. PAGED_CODE();
  888. if (BinaryMofInstanceSet->Count == 0)
  889. {
  890. return;
  891. }
  892. for (i = 0; i < BinaryMofInstanceSet->Count; i++)
  893. {
  894. ImagePathLen = sizeof(USHORT);
  895. InstanceNameLen = (sizeof(USHORT) + 7) & ~7;
  896. if (BinaryMofInstanceSet->Flags & IS_INSTANCE_STATICNAMES)
  897. {
  898. ResourceNameLen = ((wcslen(BinaryMofInstanceSet->IsStaticNames->StaticNamePtr[i])+1) * sizeof(WCHAR)) + sizeof(USHORT);
  899. } else if (BinaryMofInstanceSet->Flags & IS_INSTANCE_BASENAME) {
  900. ResourceNameLen = (((wcslen(BinaryMofInstanceSet->IsBaseName->BaseName) +
  901. MAXBASENAMESUFFIXSIZE) * sizeof(WCHAR)) + sizeof(USHORT));
  902. } else {
  903. return;
  904. }
  905. BufferSize = FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData) +
  906. InstanceNameLen +
  907. ImagePathLen +
  908. ResourceNameLen;
  909. Wnode = (PWNODE_SINGLE_INSTANCE)WmipAlloc(BufferSize);
  910. if (Wnode != NULL)
  911. {
  912. Wnode->WnodeHeader.BufferSize = BufferSize;
  913. Wnode->WnodeHeader.ProviderId = MOFEVENT_ACTION_BINARY_MOF;
  914. Wnode->WnodeHeader.Version = 1;
  915. Wnode->WnodeHeader.Linkage = 0;
  916. Wnode->WnodeHeader.Flags = (WNODE_FLAG_EVENT_ITEM |
  917. WNODE_FLAG_SINGLE_INSTANCE);
  918. memcpy(&Wnode->WnodeHeader.Guid,
  919. Guid,
  920. sizeof(GUID));
  921. WmiInsertTimestamp(&Wnode->WnodeHeader);
  922. Wnode->OffsetInstanceName = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  923. VariableData);
  924. Wnode->DataBlockOffset = Wnode->OffsetInstanceName +
  925. InstanceNameLen;
  926. Wnode->SizeDataBlock = ImagePathLen + ResourceNameLen;
  927. Ptr = (PWCHAR)&Wnode->VariableData;
  928. *Ptr++ = 0; // Empty instance name
  929. Ptr = (PWCHAR)OffsetToPtr(Wnode, Wnode->DataBlockOffset);
  930. *Ptr++ = 0; // Empty image path
  931. // Instance name for binary mof resource
  932. if (BinaryMofInstanceSet->Flags & IS_INSTANCE_STATICNAMES)
  933. {
  934. *Ptr++ = (USHORT)(ResourceNameLen - sizeof(USHORT));
  935. wcscpy(Ptr, BinaryMofInstanceSet->IsStaticNames->StaticNamePtr[i]);
  936. } else if (BinaryMofInstanceSet->Flags & IS_INSTANCE_BASENAME) {
  937. *Ptr = (USHORT)swprintf(Ptr+1,
  938. L"%ws%d",
  939. BinaryMofInstanceSet->IsBaseName->BaseName,
  940. BinaryMofInstanceSet->IsBaseName->BaseIndex+i) * sizeof(WCHAR);
  941. }
  942. WmipProcessEvent((PWNODE_HEADER)Wnode, TRUE, FALSE);
  943. WmipFree(Wnode);
  944. }
  945. }
  946. }
  947. void WmipGenerateMofResourceNotification(
  948. LPWSTR ImagePath,
  949. LPWSTR ResourceName,
  950. LPCGUID Guid,
  951. ULONG ActionCode
  952. )
  953. {
  954. PWNODE_SINGLE_INSTANCE Wnode;
  955. ULONG ImagePathLen, ResourceNameLen, InstanceNameLen, BufferSize;
  956. PWCHAR Ptr;
  957. PAGED_CODE();
  958. ImagePathLen = (wcslen(ImagePath) + 2) * sizeof(WCHAR);
  959. ResourceNameLen = (wcslen(ResourceName) + 2) * sizeof(WCHAR);
  960. InstanceNameLen = ( sizeof(USHORT)+7 ) & ~7;
  961. BufferSize = FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData) +
  962. InstanceNameLen +
  963. ImagePathLen +
  964. ResourceNameLen;
  965. Wnode = (PWNODE_SINGLE_INSTANCE)WmipAlloc(BufferSize);
  966. if (Wnode != NULL)
  967. {
  968. Wnode->WnodeHeader.BufferSize = BufferSize;
  969. Wnode->WnodeHeader.ProviderId = ActionCode;
  970. Wnode->WnodeHeader.Version = 1;
  971. Wnode->WnodeHeader.Linkage = 0;
  972. Wnode->WnodeHeader.Flags = (WNODE_FLAG_EVENT_ITEM |
  973. WNODE_FLAG_SINGLE_INSTANCE |
  974. WNODE_FLAG_INTERNAL);
  975. memcpy(&Wnode->WnodeHeader.Guid,
  976. Guid,
  977. sizeof(GUID));
  978. WmiInsertTimestamp(&Wnode->WnodeHeader);
  979. Wnode->OffsetInstanceName = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  980. VariableData);
  981. Wnode->DataBlockOffset = Wnode->OffsetInstanceName + InstanceNameLen;
  982. Wnode->SizeDataBlock = ImagePathLen + ResourceNameLen;
  983. Ptr = (PWCHAR)&Wnode->VariableData;
  984. *Ptr = 0; // Empty instance name
  985. // ImagePath name
  986. Ptr = (PWCHAR)OffsetToPtr(Wnode, Wnode->DataBlockOffset);
  987. ImagePathLen -= sizeof(USHORT);
  988. *Ptr++ = (USHORT)ImagePathLen;
  989. memcpy(Ptr, ImagePath, ImagePathLen);
  990. Ptr += (ImagePathLen / sizeof(WCHAR));
  991. // MofResource Name
  992. ResourceNameLen -= sizeof(USHORT);
  993. *Ptr++ = (USHORT)ResourceNameLen;
  994. memcpy(Ptr, ResourceName, ResourceNameLen);
  995. WmipProcessEvent((PWNODE_HEADER)Wnode, TRUE, FALSE);
  996. WmipFree(Wnode);
  997. }
  998. }
  999. void WmipGenerateRegistrationNotification(
  1000. PBDATASOURCE DataSource,
  1001. NOTIFICATIONTYPES NotificationType
  1002. )
  1003. {
  1004. PTRCACHE *Guids;
  1005. ULONG GuidCount, GuidMax;
  1006. PLIST_ENTRY InstanceSetList;
  1007. PBINSTANCESET InstanceSet;
  1008. LPGUID Guid;
  1009. PAGED_CODE();
  1010. WmipReferenceDS(DataSource);
  1011. //
  1012. // Loop over all instance sets for this data source
  1013. //
  1014. GuidCount = 0;
  1015. GuidMax = 0;
  1016. Guids = NULL;
  1017. InstanceSetList = DataSource->ISHead.Flink;
  1018. while (InstanceSetList != &DataSource->ISHead)
  1019. {
  1020. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  1021. INSTANCESET,
  1022. DSISList);
  1023. //
  1024. // Cache the guid and instance set so we can send registration
  1025. // change notifications
  1026. //
  1027. Guid = &InstanceSet->GuidEntry->Guid;
  1028. WmipCachePtrs(Guid,
  1029. InstanceSet,
  1030. &GuidCount,
  1031. &GuidMax,
  1032. &Guids);
  1033. //
  1034. // If we are adding a guid and it is already enabled then we
  1035. // need to send an enable irp. Likewise if the guid is being
  1036. // removed and is enabled then we need to send a disable
  1037. //
  1038. if (NotificationType == RegistrationAdd)
  1039. {
  1040. WmipEnableCollectionForNewGuid(Guid, InstanceSet);
  1041. } else if (NotificationType == RegistrationDelete) {
  1042. WmipDisableCollectionForRemovedGuid(Guid, InstanceSet);
  1043. }
  1044. //
  1045. // If this is a Trace Provider, then add the Unregistering Guids
  1046. // to the GuidMapList if a logger session is active.
  1047. // If there is a notification entry for this Guid, then we take
  1048. // it that there is a logger session active.
  1049. //
  1050. if ( (NotificationType == RegistrationDelete) &&
  1051. (InstanceSet->Flags & IS_TRACED) )
  1052. {
  1053. WmipSaveTraceGuidMap(Guid, InstanceSet);
  1054. }
  1055. InstanceSetList = InstanceSetList->Flink;
  1056. }
  1057. //
  1058. // Send out event that informs about guid registration changes
  1059. //
  1060. WmipSendGuidUpdateNotifications(NotificationType,
  1061. GuidCount,
  1062. Guids);
  1063. if (Guids != NULL)
  1064. {
  1065. WmipFree(Guids);
  1066. }
  1067. WmipUnreferenceDS(DataSource);
  1068. }
  1069. NTSTATUS WmipAddMofResource(
  1070. PBDATASOURCE DataSource,
  1071. LPWSTR ImagePath,
  1072. BOOLEAN IsImagePath,
  1073. LPWSTR MofResourceName,
  1074. PBOOLEAN NewMofResource
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine will build MOFCLASSINFO structures for each guid that is
  1079. described in the MOF for the data source. If there are any errors in the
  1080. mof resource then no mof information from the resource is retained and the
  1081. resource data is unloaded.
  1082. Arguments:
  1083. DataSource is the data source structure of the data provider
  1084. ImagePath points at a string that has the full path to the image
  1085. file that contains the MOF resource
  1086. MofResourceName points at a string that has the name of the MOF
  1087. resource
  1088. Return Value:
  1089. --*/
  1090. {
  1091. PMOFRESOURCE MofResource;
  1092. ULONG NewMofResourceCount;
  1093. ULONG i;
  1094. BOOLEAN FreeBuffer;
  1095. PAGED_CODE();
  1096. MofResource = WmipFindMRByNames(ImagePath,
  1097. MofResourceName);
  1098. if (MofResource == NULL)
  1099. {
  1100. //
  1101. // Mof Resource not previously specified, so allocate a new one
  1102. MofResource = WmipAllocMofResource();
  1103. if (MofResource == NULL)
  1104. {
  1105. return(STATUS_INSUFFICIENT_RESOURCES);
  1106. }
  1107. if (IsImagePath)
  1108. {
  1109. MofResource->Flags |= MR_FLAG_USER_MODE;
  1110. }
  1111. MofResource->RegistryPath = WmipAlloc((wcslen(ImagePath)+1) * sizeof(WCHAR));
  1112. MofResource->MofResourceName = WmipAlloc((wcslen(MofResourceName) + 1) * sizeof(WCHAR));
  1113. if ((MofResource->RegistryPath == NULL) ||
  1114. (MofResource->MofResourceName == NULL))
  1115. {
  1116. //
  1117. // Allocation cleanup routine will free any memory alloced for MR
  1118. WmipUnreferenceMR(MofResource);
  1119. return(STATUS_INSUFFICIENT_RESOURCES);
  1120. }
  1121. wcscpy(MofResource->RegistryPath, ImagePath);
  1122. wcscpy(MofResource->MofResourceName, MofResourceName);
  1123. WmipEnterSMCritSection();
  1124. InsertTailList(WmipMRHeadPtr, &MofResource->MainMRList);
  1125. WmipLeaveSMCritSection();
  1126. *NewMofResource = TRUE;
  1127. } else {
  1128. *NewMofResource = FALSE;
  1129. }
  1130. if (DataSource != NULL)
  1131. {
  1132. WmipEnterSMCritSection();
  1133. for (i = 0; i < DataSource->MofResourceCount; i++)
  1134. {
  1135. if (DataSource->MofResources[i] == MofResource)
  1136. {
  1137. //
  1138. // If this mof resource is already been registered for
  1139. // this data source then we do not need to worry about
  1140. // it anymore.
  1141. //
  1142. WmipUnreferenceMR(MofResource);
  1143. break;
  1144. }
  1145. if (DataSource->MofResources[i] == NULL)
  1146. {
  1147. DataSource->MofResources[i] = MofResource;
  1148. break;
  1149. }
  1150. }
  1151. if (i == DataSource->MofResourceCount)
  1152. {
  1153. NewMofResourceCount = DataSource->MofResourceCount +
  1154. AVGMOFRESOURCECOUNT;
  1155. if (DataSource->MofResources !=
  1156. DataSource->StaticMofResources)
  1157. {
  1158. FreeBuffer = TRUE;
  1159. } else {
  1160. FreeBuffer = FALSE;
  1161. }
  1162. if (WmipRealloc((PVOID *)&DataSource->MofResources,
  1163. DataSource->MofResourceCount * sizeof(PMOFRESOURCE),
  1164. NewMofResourceCount * sizeof(PMOFRESOURCE),
  1165. FreeBuffer ) )
  1166. {
  1167. DataSource->MofResourceCount = NewMofResourceCount;
  1168. DataSource->MofResources[i] = MofResource;
  1169. }
  1170. }
  1171. WmipLeaveSMCritSection();
  1172. }
  1173. return(STATUS_SUCCESS);
  1174. }
  1175. NTSTATUS WmipAddDataSource(
  1176. IN PREGENTRY RegEntry,
  1177. IN PWMIREGINFOW WmiRegInfo,
  1178. IN ULONG BufferSize,
  1179. IN PWCHAR RegPath,
  1180. IN PWCHAR ResourceName,
  1181. IN PWMIGUIDOBJECT RequestObject,
  1182. IN BOOLEAN IsUserMode
  1183. )
  1184. /*+++
  1185. Routine Description:
  1186. This routine will register a information in the WMI database for a
  1187. new DataSource or add additional guids to an existing data source.
  1188. Arguments:
  1189. RegEntry is the regentry for the data provider
  1190. WmiRegInfo is the registration information to register
  1191. BufferSize is the size of WmiRegInfo in bytes
  1192. RegPath is a pointer into WmiRegInfo to a counted string that is the
  1193. registry path (or image path for UM providers).
  1194. ResourceName is a pointer into WmiRegInfo to a counted string that is the
  1195. resource name
  1196. RequestObject is the request object associated with the UM provider.
  1197. If this is NULL then the registration is for a driver
  1198. Return Value:
  1199. STATUS_SUCCESS or an error code
  1200. ---*/
  1201. {
  1202. PBDATASOURCE DataSource;
  1203. PWMIREGGUID RegGuid;
  1204. ULONG i;
  1205. NTSTATUS Status, Status2;
  1206. PBINSTANCESET InstanceSet;
  1207. PBINSTANCESET BinaryMofInstanceSet = NULL;
  1208. PWCHAR MofRegistryPath;
  1209. PWCHAR MofResourceName;
  1210. BOOLEAN AppendToDS;
  1211. BOOLEAN NewMofResource;
  1212. UCHAR WnodeBuffer[sizeof(WNODE_HEADER) + AVGGUIDSPERDS * sizeof(GUID)];
  1213. PWNODE_HEADER Wnode;
  1214. PAGED_CODE();
  1215. if (RegEntry->DataSource != NULL)
  1216. {
  1217. DataSource = RegEntry->DataSource;
  1218. WmipAssert(DataSource != NULL);
  1219. AppendToDS = TRUE;
  1220. } else {
  1221. DataSource = WmipAllocDataSource();
  1222. AppendToDS = FALSE;
  1223. }
  1224. if (DataSource != NULL)
  1225. {
  1226. //
  1227. // Loop over each guid being registered and build instance sets and
  1228. // guid entries.
  1229. //
  1230. if (! AppendToDS)
  1231. {
  1232. DataSource->ProviderId = RegEntry->ProviderId;
  1233. if (RequestObject != NULL)
  1234. {
  1235. DataSource->Flags |= DS_USER_MODE;
  1236. DataSource->RequestObject = RequestObject;
  1237. } else {
  1238. DataSource->Flags |= DS_KERNEL_MODE;
  1239. }
  1240. }
  1241. RegGuid = WmiRegInfo->WmiRegGuid;
  1242. for (i = 0; i < WmiRegInfo->GuidCount; i++, RegGuid++)
  1243. {
  1244. if (! (RegGuid->Flags & WMIREG_FLAG_REMOVE_GUID))
  1245. {
  1246. //
  1247. // Only trace control guids are registered. Trace transaction
  1248. // guids will not be registered since they can not be enabled or
  1249. // disabled individually. They will be kept on the ControlGuids'
  1250. // instance set structure.
  1251. //
  1252. if ( ( (RegGuid->Flags & WMIREG_FLAG_TRACED_GUID) != WMIREG_FLAG_TRACED_GUID ) ||
  1253. (RegGuid->Flags & WMIREG_FLAG_TRACE_CONTROL_GUID) )
  1254. {
  1255. //
  1256. // Allocate an instance set for this new set of instances
  1257. //
  1258. InstanceSet = WmipAllocInstanceSet();
  1259. if (InstanceSet == NULL)
  1260. {
  1261. WmipUnreferenceDS(DataSource);
  1262. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAddDataSource: WmipAllocInstanceSet failed\n"));
  1263. return(STATUS_INSUFFICIENT_RESOURCES);
  1264. }
  1265. //
  1266. // We will allocate a proper guid entry for the instance
  1267. // set when the data source gets linked into the main data
  1268. // source list so we stash a pointer to the guid away now.
  1269. //
  1270. InstanceSet->GuidEntry = (PBGUIDENTRY)&RegGuid->Guid;
  1271. //
  1272. // Minimally initialize the InstanceSet and add it to
  1273. // the DataSource's list of InstanceSets. We do this
  1274. // first so that if there is any failure below and
  1275. // the DataSource can'e be fully registered the instance
  1276. // set and guid entry will be free when the DataSource is
  1277. // freed.
  1278. //
  1279. InstanceSet->DataSource = DataSource;
  1280. InstanceSet->Flags |= IS_NEWLY_REGISTERED;
  1281. Status = WmipBuildInstanceSet(RegGuid,
  1282. WmiRegInfo,
  1283. BufferSize,
  1284. InstanceSet,
  1285. RegEntry->ProviderId,
  1286. RegPath);
  1287. //
  1288. // If this is the guid that represents the binary mof data
  1289. // then remember the InstanceSet for later
  1290. //
  1291. if (IsEqualGUID(&RegGuid->Guid, &WmipBinaryMofGuid))
  1292. {
  1293. BinaryMofInstanceSet = InstanceSet;
  1294. }
  1295. InsertHeadList(&DataSource->ISHead, &InstanceSet->DSISList);
  1296. if (! NT_SUCCESS(Status))
  1297. {
  1298. WmipUnreferenceDS(DataSource);
  1299. return(Status);
  1300. }
  1301. }
  1302. }
  1303. }
  1304. //
  1305. // Now that the instance sets have been built successfully we
  1306. // can link them into the master list.
  1307. //
  1308. WmipEnterSMCritSection();
  1309. Status = WmipLinkDataSourceToList(DataSource, (BOOLEAN)(! AppendToDS));
  1310. WmipLeaveSMCritSection();
  1311. if (! NT_SUCCESS(Status))
  1312. {
  1313. WmipUnreferenceDS(DataSource);
  1314. return(Status);
  1315. }
  1316. RegEntry->DataSource = DataSource;
  1317. //
  1318. // We need to send out notification of new guids and mofs.
  1319. //
  1320. if (BinaryMofInstanceSet != NULL)
  1321. {
  1322. //
  1323. // Send binary mof guid arrival notification
  1324. //
  1325. WmipGenerateBinaryMofNotification(BinaryMofInstanceSet,
  1326. &GUID_MOF_RESOURCE_ADDED_NOTIFICATION);
  1327. }
  1328. //
  1329. // Convert Registry path to a sz string so we can assign it to
  1330. // the DS if the DS is a new one
  1331. //
  1332. if (RegPath != NULL)
  1333. {
  1334. MofRegistryPath = WmipCountedToSz(RegPath);
  1335. } else {
  1336. MofRegistryPath = NULL;
  1337. }
  1338. if ((AppendToDS == FALSE) && (MofRegistryPath != NULL))
  1339. {
  1340. DataSource->RegistryPath = MofRegistryPath;
  1341. }
  1342. if (ResourceName != NULL)
  1343. {
  1344. MofResourceName = WmipCountedToSz(ResourceName);
  1345. } else {
  1346. MofResourceName = NULL;
  1347. }
  1348. //
  1349. // Finally if we created a new data source we need to register
  1350. // the mof for it. Only register those that have a RegistryPath
  1351. // and a ResourceName
  1352. //
  1353. if ((MofRegistryPath != NULL) &&
  1354. (*MofRegistryPath != 0) &&
  1355. (MofResourceName != NULL) &&
  1356. (*MofResourceName != 0))
  1357. {
  1358. //
  1359. // If a mof is specified then add it to the list
  1360. //
  1361. Status2 = WmipAddMofResource(DataSource,
  1362. MofRegistryPath,
  1363. IsUserMode,
  1364. MofResourceName,
  1365. &NewMofResource);
  1366. if (NT_SUCCESS(Status2) && NewMofResource)
  1367. {
  1368. //
  1369. // We successfully added a brand new MOF resource so
  1370. // we need to fire an event for wbem.
  1371. //
  1372. WmipGenerateMofResourceNotification(MofRegistryPath,
  1373. MofResourceName,
  1374. &GUID_MOF_RESOURCE_ADDED_NOTIFICATION,
  1375. IsUserMode ?
  1376. MOFEVENT_ACTION_IMAGE_PATH :
  1377. MOFEVENT_ACTION_REGISTRY_PATH);
  1378. }
  1379. }
  1380. //
  1381. // Clean up registry path and mof resource name strings
  1382. //
  1383. if ((MofRegistryPath != NULL) && AppendToDS)
  1384. {
  1385. //
  1386. // Only free if registry path not saved in DataSource
  1387. //
  1388. WmipAssert(MofRegistryPath != DataSource->RegistryPath);
  1389. WmipFree(MofRegistryPath);
  1390. }
  1391. if (MofResourceName != NULL)
  1392. {
  1393. WmipFree(MofResourceName);
  1394. }
  1395. //
  1396. // Send a notification about new/changed guids
  1397. //
  1398. WmipGenerateRegistrationNotification(DataSource,
  1399. RegistrationAdd);
  1400. } else {
  1401. Status = STATUS_INSUFFICIENT_RESOURCES;
  1402. }
  1403. return(Status);
  1404. }
  1405. PBINSTANCESET WmipFindISInDSByGuid(
  1406. PBDATASOURCE DataSource,
  1407. LPGUID Guid
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This routine will find the InstanceSet in the passed DataSource for the
  1412. guid passed.
  1413. This routine assumes that the SM critical section is held before it is
  1414. called.
  1415. Arguments:
  1416. DataSource is the data source from which the guid is to be removed
  1417. Guid has the Guid for the InstanceSet to find
  1418. Return Value:
  1419. --*/
  1420. {
  1421. PLIST_ENTRY InstanceSetList;
  1422. PBINSTANCESET InstanceSet;
  1423. PAGED_CODE();
  1424. InstanceSetList = DataSource->ISHead.Flink;
  1425. while (InstanceSetList != &DataSource->ISHead)
  1426. {
  1427. InstanceSet = CONTAINING_RECORD(InstanceSetList,
  1428. INSTANCESET,
  1429. DSISList);
  1430. if ((InstanceSet->GuidEntry != NULL) &&
  1431. (IsEqualGUID(Guid, &InstanceSet->GuidEntry->Guid)))
  1432. {
  1433. WmipReferenceIS(InstanceSet);
  1434. return(InstanceSet);
  1435. }
  1436. InstanceSetList = InstanceSetList->Flink;
  1437. }
  1438. return(NULL);
  1439. }
  1440. ULONG WmipUpdateAddGuid(
  1441. PBDATASOURCE DataSource,
  1442. PWMIREGGUID RegGuid,
  1443. PWMIREGINFO WmiRegInfo,
  1444. ULONG BufferSize,
  1445. PBINSTANCESET *AddModInstanceSet
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. This routine will add a new guid for the data source and send notification
  1450. This routine assumes that the SM critical section is held before it is
  1451. called.
  1452. Arguments:
  1453. DataSource is the data source from which the guid is to be removed
  1454. RegGuid has the Guid update data structure
  1455. WmiRegInfo points at the beginning of the registration update info
  1456. Return Value:
  1457. 1 if guid was added or 0
  1458. --*/
  1459. {
  1460. PBINSTANCESET InstanceSet;
  1461. LPGUID Guid = &RegGuid->Guid;
  1462. NTSTATUS Status;
  1463. PAGED_CODE();
  1464. //
  1465. // Allocate an instance set for this new set of instances
  1466. InstanceSet = WmipAllocInstanceSet();
  1467. if (InstanceSet == NULL)
  1468. {
  1469. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipUpdateAddGuid: WmipAllocInstanceSet failed\n"));
  1470. return(0);
  1471. }
  1472. //
  1473. // We will allocate a proper guid entry for the instance set when
  1474. // the data source gets linked into the main data source list so
  1475. // we stash a pointer to the guid away now.
  1476. InstanceSet->GuidEntry = (PBGUIDENTRY)Guid;
  1477. //
  1478. // Minimally initialize the InstanceSet and add it to the DataSource's
  1479. // list of InstanceSets. We do this first so that if there is any
  1480. // failure below and the DataSource can'e be fully registered the
  1481. // instance set and guid entry will be free when the DataSource is
  1482. // freed.
  1483. InstanceSet->DataSource = DataSource;
  1484. InstanceSet->Flags |= IS_NEWLY_REGISTERED;
  1485. InsertHeadList(&DataSource->ISHead, &InstanceSet->DSISList);
  1486. Status = WmipBuildInstanceSet(RegGuid,
  1487. WmiRegInfo,
  1488. BufferSize,
  1489. InstanceSet,
  1490. DataSource->ProviderId,
  1491. DataSource->RegistryPath);
  1492. if (! NT_SUCCESS(Status))
  1493. {
  1494. WmipUnreferenceIS(InstanceSet);
  1495. return(0);
  1496. }
  1497. Status = WmipLinkDataSourceToList(DataSource,
  1498. FALSE);
  1499. *AddModInstanceSet = InstanceSet;
  1500. return( NT_SUCCESS(Status) ? 1 : 0);
  1501. }
  1502. #if DBG
  1503. PTCHAR GuidToString(
  1504. PTCHAR s,
  1505. LPGUID piid
  1506. )
  1507. {
  1508. PAGED_CODE();
  1509. swprintf(s, TEXT("%x-%x-%x-%x%x%x%x%x%x%x%x"),
  1510. piid->Data1, piid->Data2,
  1511. piid->Data3,
  1512. piid->Data4[0], piid->Data4[1],
  1513. piid->Data4[2], piid->Data4[3],
  1514. piid->Data4[4], piid->Data4[5],
  1515. piid->Data4[6], piid->Data4[7]);
  1516. return(s);
  1517. }
  1518. #endif
  1519. BOOLEAN WmipUpdateRemoveGuid(
  1520. PBDATASOURCE DataSource,
  1521. PWMIREGGUID RegGuid,
  1522. PBINSTANCESET *AddModInstanceSet
  1523. )
  1524. /*++
  1525. Routine Description:
  1526. This routine will remove the guid for the data source and send notification
  1527. This routine assumes that the SM critical section is held before it is
  1528. called.
  1529. Arguments:
  1530. DataSource is the data source from which the guid is to be removed
  1531. RegGuid has the Guid update data structure
  1532. Return Value:
  1533. TRUE if guid was removed else FALSE
  1534. --*/
  1535. {
  1536. PBINSTANCESET InstanceSet;
  1537. LPGUID Guid = &RegGuid->Guid;
  1538. BOOLEAN SendNotification;
  1539. PAGED_CODE();
  1540. InstanceSet = WmipFindISInDSByGuid(DataSource,
  1541. Guid);
  1542. if (InstanceSet != NULL)
  1543. {
  1544. WmipUnreferenceIS(InstanceSet);
  1545. *AddModInstanceSet = InstanceSet;
  1546. SendNotification = TRUE;
  1547. } else {
  1548. #if DBG
  1549. TCHAR s[256];
  1550. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: UpdateRemoveGuid %ws not registered by %ws\n",
  1551. GuidToString(s, Guid), DataSource->RegistryPath));
  1552. #endif
  1553. SendNotification = FALSE;
  1554. }
  1555. return(SendNotification);
  1556. }
  1557. BOOLEAN WmipIsEqualInstanceSets(
  1558. PBINSTANCESET InstanceSet1,
  1559. PBINSTANCESET InstanceSet2
  1560. )
  1561. {
  1562. ULONG i;
  1563. ULONG Flags1, Flags2;
  1564. PAGED_CODE();
  1565. Flags1 = InstanceSet1->Flags & ~(IS_ENABLE_EVENT | IS_ENABLE_COLLECTION);
  1566. Flags2 = InstanceSet2->Flags & ~(IS_ENABLE_EVENT | IS_ENABLE_COLLECTION);
  1567. if (Flags1 == Flags2)
  1568. {
  1569. if (InstanceSet1->Flags & IS_INSTANCE_BASENAME)
  1570. {
  1571. if ((InstanceSet1->Count == InstanceSet2->Count) &&
  1572. (wcscmp(InstanceSet1->IsBaseName->BaseName,
  1573. InstanceSet1->IsBaseName->BaseName) == 0))
  1574. {
  1575. return(TRUE);
  1576. }
  1577. } else if (InstanceSet1->Flags & IS_INSTANCE_BASENAME) {
  1578. if (InstanceSet1->Count == InstanceSet2->Count)
  1579. {
  1580. for (i = 0; i < InstanceSet1->Count; i++)
  1581. {
  1582. if (wcscmp(InstanceSet1->IsStaticNames->StaticNamePtr[i],
  1583. InstanceSet2->IsStaticNames->StaticNamePtr[i]) != 0)
  1584. {
  1585. return(FALSE);
  1586. }
  1587. }
  1588. return(TRUE);
  1589. }
  1590. } else {
  1591. return(TRUE);
  1592. }
  1593. }
  1594. return(FALSE);
  1595. }
  1596. ULONG WmipUpdateModifyGuid(
  1597. PBDATASOURCE DataSource,
  1598. PWMIREGGUID RegGuid,
  1599. PWMIREGINFO WmiRegInfo,
  1600. ULONG BufferSize,
  1601. PBINSTANCESET *AddModInstanceSet
  1602. )
  1603. /*++
  1604. Routine Description:
  1605. This routine will modify an existing guid for the data source and
  1606. send notification
  1607. This routine assumes that the SM critical section is held before it is
  1608. called.
  1609. HEHEY: If a guid was opened when it was registered as cheap, but closed
  1610. when the guid was registered expensive a disable collection will
  1611. NOT be sent. Conversely if a guid was opened when it was
  1612. registered as expensive and is closed when registed as cheap a
  1613. disable collection may be sent.
  1614. Arguments:
  1615. DataSource is the data source from which the guid is to be removed
  1616. RegGuid has the Guid update data structure
  1617. WmiRegInfo points at the beginning of the registration update info
  1618. Return Value:
  1619. 1 if guid was added or 2 if guid was modified else 0
  1620. --*/
  1621. {
  1622. PBINSTANCESET InstanceSet;
  1623. LPGUID Guid = &RegGuid->Guid;
  1624. ULONG SendNotification;
  1625. PBINSTANCESET InstanceSetNew;
  1626. PVOID ToFree;
  1627. NTSTATUS Status;
  1628. PAGED_CODE();
  1629. InstanceSet = WmipFindISInDSByGuid(DataSource,
  1630. Guid);
  1631. if (InstanceSet != NULL)
  1632. {
  1633. //
  1634. // See if anything has changed with the instance names and if not
  1635. // then don't bother to recreate the instance set
  1636. InstanceSetNew = WmipAllocInstanceSet();
  1637. if (InstanceSetNew == NULL)
  1638. {
  1639. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: UpdateModifyGuid Not enough memory to alloc InstanceSet\n"));
  1640. WmipUnreferenceIS(InstanceSet);
  1641. return(0);
  1642. }
  1643. Status = WmipBuildInstanceSet(RegGuid,
  1644. WmiRegInfo,
  1645. BufferSize,
  1646. InstanceSetNew,
  1647. DataSource->ProviderId,
  1648. DataSource->RegistryPath);
  1649. if (NT_SUCCESS(Status))
  1650. {
  1651. if (! WmipIsEqualInstanceSets(InstanceSet,
  1652. InstanceSetNew))
  1653. {
  1654. ToFree = NULL;
  1655. if (InstanceSet->IsBaseName != NULL) {
  1656. ToFree = (PVOID)InstanceSet->IsBaseName;
  1657. }
  1658. RemoveEntryList(&InstanceSet->GuidISList);
  1659. Status = WmipBuildInstanceSet(RegGuid,
  1660. WmiRegInfo,
  1661. BufferSize,
  1662. InstanceSet,
  1663. DataSource->ProviderId,
  1664. DataSource->RegistryPath);
  1665. if (NT_SUCCESS(Status))
  1666. {
  1667. InsertHeadList(&InstanceSet->GuidEntry->ISHead,
  1668. &InstanceSet->GuidISList);
  1669. } else {
  1670. //
  1671. // It is sad, but we weren't able to rebuild the instance
  1672. // set so the old one is gone. This is an unlikely
  1673. // situation that can really only occur when the machine
  1674. // is out of memory.
  1675. //
  1676. }
  1677. if (ToFree != NULL)
  1678. {
  1679. WmipFree(ToFree);
  1680. }
  1681. *AddModInstanceSet = InstanceSet;
  1682. SendNotification = 2;
  1683. } else {
  1684. //
  1685. // The InstanceSets are identical so just delete the new one
  1686. SendNotification = 0;
  1687. }
  1688. WmipUnreferenceIS(InstanceSetNew);
  1689. WmipUnreferenceIS(InstanceSet);
  1690. } else {
  1691. //
  1692. // We could not parse the new instance set so leave the old
  1693. // one alone
  1694. //
  1695. WmipUnreferenceIS(InstanceSet);
  1696. WmipUnreferenceIS(InstanceSetNew);
  1697. SendNotification = FALSE;
  1698. }
  1699. } else {
  1700. //
  1701. // Guid not already registered so try to add it
  1702. SendNotification = WmipUpdateAddGuid(DataSource,
  1703. RegGuid,
  1704. WmiRegInfo,
  1705. BufferSize,
  1706. AddModInstanceSet);
  1707. }
  1708. return(SendNotification);
  1709. }
  1710. void WmipCachePtrs(
  1711. LPGUID Ptr1,
  1712. PBINSTANCESET Ptr2,
  1713. ULONG *PtrCount,
  1714. ULONG *PtrMax,
  1715. PTRCACHE **PtrArray
  1716. )
  1717. {
  1718. PTRCACHE *NewPtrArray;
  1719. PTRCACHE *OldPtrArray;
  1720. PTRCACHE *ActualPtrArray;
  1721. PAGED_CODE();
  1722. if (*PtrCount == *PtrMax)
  1723. {
  1724. NewPtrArray = WmipAlloc((*PtrMax + PTRCACHEGROWSIZE) * sizeof(PTRCACHE));
  1725. if (NewPtrArray != NULL)
  1726. {
  1727. OldPtrArray = *PtrArray;
  1728. memcpy(NewPtrArray, OldPtrArray, *PtrMax * sizeof(PTRCACHE));
  1729. *PtrMax += PTRCACHEGROWSIZE;
  1730. if (*PtrArray != NULL)
  1731. {
  1732. WmipFree(*PtrArray);
  1733. }
  1734. *PtrArray = NewPtrArray;
  1735. } else {
  1736. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Couldn't alloc memory for pointer cache\n"));
  1737. return;
  1738. }
  1739. }
  1740. ActualPtrArray = *PtrArray;
  1741. ActualPtrArray[*PtrCount].Guid = Ptr1;
  1742. ActualPtrArray[*PtrCount].InstanceSet = Ptr2;
  1743. (*PtrCount)++;
  1744. }
  1745. NTSTATUS WmipUpdateDataSource(
  1746. PREGENTRY RegEntry,
  1747. PWMIREGINFOW WmiRegInfo,
  1748. ULONG RetSize
  1749. )
  1750. /*++
  1751. Routine Description:
  1752. This routine will update a data source with changes to already registered
  1753. guids.
  1754. Arguments:
  1755. ProviderId is the provider id of the DataSource whose guids are being
  1756. updated.
  1757. WmiRegInfo has the registration update information
  1758. RetSize has the size of the registration information returned from
  1759. kernel mode.
  1760. Return Value:
  1761. --*/
  1762. {
  1763. PBDATASOURCE DataSource;
  1764. PUCHAR RegInfo;
  1765. ULONG RetSizeLeft;
  1766. ULONG i;
  1767. PWMIREGGUID RegGuid;
  1768. ULONG NextWmiRegInfo;
  1769. PTRCACHE *RemovedGuids;
  1770. PTRCACHE *AddedGuids;
  1771. PTRCACHE *ModifiedGuids;
  1772. ULONG RemovedGuidCount;
  1773. ULONG AddedGuidCount;
  1774. ULONG ModifiedGuidCount;
  1775. ULONG RemovedGuidMax;
  1776. ULONG AddedGuidMax;
  1777. ULONG ModifiedGuidMax;
  1778. PBINSTANCESET InstanceSet;
  1779. ULONG Action;
  1780. PAGED_CODE();
  1781. DataSource = RegEntry->DataSource;
  1782. if (DataSource == NULL)
  1783. {
  1784. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: RegEntry %p requested update but is not registered\n",
  1785. RegEntry));
  1786. return(STATUS_OBJECT_NAME_NOT_FOUND);
  1787. }
  1788. WmipReferenceDS(DataSource);
  1789. AddedGuidCount = 0;
  1790. ModifiedGuidCount = 0;
  1791. RemovedGuidCount = 0;
  1792. AddedGuidMax = 0;
  1793. ModifiedGuidMax = 0;
  1794. RemovedGuidMax = 0;
  1795. ModifiedGuids = NULL;
  1796. AddedGuids = NULL;
  1797. RemovedGuids = NULL;
  1798. NextWmiRegInfo = 0;
  1799. RetSizeLeft = RetSize;
  1800. WmipEnterSMCritSection();
  1801. RegInfo = (PUCHAR)WmiRegInfo;
  1802. for (i = 0; i < WmiRegInfo->GuidCount; i++)
  1803. {
  1804. RegGuid = &WmiRegInfo->WmiRegGuid[i];
  1805. if (RegGuid->Flags & WMIREG_FLAG_REMOVE_GUID)
  1806. {
  1807. if (WmipUpdateRemoveGuid(DataSource,
  1808. RegGuid,
  1809. &InstanceSet))
  1810. {
  1811. WmipCachePtrs(&RegGuid->Guid,
  1812. InstanceSet,
  1813. &RemovedGuidCount,
  1814. &RemovedGuidMax,
  1815. &RemovedGuids);
  1816. }
  1817. } else {
  1818. Action = WmipUpdateModifyGuid(DataSource,
  1819. RegGuid,
  1820. WmiRegInfo,
  1821. RetSize,
  1822. &InstanceSet);
  1823. if (Action == 1)
  1824. {
  1825. WmipCachePtrs(&RegGuid->Guid,
  1826. InstanceSet,
  1827. &AddedGuidCount,
  1828. &AddedGuidMax,
  1829. &AddedGuids);
  1830. } else if (Action == 2) {
  1831. WmipCachePtrs(&RegGuid->Guid,
  1832. InstanceSet,
  1833. &ModifiedGuidCount,
  1834. &ModifiedGuidMax,
  1835. &ModifiedGuids);
  1836. }
  1837. }
  1838. }
  1839. WmipLeaveSMCritSection();
  1840. WmipUnreferenceDS(DataSource);
  1841. if (RemovedGuidCount > 0)
  1842. {
  1843. for (i = 0; i < RemovedGuidCount; i++)
  1844. {
  1845. if (IsEqualGUID(RemovedGuids[i].Guid,
  1846. &WmipBinaryMofGuid))
  1847. {
  1848. WmipGenerateBinaryMofNotification(RemovedGuids[i].InstanceSet,
  1849. &GUID_MOF_RESOURCE_REMOVED_NOTIFICATION);
  1850. }
  1851. InstanceSet = RemovedGuids[i].InstanceSet;
  1852. WmipDisableCollectionForRemovedGuid(RemovedGuids[i].Guid,
  1853. InstanceSet);
  1854. WmipEnterSMCritSection();
  1855. //
  1856. // If IS is on the GE list then remove it
  1857. if (InstanceSet->GuidISList.Flink != NULL)
  1858. {
  1859. RemoveEntryList(&InstanceSet->GuidISList);
  1860. InstanceSet->GuidEntry->ISCount--;
  1861. }
  1862. if (! (InstanceSet->Flags & IS_NEWLY_REGISTERED))
  1863. {
  1864. WmipUnreferenceGE(InstanceSet->GuidEntry);
  1865. }
  1866. InstanceSet->GuidEntry = NULL;
  1867. //
  1868. // Remove IS from the DS List
  1869. RemoveEntryList(&InstanceSet->DSISList);
  1870. WmipUnreferenceIS(InstanceSet);
  1871. WmipLeaveSMCritSection();
  1872. }
  1873. WmipSendGuidUpdateNotifications(RegistrationDelete,
  1874. RemovedGuidCount,
  1875. RemovedGuids);
  1876. WmipFree(RemovedGuids);
  1877. }
  1878. if (ModifiedGuidCount > 0)
  1879. {
  1880. for (i = 0; i < ModifiedGuidCount; i++)
  1881. {
  1882. if (IsEqualGUID(ModifiedGuids[i].Guid,
  1883. &WmipBinaryMofGuid))
  1884. {
  1885. WmipGenerateBinaryMofNotification(ModifiedGuids[i].InstanceSet,
  1886. &GUID_MOF_RESOURCE_ADDED_NOTIFICATION);
  1887. }
  1888. }
  1889. WmipSendGuidUpdateNotifications(RegistrationUpdate,
  1890. ModifiedGuidCount,
  1891. ModifiedGuids);
  1892. WmipFree(ModifiedGuids);
  1893. }
  1894. if (AddedGuidCount > 0)
  1895. {
  1896. for (i = 0; i < AddedGuidCount; i++)
  1897. {
  1898. if (IsEqualGUID(AddedGuids[i].Guid,
  1899. &WmipBinaryMofGuid))
  1900. {
  1901. WmipGenerateBinaryMofNotification(AddedGuids[i].InstanceSet,
  1902. &GUID_MOF_RESOURCE_ADDED_NOTIFICATION);
  1903. }
  1904. WmipEnableCollectionForNewGuid(AddedGuids[i].Guid,
  1905. AddedGuids[i].InstanceSet);
  1906. }
  1907. WmipSendGuidUpdateNotifications(RegistrationAdd,
  1908. AddedGuidCount,
  1909. AddedGuids);
  1910. WmipFree(AddedGuids);
  1911. }
  1912. return(STATUS_SUCCESS);
  1913. }
  1914. void WmipRemoveDataSourceByDS(
  1915. PBDATASOURCE DataSource
  1916. )
  1917. {
  1918. PAGED_CODE();
  1919. WmipGenerateRegistrationNotification(DataSource,
  1920. RegistrationDelete);
  1921. WmipUnreferenceDS(DataSource);
  1922. }
  1923. NTSTATUS WmipRemoveDataSource(
  1924. PREGENTRY RegEntry
  1925. )
  1926. {
  1927. PBDATASOURCE DataSource;
  1928. NTSTATUS Status;
  1929. PAGED_CODE();
  1930. DataSource = RegEntry->DataSource;
  1931. if (DataSource != NULL)
  1932. {
  1933. WmipReferenceDS(DataSource);
  1934. WmipRemoveDataSourceByDS(DataSource);
  1935. WmipUnreferenceDS(DataSource);
  1936. Status = STATUS_SUCCESS;
  1937. } else {
  1938. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Attempt to remove non existant data source %p\n",
  1939. RegEntry));
  1940. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1941. }
  1942. return(Status);
  1943. }
  1944. NTSTATUS WmipEnumerateMofResources(
  1945. PWMIMOFLIST MofList,
  1946. ULONG BufferSize,
  1947. ULONG *RetSize
  1948. )
  1949. {
  1950. PLIST_ENTRY MofResourceList;
  1951. PMOFRESOURCE MofResource;
  1952. ULONG MRCount;
  1953. ULONG SizeNeeded, MRSize;
  1954. PWMIMOFENTRY MofEntry;
  1955. PWCHAR MRBuffer;
  1956. ULONG i;
  1957. PAGED_CODE();
  1958. WmipEnterSMCritSection();
  1959. MRCount = 0;
  1960. SizeNeeded = 0;
  1961. MofResourceList = WmipMRHeadPtr->Flink;
  1962. while (MofResourceList != WmipMRHeadPtr)
  1963. {
  1964. MofResource = CONTAINING_RECORD(MofResourceList,
  1965. MOFRESOURCE,
  1966. MainMRList);
  1967. MRCount++;
  1968. SizeNeeded += (wcslen(MofResource->RegistryPath) +
  1969. wcslen(MofResource->MofResourceName) + 2) *
  1970. sizeof(WCHAR);
  1971. MofResourceList = MofResourceList->Flink;
  1972. }
  1973. if (MRCount != 0)
  1974. {
  1975. MRSize = sizeof(WMIMOFLIST) + ((MRCount-1) * sizeof(WMIMOFENTRY));
  1976. SizeNeeded += MRSize;
  1977. if (BufferSize >= SizeNeeded)
  1978. {
  1979. MofList->MofListCount = MRCount;
  1980. MofResourceList = WmipMRHeadPtr->Flink;
  1981. i = 0;
  1982. while (MofResourceList != WmipMRHeadPtr)
  1983. {
  1984. MofResource = CONTAINING_RECORD(MofResourceList,
  1985. MOFRESOURCE,
  1986. MainMRList);
  1987. MofEntry = &MofList->MofEntry[i++];
  1988. MofEntry->Flags = MofResource->Flags & MR_FLAG_USER_MODE ?
  1989. WMIMOFENTRY_FLAG_USERMODE :
  1990. 0;
  1991. MofEntry->RegPathOffset = MRSize;
  1992. MRBuffer = (PWCHAR)OffsetToPtr(MofList, MRSize);
  1993. wcscpy(MRBuffer, MofResource->RegistryPath);
  1994. MRSize += (wcslen(MofResource->RegistryPath) + 1) * sizeof(WCHAR);
  1995. MofEntry->ResourceOffset = MRSize;
  1996. MRBuffer = (PWCHAR)OffsetToPtr(MofList, MRSize);
  1997. wcscpy(MRBuffer, MofResource->MofResourceName);
  1998. MRSize += (wcslen(MofResource->MofResourceName) + 1) * sizeof(WCHAR);
  1999. MofResourceList = MofResourceList->Flink;
  2000. }
  2001. } else {
  2002. //
  2003. // Buffer not large enough, return size needed
  2004. //
  2005. MofList->MofListCount = SizeNeeded;
  2006. *RetSize = sizeof(ULONG);
  2007. }
  2008. } else {
  2009. //
  2010. // No mof resources
  2011. //
  2012. MofList->MofListCount = 0;
  2013. *RetSize = sizeof(WMIMOFLIST);
  2014. }
  2015. WmipLeaveSMCritSection();
  2016. return(STATUS_SUCCESS);
  2017. }
  2018. NTSTATUS WmipInitializeDataStructs(
  2019. void
  2020. )
  2021. /*++
  2022. Routine Description:
  2023. This routine will do the work of initializing the WMI service
  2024. Arguments:
  2025. Return Value:
  2026. Error status value
  2027. --*/
  2028. {
  2029. ULONG Status;
  2030. UCHAR RegInfoBuffer[sizeof(WMIREGINFOW) + 2 * sizeof(WMIREGGUIDW)];
  2031. PWMIREGINFOW RegInfo = (PWMIREGINFOW)RegInfoBuffer;
  2032. GUID InstanceInfoGuid = INSTANCE_INFO_GUID;
  2033. GUID EnumerateGuidsGuid = ENUMERATE_GUIDS_GUID;
  2034. PREGENTRY RegEntry;
  2035. PDEVICE_OBJECT Callback;
  2036. PLIST_ENTRY GuidEntryList;
  2037. PBGUIDENTRY GuidEntry;
  2038. BOOLEAN NewResource;
  2039. PAGED_CODE();
  2040. //
  2041. // Initialize the various data structure lists that we maintain
  2042. //
  2043. WmipDSHeadPtr = &WmipDSHead;
  2044. InitializeListHead(WmipDSHeadPtr);
  2045. InitializeListHead(&WmipDSChunkInfo.ChunkHead);
  2046. WmipGEHeadPtr = &WmipGEHead;
  2047. InitializeListHead(WmipGEHeadPtr);
  2048. InitializeListHead(&WmipGEChunkInfo.ChunkHead);
  2049. WmipMRHeadPtr = &WmipMRHead;
  2050. InitializeListHead(WmipMRHeadPtr);
  2051. InitializeListHead(&WmipMRChunkInfo.ChunkHead);
  2052. InitializeListHead(&WmipISChunkInfo.ChunkHead);
  2053. WmipGMHeadPtr = &WmipGMHead;
  2054. InitializeListHead(WmipGMHeadPtr);
  2055. //
  2056. // Register any internal data provider guids and mark them as such
  2057. //
  2058. Callback = (PDEVICE_OBJECT)WmipUMProviderCallback;
  2059. //
  2060. // Establish a regentry for the data provider
  2061. //
  2062. RegEntry = WmipAllocRegEntry(Callback,
  2063. WMIREG_FLAG_CALLBACK |
  2064. REGENTRY_FLAG_TRACED |
  2065. REGENTRY_FLAG_NEWREGINFO |
  2066. REGENTRY_FLAG_INUSE |
  2067. REGENTRY_FLAG_REG_IN_PROGRESS);
  2068. if (RegEntry != NULL)
  2069. {
  2070. //
  2071. // This code assumes that no other data providers have
  2072. // yet registered.
  2073. //
  2074. WmipAssert(WmipGEHeadPtr->Flink == WmipGEHeadPtr);
  2075. RtlZeroMemory(RegInfo, sizeof(RegInfoBuffer));
  2076. RegInfo->BufferSize = sizeof(RegInfoBuffer);
  2077. RegInfo->GuidCount = 2;
  2078. RegInfo->WmiRegGuid[0].Guid = InstanceInfoGuid;
  2079. RegInfo->WmiRegGuid[1].Guid = EnumerateGuidsGuid;
  2080. Status = WmipAddDataSource(RegEntry,
  2081. RegInfo,
  2082. RegInfo->BufferSize,
  2083. NULL,
  2084. NULL,
  2085. NULL,
  2086. FALSE);
  2087. if (NT_SUCCESS(Status))
  2088. {
  2089. GuidEntryList = WmipGEHeadPtr->Flink;
  2090. while (GuidEntryList != WmipGEHeadPtr)
  2091. {
  2092. GuidEntry = CONTAINING_RECORD(GuidEntryList,
  2093. GUIDENTRY,
  2094. MainGEList);
  2095. GuidEntry->Flags |= GE_FLAG_INTERNAL;
  2096. GuidEntryList = GuidEntryList->Flink;
  2097. }
  2098. } else {
  2099. RegEntry->Flags |= (REGENTRY_FLAG_RUNDOWN |
  2100. REGENTRY_FLAG_NOT_ACCEPTING_IRPS);
  2101. WmipUnreferenceRegEntry(RegEntry);
  2102. }
  2103. }
  2104. Status = WmipAddMofResource(RegEntry->DataSource,
  2105. WMICOREIMAGEPATH,
  2106. TRUE,
  2107. WMICORERESOURCENAME,
  2108. &NewResource);
  2109. WmipAssert(NewResource);
  2110. return(STATUS_SUCCESS);
  2111. }