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.

487 lines
20 KiB

  1. #include "drmkPCH.h"
  2. #include "KList.h"
  3. #include "StreamMgr.h"
  4. #include "iohelp.h"
  5. //-------------------------------------------------------------------------------------------------
  6. // Package implements the DRMK authentication stubs. Routines are called to notify DRMK of downstream
  7. // components and to notify DRMK of the creation and destruction of composite streams. ContentId
  8. // in this file is called StreamId elsewhere.
  9. //-------------------------------------------------------------------------------------------------
  10. static NTSTATUS GetDeviceObjectDispatchTable(IN DWORD ContentId, IN _DEVICE_OBJECT* pDevO, IN BOOL fCheckAttached);
  11. static NTSTATUS GetFileObjectDispatchTable(IN DWORD ContentId, IN PFILE_OBJECT pF);
  12. //-------------------------------------------------------------------------------------------------
  13. /*
  14. Routine called by a splitter component. Any stream with ContentId==0 is considered unprotected.
  15. */
  16. NTSTATUS DrmCreateContentMixed(IN PULONG paContentId,
  17. IN ULONG cContentId,
  18. OUT PULONG pMixedContentId)
  19. {
  20. KCritical s(TheStreamMgr->getCritMgr());
  21. if((NULL==paContentId && !(cContentId!=0)) || NULL==pMixedContentId){
  22. _DbgPrintF(DEBUGLVL_VERBOSE,("Invalid NULL-parameter for DrmCreateContentMixed"));
  23. TheStreamMgr->logErrorToStream(0, STATUS_INVALID_PARAMETER);
  24. return STATUS_INVALID_PARAMETER;
  25. };
  26. _DbgPrintF(DEBUGLVL_VERBOSE,("DrmCreateMixed for N streams, N= %d", cContentId));
  27. DRM_STATUS stat = TheStreamMgr->createCompositeStream(pMixedContentId, paContentId, cContentId);
  28. if(stat==DRM_OK){
  29. return STATUS_SUCCESS;
  30. }
  31. // only error is out-of-memory
  32. TheStreamMgr->setFatalError(STATUS_INSUFFICIENT_RESOURCES);
  33. return STATUS_INSUFFICIENT_RESOURCES;
  34. }
  35. //------------------------------IO-------------------------------------------------------------------
  36. /*
  37. Routine called by a component to notify KRM of a downstream COM object that will process audio.
  38. DrmForwardContent will collect its authentication function, and set the DRMRIGHTS bits appropriately.
  39. */
  40. NTSTATUS DrmForwardContentToInterface(ULONG ContentId, PUNKNOWN pUnknown, ULONG NumMethods)
  41. {
  42. NTSTATUS Status;
  43. PDRMAUDIOSTREAM DrmAudioStream;
  44. _DbgPrintF(DEBUGLVL_VERBOSE,("***IN ForwardToInterface"));
  45. if(NULL == pUnknown){
  46. _DbgPrintF(DEBUGLVL_VERBOSE,("Invalid NULL-parameter for DrmForwardContentToInterface"));
  47. TheStreamMgr->logErrorToStream(ContentId, STATUS_INVALID_PARAMETER);
  48. return STATUS_INVALID_PARAMETER;
  49. };
  50. Status = pUnknown->QueryInterface(IID_IDrmAudioStream, (PVOID*)&DrmAudioStream);
  51. if (!NT_SUCCESS(Status)){
  52. _DbgPrintF(DEBUGLVL_VERBOSE,("QI Failed for StreamId= %x (Status=%d, %x)", ContentId, Status, Status));
  53. TheStreamMgr->logErrorToStream(ContentId, Status);
  54. return Status;
  55. };
  56. // ReferenceAquirer calls Release() when it goes out of scope
  57. ReferenceAquirer<PDRMAUDIOSTREAM> aq(DrmAudioStream);
  58. // rights are most permissive. If ContentId!=0, we query the mixed stream that compose
  59. // this stream to restrict the rights.
  60. DRMRIGHTS DrmRights={FALSE, FALSE, FALSE};
  61. if(ContentId!=0){
  62. KCritical s(TheStreamMgr->getCritMgr());
  63. _DbgPrintF(DEBUGLVL_VERBOSE,("Adding %d methods", NumMethods));
  64. // get the pointer to the vtbl
  65. PVOID* vtbl= *((PVOID**) pUnknown);
  66. // and add NumMethods of from the vtbl
  67. for(ULONG j=0;j<NumMethods;j++){
  68. _DbgPrintF(DEBUGLVL_VERBOSE,("ADDING = %x", vtbl[j]));
  69. if (vtbl[j]) {
  70. Status = TheStreamMgr->addProvingFunction(ContentId, vtbl[j]);
  71. } else {
  72. Status = STATUS_INVALID_PARAMETER;
  73. }
  74. if(!NT_SUCCESS(Status)){
  75. _DbgPrintF(DEBUGLVL_VERBOSE,("addProveFunc Failed for StreamId= %x", ContentId));
  76. TheStreamMgr->logErrorToStream(ContentId, Status);
  77. return Status;
  78. };
  79. };
  80. Status=TheStreamMgr->getRights(ContentId, &DrmRights);
  81. if(!NT_SUCCESS(Status)){
  82. _DbgPrintF(DEBUGLVL_VERBOSE,("getRights failed for StreamId= %x", ContentId));
  83. TheStreamMgr->logErrorToStream(ContentId, Status);
  84. return Status;
  85. };
  86. };
  87. _DbgPrintF(DEBUGLVL_VERBOSE,("About to SetContentId "));
  88. Status = DrmAudioStream->SetContentId(ContentId, &DrmRights);
  89. if(!NT_SUCCESS(Status)){
  90. _DbgPrintF(DEBUGLVL_VERBOSE,("SetContentId failed for StreamId= %x (Status=%d, %x)", ContentId, Status, Status));
  91. if (STATUS_NOT_IMPLEMENTED == Status) {
  92. TheStreamMgr->logErrorToStream(ContentId, DRM_RIGHTSNOTSUPPORTED);
  93. } else {
  94. TheStreamMgr->logErrorToStream(ContentId, Status);
  95. }
  96. return Status;
  97. };
  98. return STATUS_SUCCESS;
  99. }
  100. //-------------------------------------------------------------------------------------------------
  101. /*
  102. Routine called by a component to notify KRM of a downstream FILE object that will process audio.
  103. DrmForwardContent will collect its authentication function, and set the DRMRIGHTS bits appropriately.
  104. */
  105. NTSTATUS DrmForwardContentToFileObject(IN ULONG ContentId,
  106. IN PFILE_OBJECT FileObject)
  107. {
  108. KSP_DRMAUDIOSTREAM_CONTENTID Property;
  109. KSDRMAUDIOSTREAM_CONTENTID PropertyValue;
  110. ULONG cbReturned;
  111. NTSTATUS Status;
  112. _DbgPrintF(DEBUGLVL_VERBOSE,("***IN ForwardToFileObject"));
  113. if (FileObject)
  114. {
  115. KCritical s(TheStreamMgr->getCritMgr());
  116. if (0 != ContentId) {
  117. NTSTATUS stat=GetFileObjectDispatchTable(ContentId, FileObject);
  118. }
  119. Property.Property.Set = KSPROPSETID_DrmAudioStream;
  120. Property.Property.Id = KSPROPERTY_DRMAUDIOSTREAM_CONTENTID;
  121. Property.Property.Flags = KSPROPERTY_TYPE_SET;
  122. Property.Context = FileObject;
  123. Property.DrmAddContentHandlers = DrmAddContentHandlers;
  124. Property.DrmCreateContentMixed = DrmCreateContentMixed;
  125. Property.DrmDestroyContent = DrmDestroyContent;
  126. Property.DrmForwardContentToDeviceObject = DrmForwardContentToDeviceObject;
  127. Property.DrmForwardContentToFileObject = DrmForwardContentToFileObject;
  128. Property.DrmForwardContentToInterface = DrmForwardContentToInterface;
  129. Property.DrmGetContentRights = DrmGetContentRights;
  130. PropertyValue.ContentId = ContentId;
  131. Status = TheStreamMgr->getRights(ContentId, &PropertyValue.DrmRights);
  132. if(!NT_SUCCESS(Status)){
  133. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad getRights for StreamId= %x", ContentId));
  134. return Status;
  135. };
  136. } else {
  137. _DbgPrintF(DEBUGLVL_VERBOSE,("Invalid NULL-parameter for DrmForwardContentToFileObject"));
  138. TheStreamMgr->logErrorToStream(ContentId, STATUS_INVALID_PARAMETER);
  139. return STATUS_INVALID_PARAMETER;
  140. }
  141. Status = KsSynchronousIoControlDevice(FileObject, KernelMode, IOCTL_KS_PROPERTY,
  142. &Property, sizeof(Property),
  143. &PropertyValue, sizeof(PropertyValue),
  144. &cbReturned);
  145. // TBD: translate STATUS_PROPSET_NOT_FOUND to something better
  146. if(!NT_SUCCESS(Status)){
  147. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad IoControl(1b) for StreamId= %x on driver. Device with load address [%x] does not support DRM property,(Status=%d, %x)",
  148. ContentId, IoGetRelatedDeviceObject(FileObject)->DriverObject->DriverStart,Status, Status));
  149. if (STATUS_NOT_IMPLEMENTED == Status) {
  150. TheStreamMgr->logErrorToStream(ContentId, DRM_RIGHTSNOTSUPPORTED);
  151. } else {
  152. TheStreamMgr->logErrorToStream(ContentId, Status);
  153. }
  154. return Status;
  155. };
  156. //This may be confusing. We're logging an error here to indicate
  157. //that DrmForwardContentToFileObject was called. This error will
  158. //later be propagated up to krmproxy and used to adjust the security
  159. //level of the drivers, since DrmForwardContentToFileObject opens a
  160. //security hole. We return success from the function after logging
  161. //because we want driver walking to continue from this point, not
  162. //fail, since this is not a fatal error.
  163. //This error code can be overwritten later by another call to
  164. //logErrorToStream, but it will be overwritten either with a fatal
  165. //error or with DRM_BADDRMLEVEL again.
  166. TheStreamMgr->logErrorToStream(ContentId, DRM_BADDRMLEVEL);
  167. return STATUS_SUCCESS;
  168. }
  169. //-------------------------------------------------------------------------------------------------
  170. /*
  171. Routine called by a component to notify KRM of a downstream DEVICE object that will process audio.
  172. DrmForwardContent will collect its authentication function, and set the DRMRIGHTS bits appropriately.
  173. */
  174. NTSTATUS DrmForwardContentToDeviceObject(IN ULONG ContentId,
  175. IN PVOID Reserved,
  176. IN PCDRMFORWARD DrmForward)
  177. {
  178. _DbgPrintF(DEBUGLVL_VERBOSE,("***IN ForwardToDeviceObject"));
  179. PDEVICE_OBJECT DeviceObject;
  180. PFILE_OBJECT FileObject;
  181. PVOID Context;
  182. NTSTATUS Status;
  183. KSP_DRMAUDIOSTREAM_CONTENTID Property;
  184. KSDRMAUDIOSTREAM_CONTENTID PropertyValue;
  185. Status = STATUS_SUCCESS;
  186. if (NULL != Reserved) {
  187. //
  188. // This is an older driver which passes the DeviceObject as the
  189. // second param and the Context as the third param.
  190. //
  191. DeviceObject = (PDEVICE_OBJECT)Reserved;
  192. FileObject = NULL;
  193. Context = (PVOID)DrmForward;
  194. } else {
  195. if (0 != DrmForward->Flags) {
  196. Status = STATUS_INVALID_PARAMETER;
  197. TheStreamMgr->logErrorToStream(ContentId, Status);
  198. } else {
  199. DeviceObject = DrmForward->DeviceObject;
  200. FileObject = DrmForward->FileObject;
  201. Context = DrmForward->Context;
  202. }
  203. }
  204. if (!NT_SUCCESS(Status)) return Status;
  205. if (DeviceObject)
  206. {
  207. KCritical s(TheStreamMgr->getCritMgr());
  208. if (0 != ContentId) {
  209. NTSTATUS stat=GetDeviceObjectDispatchTable(ContentId, DeviceObject, FALSE);
  210. }
  211. Property.Property.Set = KSPROPSETID_DrmAudioStream;
  212. Property.Property.Id = KSPROPERTY_DRMAUDIOSTREAM_CONTENTID;
  213. Property.Property.Flags = KSPROPERTY_TYPE_SET;
  214. Property.Context = Context;
  215. Property.DrmAddContentHandlers = DrmAddContentHandlers;
  216. Property.DrmCreateContentMixed = DrmCreateContentMixed;
  217. Property.DrmDestroyContent = DrmDestroyContent;
  218. Property.DrmForwardContentToDeviceObject = DrmForwardContentToDeviceObject;
  219. Property.DrmForwardContentToFileObject = DrmForwardContentToFileObject;
  220. Property.DrmForwardContentToInterface = DrmForwardContentToInterface;
  221. Property.DrmGetContentRights = DrmGetContentRights;
  222. PropertyValue.ContentId = ContentId;
  223. Status = TheStreamMgr->getRights(ContentId, &PropertyValue.DrmRights);
  224. if(!NT_SUCCESS(Status)){
  225. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad getRights for StreamId= %x", ContentId));
  226. return Status;
  227. };
  228. } else {
  229. _DbgPrintF(DEBUGLVL_VERBOSE,("Invalid NULL-parameter for DrmForwardContentToFileObject"));
  230. TheStreamMgr->logErrorToStream(ContentId, STATUS_INVALID_PARAMETER);
  231. return STATUS_INVALID_PARAMETER;
  232. }
  233. KEVENT Event;
  234. PIRP Irp;
  235. IO_STATUS_BLOCK IoStatusBlock;
  236. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  237. Irp = IoBuildDeviceIoControlRequest(
  238. IOCTL_KS_PROPERTY,
  239. DeviceObject,
  240. &Property,
  241. sizeof(Property),
  242. &PropertyValue,
  243. sizeof(PropertyValue),
  244. FALSE,
  245. &Event,
  246. &IoStatusBlock);
  247. if (Irp) {
  248. //
  249. // Originating in kernel, no need to probe buffers, etc.
  250. //
  251. Irp->RequestorMode = KernelMode;
  252. //
  253. // Set the file object in the next stack location
  254. //
  255. IoGetNextIrpStackLocation(Irp)->FileObject = FileObject;
  256. //
  257. Status = IoCallDriver(DeviceObject, Irp);
  258. if (Status == STATUS_PENDING) {
  259. //
  260. // This waits using KernelMode, so that the stack, and therefore the
  261. // event on that stack, is not paged out.
  262. //
  263. KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
  264. Status = IoStatusBlock.Status;
  265. }
  266. } else {
  267. Status = STATUS_INSUFFICIENT_RESOURCES;
  268. }
  269. // TBD: translate STATUS_PROPSET_NOT_FOUND to something better
  270. if(!NT_SUCCESS(Status)){
  271. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad IoControl for StreamId(2)= %x (Status=%d, %x)", ContentId, Status, Status));
  272. if (STATUS_NOT_IMPLEMENTED == Status) {
  273. TheStreamMgr->logErrorToStream(ContentId, DRM_RIGHTSNOTSUPPORTED);
  274. } else {
  275. TheStreamMgr->logErrorToStream(ContentId, Status);
  276. }
  277. return Status;
  278. };
  279. return STATUS_SUCCESS;
  280. }
  281. //--------------------------------------------------------------------------
  282. NTSTATUS DrmDestroyContent(IN ULONG ContentId)
  283. {
  284. KCritical s(TheStreamMgr->getCritMgr());
  285. _DbgPrintF(DEBUGLVL_VERBOSE,("DestroyStream for StreamId= %x", ContentId));
  286. NTSTATUS stat = TheStreamMgr->destroyStream(ContentId);
  287. if (!NT_SUCCESS(stat)){
  288. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad destroyStream for StreamId= %d", ContentId));
  289. // not sure if we should flag this as fatal (we sure can't log it to any stream)
  290. // TheStreamMgr->logErrorToStream(0, Status);
  291. return stat;
  292. };
  293. return STATUS_SUCCESS;
  294. }
  295. //---------------------------------------------------------------------------
  296. NTSTATUS DrmGetContentRights(IN DWORD ContentId, OUT DRMRIGHTS* DrmRights){
  297. KCritical s(TheStreamMgr->getCritMgr());
  298. NTSTATUS Status=TheStreamMgr->getRights(ContentId, DrmRights);
  299. if(!NT_SUCCESS(Status)){
  300. _DbgPrintF(DEBUGLVL_VERBOSE,("getRights failed for StreamId= %x", ContentId));
  301. return Status;
  302. };
  303. return Status;
  304. };
  305. //---------------------------------------------------------------------------
  306. NTSTATUS DrmAddContentHandlers(IN ULONG ContentId, IN PVOID* paHandlers, IN ULONG NumHandlers)
  307. {
  308. KCritical s(TheStreamMgr->getCritMgr());
  309. ULONG i;
  310. NTSTATUS Status = STATUS_SUCCESS;
  311. if (0 != ContentId) {
  312. for (i = 0; i < NumHandlers && NT_SUCCESS(Status); i++) {
  313. if (paHandlers[i]) {
  314. Status = TheStreamMgr->addProvingFunction(ContentId, paHandlers[i]);
  315. if(!NT_SUCCESS(Status)){
  316. _DbgPrintF(DEBUGLVL_VERBOSE,("addProveFunc Failed for StreamId= %x", ContentId));
  317. TheStreamMgr->logErrorToStream(ContentId, Status);
  318. };
  319. }
  320. }
  321. }
  322. return Status;
  323. }
  324. //---------------------------------------------------------------------------
  325. static NTSTATUS GetFileObjectDispatchTable(IN DWORD ContentId, IN PFILE_OBJECT pF){
  326. if(pF==NULL){
  327. _DbgPrintF(DEBUGLVL_VERBOSE,("Invalid FILE_OBJECT on stream %x", ContentId));
  328. return STATUS_INVALID_PARAMETER;
  329. };
  330. PDEVICE_OBJECT pDevO=pF->DeviceObject;
  331. if(pDevO==NULL){
  332. _DbgPrintF(DEBUGLVL_VERBOSE,("Invalid DEVICE_OBJECT for stream %x on PFILE_OBJECT = %x", ContentId, pF));
  333. return STATUS_INVALID_PARAMETER;
  334. };
  335. NTSTATUS stat=GetDeviceObjectDispatchTable(ContentId, pDevO, TRUE);
  336. if(!NT_SUCCESS(stat)){
  337. return stat;
  338. };
  339. return stat;
  340. };
  341. //---------------------------------------------------------------------------
  342. static NTSTATUS GetDeviceObjectDispatchTable(IN DWORD ContentId, IN _DEVICE_OBJECT* pDevO, BOOL fCheckAttached){
  343. _DRIVER_OBJECT* pDriverObject=pDevO->DriverObject;
  344. if(pDriverObject==NULL){
  345. _DbgPrintF(DEBUGLVL_VERBOSE,("Invalid PDRIVER_OBJECT for stream %x", ContentId));
  346. return STATUS_INVALID_PARAMETER;
  347. };
  348. // collect the dispatch table.
  349. for(DWORD j=0;j<IRP_MJ_MAXIMUM_FUNCTION;j++){
  350. PDRIVER_DISPATCH pDisp=pDriverObject->MajorFunction[j];
  351. if(pDisp==NULL)continue;
  352. // _DbgPrintF(DEBUGLVL_VERBOSE,("DISPATCH (%3d) devO =%10x, func=%10x", j, pDevO, pDisp));
  353. DRM_STATUS stat=TheStreamMgr->addProvingFunction(ContentId, pDisp);
  354. if(stat!=DRM_OK){
  355. _DbgPrintF(DEBUGLVL_VERBOSE,("bad AddProve on stream %x (error=%x)", ContentId));
  356. return STATUS_INSUFFICIENT_RESOURCES;
  357. };
  358. };
  359. // collect the other driver entry points
  360. const DWORD numMiscEntries=4;
  361. PVOID miscEntry[numMiscEntries];
  362. miscEntry[0]=pDriverObject->DriverExtension->AddDevice;
  363. miscEntry[1]=pDriverObject->DriverUnload;
  364. miscEntry[2]=pDriverObject->DriverStartIo;
  365. miscEntry[3]=pDriverObject->DriverInit;
  366. for(j=0;j<numMiscEntries;j++){
  367. if(NULL!=miscEntry[j]){
  368. DRM_STATUS stat=TheStreamMgr->addProvingFunction(ContentId, miscEntry[j]);
  369. if(stat!=DRM_OK){
  370. _DbgPrintF(DEBUGLVL_VERBOSE,("bad AddProve on stream %x (error=%x)", ContentId));
  371. return STATUS_INSUFFICIENT_RESOURCES;
  372. };
  373. };
  374. };
  375. // collect the fastIo dispatch points (if they are present)
  376. FAST_IO_DISPATCH* pFastIo=pDriverObject->FastIoDispatch;
  377. if(NULL!=pFastIo){
  378. ULONG numFastIo=(pFastIo->SizeOfFastIoDispatch - sizeof(pFastIo->SizeOfFastIoDispatch)) / sizeof(PVOID);
  379. if(numFastIo!=0){
  380. _DbgPrintF(DEBUGLVL_VERBOSE,("FASTIO DISPATCH: Num=", numFastIo));
  381. // Collect the FastIo entries. wdm.h makes has some strict requirements on
  382. // editing this structure, which means that we can pick up the entries as if
  383. // they were in a real array.
  384. PVOID* fastIoTable= (PVOID*)&(pFastIo->FastIoCheckIfPossible);
  385. for(ULONG j=0;j<numFastIo;j++){
  386. PVOID fastIoEntry= *(fastIoTable+j);
  387. if(NULL!=fastIoEntry){
  388. DRM_STATUS stat=TheStreamMgr->addProvingFunction(ContentId, fastIoEntry);
  389. if(stat!=DRM_OK){
  390. _DbgPrintF(DEBUGLVL_VERBOSE,("bad AddProve on stream %x (error=%x)", ContentId));
  391. return STATUS_INSUFFICIENT_RESOURCES;
  392. };
  393. };
  394. };
  395. };
  396. };
  397. // now traverse the driver stack (if there is one)
  398. if (fCheckAttached) {
  399. _DEVICE_OBJECT* pNextDevice=pDevO->AttachedDevice;
  400. if(NULL == pNextDevice)return STATUS_SUCCESS;
  401. NTSTATUS stat=GetDeviceObjectDispatchTable(ContentId, pNextDevice, fCheckAttached);
  402. if(!NT_SUCCESS(stat)){
  403. _DbgPrintF(DEBUGLVL_VERBOSE,("Failed to add dispatch entries from attached device on stream=%x ", ContentId));
  404. return stat;
  405. };
  406. }
  407. // Verifier and Acpi are special case filter drivers. Instead of modifying them
  408. // to handle DRM, we assume that it blindly "forwards" everything to the next
  409. // lower driver
  410. if (NT_SUCCESS(IoDeviceIsVerifier(pDevO)) || NT_SUCCESS(IoDeviceIsAcpi(pDevO)))
  411. {
  412. PDEVICE_OBJECT LowerDeviceObject = IoGetLowerDeviceObject(pDevO);
  413. _DbgPrintF(DEBUGLVL_TERSE,("Detected Verifier or Acpi on DO %p, checked lower DO", pDevO));
  414. if (LowerDeviceObject)
  415. {
  416. NTSTATUS status = GetDeviceObjectDispatchTable(ContentId, LowerDeviceObject, FALSE);
  417. ObDereferenceObject(LowerDeviceObject);
  418. if (!NT_SUCCESS(status)) return status;
  419. }
  420. else
  421. {
  422. return STATUS_INVALID_DEVICE_REQUEST;
  423. }
  424. }
  425. return STATUS_SUCCESS;
  426. };
  427. //---------------------------------------------------------------------------