Leaked source code of windows server 2003
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.

630 lines
17 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: fn.cpp
  4. //
  5. // Description:
  6. //
  7. //
  8. //@@BEGIN_MSINTERNAL
  9. // Development Team:
  10. // Mike McLaughlin
  11. //
  12. // History: Date Author Comment
  13. //
  14. // To Do: Date Author Comment
  15. //
  16. //@@END_MSINTERNAL
  17. //
  18. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  19. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  20. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  21. // PURPOSE.
  22. //
  23. // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
  24. //
  25. //---------------------------------------------------------------------------
  26. #include "common.h"
  27. EXTERN_C VOID KeAttachProcess(PVOID);
  28. EXTERN_C VOID KeDetachProcess(VOID);
  29. //---------------------------------------------------------------------------
  30. //---------------------------------------------------------------------------
  31. PLIST_FILTER_NODE gplstFilterNode = NULL;
  32. PLIST_MULTI_LOGICAL_FILTER_NODE gplstLogicalFilterNode = NULL;
  33. //---------------------------------------------------------------------------
  34. //---------------------------------------------------------------------------
  35. NTSTATUS
  36. InitializeFilterNode()
  37. {
  38. if(gplstFilterNode == NULL) {
  39. gplstFilterNode = new LIST_FILTER_NODE;
  40. if(gplstFilterNode == NULL) {
  41. return(STATUS_INSUFFICIENT_RESOURCES);
  42. }
  43. }
  44. if(gplstLogicalFilterNode == NULL) {
  45. gplstLogicalFilterNode = new LIST_MULTI_LOGICAL_FILTER_NODE;
  46. if(gplstLogicalFilterNode == NULL) {
  47. return(STATUS_INSUFFICIENT_RESOURCES);
  48. }
  49. }
  50. return(STATUS_SUCCESS);
  51. }
  52. #pragma PAGEABLE_CODE
  53. #pragma PAGEABLE_DATA
  54. VOID
  55. UninitializeFilterNode()
  56. {
  57. PFILTER_NODE pFilterNode;
  58. if (NULL != gplstFilterNode) {
  59. FOR_EACH_LIST_ITEM_DELETE(gplstFilterNode, pFilterNode) {
  60. if (pFilterNode->pDeviceNode) {
  61. pFilterNode->pDeviceNode->pFilterNode=NULL;
  62. }
  63. delete pFilterNode;
  64. DELETE_LIST_ITEM(gplstFilterNode);
  65. } END_EACH_LIST_ITEM
  66. }
  67. delete gplstFilterNode;
  68. gplstFilterNode = NULL;
  69. delete gplstLogicalFilterNode;
  70. gplstLogicalFilterNode = NULL;
  71. }
  72. //---------------------------------------------------------------------------
  73. CFilterNode::CFilterNode(
  74. ULONG fulType
  75. )
  76. {
  77. ASSERT(gplstFilterNode != NULL);
  78. SetType(fulType);
  79. AddListEnd(gplstFilterNode);
  80. DPF2(60, "CFilterNode: %08x %s", this, DumpName());
  81. }
  82. CFilterNode::~CFilterNode(
  83. )
  84. {
  85. PFILTER_NODE pFilterNode;
  86. Assert(this);
  87. DPF2(60, "~CFilterNode: %08x %s", this, DumpName());
  88. RemoveListCheck();
  89. if (pDeviceNode) {
  90. pDeviceNode->pFilterNode = NULL;
  91. }
  92. if (pFileObject) {
  93. ::ObDereferenceObject(pFileObject);
  94. pFileObject = NULL;
  95. }
  96. delete pDeviceNode;
  97. FOR_EACH_LIST_ITEM(gplstFilterNode, pFilterNode) {
  98. pFilterNode->lstConnectedFilterNode.RemoveList(this);
  99. } END_EACH_LIST_ITEM
  100. // Free all other memory
  101. lstFreeMem.EnumerateList(CListDataItem::Destroy);
  102. }
  103. NTSTATUS
  104. CFilterNode::Create(
  105. PWSTR pwstrDeviceInterface
  106. )
  107. {
  108. PFILTER_NODE_INSTANCE pFilterNodeInstance = NULL;
  109. PKEY_VALUE_FULL_INFORMATION pkvfi = NULL;
  110. NTSTATUS Status = STATUS_SUCCESS;
  111. HANDLE hkeyDeviceClass = NULL;
  112. UNICODE_STRING ustrFilterName;
  113. KSPROPERTY PropertyComponentId;
  114. KSCOMPONENTID ComponentId;
  115. ULONG BytesReturned;
  116. PFILE_OBJECT pFileObject;
  117. //
  118. // SECURITY NOTE:
  119. // pwstrDeviceInterface is either given to us by PNP system or is
  120. // internal.
  121. //
  122. this->pwstrDeviceInterface = new WCHAR[wcslen(pwstrDeviceInterface) + 1];
  123. if(this->pwstrDeviceInterface == NULL) {
  124. Status = STATUS_INSUFFICIENT_RESOURCES;
  125. goto exit;
  126. }
  127. wcscpy(this->pwstrDeviceInterface, pwstrDeviceInterface);
  128. Status = lstFreeMem.AddList(this->pwstrDeviceInterface);
  129. if(!NT_SUCCESS(Status)) {
  130. Trap();
  131. delete this->pwstrDeviceInterface;
  132. goto exit;
  133. }
  134. Status = CFilterNodeInstance::Create(&pFilterNodeInstance, this);
  135. if(!NT_SUCCESS(Status)) {
  136. goto exit;
  137. }
  138. pFileObject = pFilterNodeInstance->pFileObject;
  139. // Get the filter's friendly name
  140. RtlInitUnicodeString(&ustrFilterName, this->pwstrDeviceInterface);
  141. Status = IoOpenDeviceInterfaceRegistryKey(
  142. &ustrFilterName,
  143. KEY_READ,
  144. &hkeyDeviceClass);
  145. if(!NT_SUCCESS(Status)) {
  146. goto exit;
  147. }
  148. //
  149. // Note that we do not care if the device has a friendlyname or not.
  150. // We will simply ignore registry-read failure for the rest of this
  151. // function.
  152. //
  153. Status = QueryRegistryValue(hkeyDeviceClass, L"FriendlyName", &pkvfi);
  154. if(NT_SUCCESS(Status)) {
  155. if(pkvfi->Type == REG_SZ && pkvfi->DataLength > 0) {
  156. Status = lstFreeMem.AddList(pkvfi);
  157. if(!NT_SUCCESS(Status)) {
  158. Trap();
  159. delete pkvfi;
  160. goto exit;
  161. }
  162. pwstrFriendlyName = (PWSTR)(((PUCHAR)pkvfi) + pkvfi->DataOffset);
  163. }
  164. else {
  165. delete pkvfi;
  166. }
  167. }
  168. #ifdef DEBUG
  169. HANDLE hkeySysaudio = NULL;
  170. Status = OpenRegistryKeyForRead(L"Sysaudio", &hkeySysaudio, hkeyDeviceClass);
  171. // We do not need these registry keys for retail builds
  172. if(NT_SUCCESS(Status)) {
  173. Status = QueryRegistryValue(hkeySysaudio, L"Disabled", &pkvfi);
  174. if(NT_SUCCESS(Status)) {
  175. if(pkvfi->Type == REG_DWORD) {
  176. if(*((PULONG)(((PUCHAR)pkvfi) + pkvfi->DataOffset))) {
  177. Status = STATUS_SERVER_DISABLED;
  178. delete pkvfi;
  179. goto exit;
  180. }
  181. }
  182. delete pkvfi;
  183. }
  184. Status = QueryRegistryValue(hkeySysaudio, L"Device", &pkvfi);
  185. if(NT_SUCCESS(Status)) {
  186. if(pkvfi->Type == REG_SZ && pkvfi->DataLength > 0) {
  187. Status = lstFreeMem.AddList(pkvfi);
  188. if(!NT_SUCCESS(Status)) {
  189. Trap();
  190. delete pkvfi;
  191. goto exit;
  192. }
  193. Status = AddDeviceInterfaceMatch(
  194. (PWSTR)(((PUCHAR)pkvfi) + pkvfi->DataOffset));
  195. if(!NT_SUCCESS(Status)) {
  196. Trap();
  197. delete pkvfi;
  198. goto exit;
  199. }
  200. }
  201. else {
  202. delete pkvfi;
  203. }
  204. }
  205. Status = QueryRegistryValue(hkeySysaudio, L"Order", &pkvfi);
  206. if(NT_SUCCESS(Status)) {
  207. if(pkvfi->Type == REG_DWORD) {
  208. ulOrder = *((PULONG)(((PUCHAR)pkvfi) + pkvfi->DataOffset));
  209. }
  210. delete pkvfi;
  211. }
  212. Status = QueryRegistryValue(hkeySysaudio, L"Capture", &pkvfi);
  213. if(NT_SUCCESS(Status)) {
  214. if(pkvfi->Type == REG_DWORD) {
  215. if(*((PULONG)(((PUCHAR)pkvfi) + pkvfi->DataOffset))) {
  216. ulFlags |= FN_FLAGS_CAPTURE;
  217. }
  218. else {
  219. ulFlags |= FN_FLAGS_NO_CAPTURE;
  220. }
  221. }
  222. delete pkvfi;
  223. }
  224. Status = QueryRegistryValue(hkeySysaudio, L"Render", &pkvfi);
  225. if(NT_SUCCESS(Status)) {
  226. if(pkvfi->Type == REG_DWORD) {
  227. if(*((PULONG)(((PUCHAR)pkvfi) + pkvfi->DataOffset))) {
  228. ulFlags |= FN_FLAGS_RENDER;
  229. }
  230. else {
  231. ulFlags |= FN_FLAGS_NO_RENDER;
  232. }
  233. }
  234. delete pkvfi;
  235. }
  236. }
  237. #endif // DEBUG
  238. // Get the component Id of the filter
  239. PropertyComponentId.Set = KSPROPSETID_General;
  240. PropertyComponentId.Id = KSPROPERTY_GENERAL_COMPONENTID;
  241. PropertyComponentId.Flags = KSPROPERTY_TYPE_GET;
  242. Status = KsSynchronousIoControlDevice(
  243. pFileObject,
  244. KernelMode,
  245. IOCTL_KS_PROPERTY,
  246. &PropertyComponentId,
  247. sizeof(PropertyComponentId),
  248. &ComponentId,
  249. sizeof(ComponentId),
  250. &BytesReturned);
  251. // Store the component Id
  252. if (NT_SUCCESS(Status)) {
  253. ASSERT(BytesReturned >= sizeof(ComponentId));
  254. this->ComponentId = new KSCOMPONENTID;
  255. if (this->ComponentId) {
  256. RtlCopyMemory(this->ComponentId,
  257. &ComponentId,
  258. sizeof(KSCOMPONENTID));
  259. Status = lstFreeMem.AddList(this->ComponentId);
  260. if(!NT_SUCCESS(Status)) {
  261. delete this->ComponentId;
  262. this->ComponentId = NULL;
  263. }
  264. }
  265. }
  266. else {
  267. this->ComponentId = NULL;
  268. }
  269. Status = this->ProfileFilter(pFileObject);
  270. exit:
  271. #ifdef DEBUG
  272. if(hkeySysaudio != NULL) {
  273. ZwClose(hkeySysaudio);
  274. }
  275. #endif
  276. if(hkeyDeviceClass != NULL) {
  277. ZwClose(hkeyDeviceClass);
  278. }
  279. if (pFilterNodeInstance) {
  280. pFilterNodeInstance->Destroy();
  281. }
  282. return(Status);
  283. }
  284. NTSTATUS
  285. CFilterNode::ProfileFilter(
  286. PFILE_OBJECT pFileObject
  287. )
  288. {
  289. NTSTATUS Status = STATUS_SUCCESS;
  290. PKSMULTIPLE_ITEM pCategories = NULL;
  291. PKSMULTIPLE_ITEM pConnections = NULL;
  292. PKSMULTIPLE_ITEM pNodes = NULL;
  293. ULONG PinId;
  294. PPIN_INFO pPinInfo;
  295. ULONG i;
  296. KSTOPOLOGY Topology;
  297. RtlZeroMemory(&Topology, sizeof(Topology));
  298. // Get the number of pins
  299. Status = GetPinProperty(
  300. pFileObject,
  301. KSPROPERTY_PIN_CTYPES,
  302. 0, // doesn't matter for ctypes
  303. sizeof(cPins),
  304. (PVOID)&cPins);
  305. if(!NT_SUCCESS(Status)) {
  306. Trap();
  307. goto exit;
  308. }
  309. // Get the topology of the filter
  310. Status = GetProperty(
  311. pFileObject,
  312. &KSPROPSETID_Topology,
  313. KSPROPERTY_TOPOLOGY_CATEGORIES,
  314. (PVOID*)&pCategories);
  315. if(!NT_SUCCESS(Status)) {
  316. Trap();
  317. goto exit;
  318. }
  319. if(pCategories != NULL) {
  320. Topology.CategoriesCount = pCategories->Count;
  321. Topology.Categories = (GUID*)(pCategories + 1);
  322. ULONG fulType = 0;
  323. for(i = 0; i < pCategories->Count; i++) {
  324. GetFilterTypeFromGuid((LPGUID)&Topology.Categories[i], &fulType);
  325. }
  326. SetType(fulType);
  327. }
  328. Status = GetProperty(
  329. pFileObject,
  330. &KSPROPSETID_Topology,
  331. KSPROPERTY_TOPOLOGY_NODES,
  332. (PVOID*)&pNodes);
  333. if(!NT_SUCCESS(Status)) {
  334. Trap();
  335. goto exit;
  336. }
  337. if(pNodes != NULL) {
  338. Status = lstFreeMem.AddList(pNodes);
  339. if(!NT_SUCCESS(Status)) {
  340. Trap();
  341. delete pNodes;
  342. goto exit;
  343. }
  344. Topology.TopologyNodesCount = pNodes->Count;
  345. Topology.TopologyNodes = (GUID*)(pNodes + 1);
  346. }
  347. Status = GetProperty(
  348. pFileObject,
  349. &KSPROPSETID_Topology,
  350. KSPROPERTY_TOPOLOGY_CONNECTIONS,
  351. (PVOID*)&pConnections);
  352. if(!NT_SUCCESS(Status)) {
  353. Trap();
  354. goto exit;
  355. }
  356. if(pConnections != NULL) {
  357. Topology.TopologyConnectionsCount = pConnections->Count;
  358. Topology.TopologyConnections =
  359. (PKSTOPOLOGY_CONNECTION)(pConnections + 1);
  360. }
  361. // Each pin loop
  362. for(PinId = 0; PinId < cPins; PinId++) {
  363. pPinInfo = new PIN_INFO(this, PinId);
  364. if(pPinInfo == NULL) {
  365. Status = STATUS_INSUFFICIENT_RESOURCES;
  366. Trap();
  367. goto exit;
  368. }
  369. Status = pPinInfo->Create(pFileObject);
  370. if(!NT_SUCCESS(Status)) {
  371. goto exit;
  372. }
  373. }
  374. Status = CreateTopology(this, &Topology);
  375. if(!NT_SUCCESS(Status)) {
  376. goto exit;
  377. }
  378. Status = lstPinInfo.EnumerateList(CPinInfo::CreatePhysicalConnection);
  379. if(Status == STATUS_CONTINUE) {
  380. Status = STATUS_SUCCESS;
  381. }
  382. else if(!NT_SUCCESS(Status)) {
  383. goto exit;
  384. }
  385. Status = CLogicalFilterNode::CreateAll(this);
  386. if(!NT_SUCCESS(Status)) {
  387. goto exit;
  388. }
  389. exit:
  390. delete pCategories;
  391. delete pConnections;
  392. return(Status);
  393. }
  394. NTSTATUS
  395. CFilterNode::DuplicateForCapture(
  396. )
  397. {
  398. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  399. NTSTATUS Status = STATUS_SUCCESS;
  400. PFILTER_NODE pFilterNode = NULL;
  401. if(GetType() & FILTER_TYPE_DUP_FOR_CAPTURE) {
  402. FOR_EACH_LIST_ITEM(&lstLogicalFilterNode, pLogicalFilterNode) {
  403. if(!pLogicalFilterNode->IsRenderAndCapture()) {
  404. ASSERT(NT_SUCCESS(Status));
  405. goto exit;
  406. }
  407. } END_EACH_LIST_ITEM
  408. pFilterNode = new FILTER_NODE(GetType());
  409. if(pFilterNode == NULL) {
  410. Status = STATUS_INSUFFICIENT_RESOURCES;
  411. Trap();
  412. goto exit;
  413. }
  414. Status = pFilterNode->Create(GetDeviceInterface());
  415. if(!NT_SUCCESS(Status)) {
  416. goto exit;
  417. }
  418. SetRenderOnly();
  419. pFilterNode->SetCaptureOnly();
  420. }
  421. exit:
  422. if(!NT_SUCCESS(Status)) {
  423. Trap();
  424. delete pFilterNode;
  425. }
  426. return(Status);
  427. }
  428. BOOL
  429. CFilterNode::IsDeviceInterfaceMatch(
  430. PDEVICE_NODE pDeviceNode
  431. )
  432. {
  433. PWSTR pwstr, pwstrDeviceInterface;
  434. UNICODE_STRING String1, String2;
  435. Assert(this);
  436. if(lstwstrDeviceInterfaceMatch.IsLstEmpty()) {
  437. return(TRUE);
  438. }
  439. //
  440. // The +4 for both the strings is to eliminate the \\.\ differences in
  441. // user mode device interface names & kernel mode device interface names
  442. //
  443. pwstrDeviceInterface = pDeviceNode->GetDeviceInterface()+4;
  444. RtlInitUnicodeString(&String2, pwstrDeviceInterface);
  445. FOR_EACH_LIST_ITEM(&lstwstrDeviceInterfaceMatch, pwstr) {
  446. RtlInitUnicodeString(&String1, (pwstr+4));
  447. if (RtlEqualUnicodeString(&String1, &String2, TRUE)) {
  448. return(TRUE);
  449. }
  450. } END_EACH_LIST_ITEM
  451. return(FALSE);
  452. }
  453. VOID
  454. CFilterNode::SetType(
  455. ULONG fulType
  456. )
  457. {
  458. this->fulType |= fulType;
  459. //
  460. // This is because of left overs (type bridge) in the registry
  461. // that look like aliases.
  462. //
  463. if(this->fulType & FILTER_TYPE_TOPOLOGY) {
  464. this->fulType = (FILTER_TYPE_AUDIO | FILTER_TYPE_TOPOLOGY);
  465. }
  466. GetDefaultOrder(this->fulType, &ulOrder);
  467. }
  468. NTSTATUS
  469. CFilterNode::CreatePin(
  470. PKSPIN_CONNECT pPinConnect,
  471. ACCESS_MASK Access,
  472. PHANDLE pHandle
  473. )
  474. {
  475. NTSTATUS Status;
  476. //
  477. // SECURITY NOTE:
  478. // ACCESS_MASK must include OBJ_KERNEL_HANDLE. This routine does not run
  479. // in system process, thus the handle must be protected.
  480. //
  481. ::KeAttachProcess(this->pProcess);
  482. Status = KsCreatePin(this->hFileHandle,
  483. pPinConnect,
  484. Access | OBJ_KERNEL_HANDLE,
  485. pHandle);
  486. ::KeDetachProcess();
  487. return(Status);
  488. }
  489. BOOL
  490. CFilterNode::DoesGfxMatch(
  491. HANDLE hGfx,
  492. PWSTR pwstrDeviceName,
  493. ULONG GfxOrder
  494. )
  495. {
  496. ULONG DeviceCount;
  497. UNICODE_STRING usInDevice, usfnDevice;
  498. PWSTR pwstr;
  499. //
  500. // SECURITY NOTE:
  501. // This functions assumes that the pwstrDeviceName will be at least
  502. // 4 characters long.
  503. // This function is only called from notify.cpp and the caller makes sure
  504. // that this assumption holds.
  505. //
  506. RtlInitUnicodeString(&usInDevice, (pwstrDeviceName+4));
  507. //
  508. // Skip if it is not a GFX
  509. //
  510. DPF1(90, "DoesGfxMatch:: fultype=%x", this->fulType);
  511. if (!(this->fulType & FILTER_TYPE_GFX)) {
  512. return(FALSE);
  513. }
  514. //
  515. // If it is a valid handle value, check whether the handle matches
  516. //
  517. if (hGfx) {
  518. if (this->hFileHandle != hGfx) {
  519. return(FALSE);
  520. }
  521. }
  522. //
  523. // Skip if the order does not match
  524. //
  525. DPF1(90, "DoesGfxMatch:: order=%x", this->ulOrder);
  526. if (GfxOrder != this->ulOrder) {
  527. return(FALSE);
  528. }
  529. //
  530. // Skip if the match device list is empty :: should not happen with GFX
  531. //
  532. if(lstwstrDeviceInterfaceMatch.IsLstEmpty()) {
  533. ASSERT(!"GFX with no device to attach to!\n");
  534. return(FALSE);
  535. }
  536. //
  537. // Check if any of the Match device strings matches the device interface
  538. // passed in. (In case of GFX we should have only one string though)
  539. //
  540. DeviceCount = 0;
  541. FOR_EACH_LIST_ITEM(&lstwstrDeviceInterfaceMatch, pwstr) {
  542. ASSERT(DeviceCount == 0);
  543. RtlInitUnicodeString(&usfnDevice, (pwstr+4));
  544. DPF1(95, "DoesGfxMatch:: new di = %s)", DbgUnicode2Sz(pwstrDeviceName));
  545. DPF1(95, "DoesGfxMatch:: old di = %s)", DbgUnicode2Sz(pwstr));
  546. if (RtlEqualUnicodeString(&usInDevice, &usfnDevice, TRUE)) {
  547. DPF1(90, "Found a duplicate GFX, pFilterNode = %x", this);
  548. return(TRUE);
  549. }
  550. DeviceCount++;
  551. } END_EACH_LIST_ITEM
  552. return (FALSE);
  553. }
  554. //---------------------------------------------------------------------------