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.

520 lines
18 KiB

  1. #include "drmkPCH.h"
  2. #include "KList.h"
  3. #include "VRoot.h"
  4. #include "StreamMgr.h"
  5. //------------------------------------------------------------------------------
  6. StreamMgr* TheStreamMgr=NULL;
  7. // 'secondary root - lowest secondary stream ID
  8. #define SEC_ROOT 0x80000000
  9. //------------------------------------------------------------------------------
  10. StreamMgr::StreamMgr(){
  11. TheStreamMgr=this;
  12. nextStreamId=1;
  13. nextCompositeId=SEC_ROOT+1;
  14. criticalErrorCode=STATUS_SUCCESS;
  15. if(!critMgr.isOK()){
  16. _DbgPrintF(DEBUGLVL_VERBOSE,("Out of memory"));
  17. criticalErrorCode=STATUS_INSUFFICIENT_RESOURCES;
  18. };
  19. return;
  20. };
  21. //------------------------------------------------------------------------------
  22. StreamMgr::~StreamMgr(){
  23. {
  24. KCritical s(critMgr);
  25. POS p=primary.getHeadPosition();
  26. while(p!=NULL){
  27. StreamInfo* info=primary.getNext(p);
  28. delete info;
  29. };
  30. p=composite.getHeadPosition();
  31. while(p!=NULL){
  32. CompositeStreamInfo* info=composite.getNext(p);
  33. delete info;
  34. };
  35. };
  36. return;
  37. };
  38. //------------------------------------------------------------------------------
  39. DRM_STATUS StreamMgr::createStream(HANDLE Handle, DWORD* StreamId,
  40. const DRMRIGHTS* RightsStruct, IN STREAMKEY* Key){
  41. *StreamId = 0xFFFFffff;
  42. StreamInfo* newInfo=new StreamInfo;
  43. if(newInfo==NULL){
  44. _DbgPrintF(DEBUGLVL_BLAB,("Out of memory"));
  45. return DRM_OUTOFMEMORY;
  46. };
  47. newInfo->StreamId=nextStreamId++;
  48. newInfo->Handle=Handle;
  49. newInfo->Key= *Key;
  50. newInfo->Rights= *RightsStruct;
  51. newInfo->drmFormat=NULL;
  52. newInfo->streamStatus=DRM_OK;
  53. newInfo->streamWalked=false;
  54. newInfo->newProveFuncs=false;
  55. newInfo->OutType=IsUndefined;
  56. newInfo->OutInt=NULL;
  57. newInfo->OutPinFileObject=NULL;
  58. newInfo->OutPinDeviceObject=NULL;
  59. bool ok=addStream(*newInfo);
  60. if(!ok){
  61. _DbgPrintF(DEBUGLVL_BLAB,("Out of memory"));
  62. delete newInfo;
  63. return DRM_OUTOFMEMORY;
  64. };
  65. *StreamId= newInfo->StreamId;
  66. return KRM_OK;
  67. };
  68. //------------------------------------------------------------------------------
  69. DRM_STATUS StreamMgr::destroyStream(DWORD StreamId){
  70. KCritical s(critMgr);
  71. if(StreamId==0){
  72. return KRM_OK;
  73. };
  74. POS pos=getStreamPos(StreamId);
  75. if(pos==NULL)return KRM_BADSTREAM;
  76. bool primary=StreamId<SEC_ROOT;
  77. deleteStreamAt(primary, pos);
  78. return KRM_OK;
  79. };
  80. //------------------------------------------------------------------------------
  81. // The 'handle' allows streams to be collected into a group and deleted together.
  82. // It is mostly for debugging
  83. DRM_STATUS StreamMgr::destroyAllStreamsByHandle(HANDLE Handle){
  84. KCritical s(critMgr);
  85. POS p=primary.getHeadPosition();
  86. while(p!=NULL){
  87. POS oldP=p;
  88. StreamInfo* stream=primary.getNext(p);
  89. if(stream->Handle==Handle){
  90. delete stream;
  91. primary.removeAt(oldP);
  92. };
  93. };
  94. return KRM_OK;
  95. };
  96. //------------------------------------------------------------------------------
  97. // Called by a filter to instuct StreamMgr that a mixed stream is being created.
  98. DRM_STATUS StreamMgr::createCompositeStream(OUT DWORD* StreamId, IN DWORD* StreamInArray, DWORD NumStreams){
  99. KCritical s(critMgr);
  100. CompositeStreamInfo* newStream=new CompositeStreamInfo;;
  101. if(newStream==NULL){
  102. _DbgPrintF(DEBUGLVL_BLAB,("Out of memory"));
  103. return DRM_OUTOFMEMORY;
  104. };
  105. for(DWORD j=0;j<NumStreams;j++){
  106. if(StreamInArray[j]==0)continue;
  107. bool ok=newStream->parents.addTail(StreamInArray[j]);
  108. if(!ok){
  109. delete newStream;
  110. _DbgPrintF(DEBUGLVL_BLAB,("Out of memory"));
  111. return DRM_OUTOFMEMORY;
  112. };
  113. };
  114. newStream->StreamId=nextCompositeId++;
  115. bool ok=composite.addTail(newStream);
  116. if(!ok){
  117. delete newStream;
  118. _DbgPrintF(DEBUGLVL_BLAB,("Out of memory"));
  119. return DRM_OUTOFMEMORY;
  120. };
  121. *StreamId=newStream->StreamId;
  122. return DRM_OK;
  123. };
  124. //------------------------------------------------------------------------------
  125. DRM_STATUS StreamMgr::destroyCompositeStream(IN DWORD CompositeStreamId){
  126. bool primary=(CompositeStreamId<SEC_ROOT);
  127. ASSERT(!primary);
  128. if(primary)return KRM_BADSTREAM;
  129. return destroyStream(CompositeStreamId);
  130. };
  131. //------------------------------------------------------------------------------
  132. // get the data encryption key for a stream.
  133. DRM_STATUS StreamMgr::getKey(IN DWORD StreamId, OUT STREAMKEY*& Key){
  134. KCritical s(critMgr);
  135. Key=NULL;
  136. if(StreamId>=SEC_ROOT)return KRM_NOTPRIMARY;
  137. POS pos=getStreamPos(StreamId);
  138. if(pos==NULL)return KRM_BADSTREAM;
  139. Key=&(primary.getAt(pos)->Key);
  140. return KRM_OK;
  141. };
  142. //------------------------------------------------------------------------------
  143. bool StreamMgr::addStream(StreamInfo& NewInfo){
  144. KCritical s(critMgr);
  145. return primary.addTail(&NewInfo);
  146. };
  147. //------------------------------------------------------------------------------
  148. POS StreamMgr::getStreamPos(DWORD StreamId){
  149. KCritical s(critMgr);
  150. if(StreamId<SEC_ROOT){
  151. POS p=primary.getHeadPosition();
  152. while(p!=NULL){
  153. POS oldPos=p;
  154. if(primary.getNext(p)->StreamId==StreamId)return oldPos;
  155. };
  156. return NULL;
  157. } else {
  158. POS p=composite.getHeadPosition();
  159. while(p!=NULL){
  160. POS oldPos=p;
  161. if(composite.getNext(p)->StreamId==StreamId)return oldPos;
  162. };
  163. return NULL;
  164. };
  165. };
  166. //------------------------------------------------------------------------------
  167. void StreamMgr::deleteStreamAt(bool Primary,POS pos){
  168. KCritical s(critMgr);
  169. if(Primary){
  170. StreamInfo* it=primary.getAt(pos);
  171. primary.removeAt(pos);
  172. delete it;
  173. } else {
  174. CompositeStreamInfo* it=composite.getAt(pos);
  175. composite.removeAt(pos);
  176. delete it;
  177. };
  178. };
  179. //------------------------------------------------------------------------------
  180. DRM_STATUS StreamMgr::getRights(DWORD StreamId,DRMRIGHTS* Rights){
  181. KCritical s(critMgr);
  182. DEFINE_DRMRIGHTS_DEFAULT(DrmRightsDefault);
  183. *Rights = DrmRightsDefault;
  184. return getRightsWorker(StreamId, Rights);
  185. };
  186. //------------------------------------------------------------------------------
  187. bool StreamMgr::isPrimaryStream(DWORD StreamId){
  188. return StreamId<SEC_ROOT;
  189. };
  190. //------------------------------------------------------------------------------
  191. // called recursively from the getRights parent
  192. DRM_STATUS StreamMgr::getRightsWorker(DWORD StreamId, DRMRIGHTS* Rights){
  193. if(isPrimaryStream(StreamId)){
  194. if(StreamId==0){
  195. // stream is unprotected - no further restrictions
  196. return DRM_OK;
  197. };
  198. // else a protected primary stream
  199. POS p=getStreamPos(StreamId);
  200. if(p==NULL){
  201. // if the primary stream has gone, then it does not care about
  202. // the stream rights. We do not flag an error
  203. _DbgPrintF(DEBUGLVL_BLAB,("Bad primary stream (getRightsWorker) %x", StreamId));
  204. return KRM_OK;
  205. };
  206. StreamInfo* s=primary.getAt(p);
  207. // set rights to most restrictive of current stream and current settings
  208. if(s->Rights.CopyProtect)Rights->CopyProtect=TRUE;
  209. if(s->Rights.DigitalOutputDisable)Rights->DigitalOutputDisable=TRUE;
  210. return DRM_OK;
  211. } else {
  212. // For composite streams, any of the parent streams can reduce the
  213. // current settings. We descend to the primary parents thru recursion.
  214. // Note, for this to work, we must have 'monotonic rights' - there should
  215. // be no case where two components disagree on 'more restrictive'
  216. POS pos=getStreamPos(StreamId);
  217. if(pos==NULL){
  218. _DbgPrintF(DEBUGLVL_BLAB,("Bad secondary stream"));
  219. Rights->CopyProtect=TRUE;
  220. Rights->DigitalOutputDisable=TRUE;
  221. return KRM_BADSTREAM;
  222. };
  223. CompositeStreamInfo* thisComp=composite.getAt(pos);
  224. POS p=thisComp->parents.getHeadPosition();
  225. while(p!=NULL){
  226. DWORD streamId=thisComp->parents.getNext(p);
  227. if(streamId==0)continue; // unprotected - no change to rights
  228. // else allow the parent stream (and its parents) to
  229. // further restrict rights
  230. DRM_STATUS stat=getRightsWorker(streamId, Rights);
  231. if(stat!=DRM_OK)return stat;
  232. };
  233. };
  234. return DRM_OK;
  235. };
  236. //------------------------------------------------------------------------------
  237. // Proving function is only of interest to parent stream. We recurse up the
  238. // stream parentage to all parents and add the proving fucntion to their lists.
  239. DRM_STATUS StreamMgr::addProvingFunction(DWORD StreamId,PVOID Func){
  240. KCritical s(critMgr);
  241. if(isPrimaryStream(StreamId)){
  242. StreamInfo* si=getPrimaryStream(StreamId);
  243. if(si==NULL){
  244. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad primary stream (addProveFunc) %x", StreamId));
  245. return DRM_BADPARAM;
  246. };
  247. // check to see if we already have this provinFunc
  248. POS p=si->proveFuncs.getHeadPosition();
  249. while(p!=NULL){
  250. PVOID addr=si->proveFuncs.getNext(p);
  251. if(addr==Func)return DRM_OK;
  252. };
  253. // if not, add it...
  254. bool ok=si->proveFuncs.addTail(Func);
  255. if(!ok){
  256. _DbgPrintF(DEBUGLVL_VERBOSE,("Out of memory"));
  257. return DRM_OUTOFMEMORY;
  258. };
  259. si->newProveFuncs = TRUE;
  260. return DRM_OK;
  261. };
  262. // else is secondary...recurse to root.
  263. CompositeStreamInfo* comp=getCompositeStream(StreamId);
  264. if(comp==NULL){
  265. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad streamId %x", StreamId));
  266. return DRM_BADPARAM;
  267. };
  268. POS p=comp->parents.getHeadPosition();
  269. while(p!=NULL){
  270. DWORD parentId=comp->parents.getNext(p);
  271. addProvingFunction(parentId, Func);
  272. };
  273. return DRM_OK;
  274. };
  275. //------------------------------------------------------------------------------
  276. StreamMgr::StreamInfo* StreamMgr::getPrimaryStream(DWORD StreamId){
  277. KCritical s(critMgr);
  278. POS pos=getStreamPos(StreamId);
  279. if(pos==NULL)return NULL;
  280. return primary.getAt(pos);
  281. };
  282. //------------------------------------------------------------------------------
  283. StreamMgr::CompositeStreamInfo* StreamMgr::getCompositeStream(DWORD StreamId){
  284. KCritical s(critMgr);
  285. POS pos=getStreamPos(StreamId);
  286. if(pos==NULL)return NULL;
  287. return composite.getAt(pos);
  288. };
  289. //------------------------------------------------------------------------------
  290. DRM_STATUS StreamMgr::walkDrivers(DWORD StreamId, PVOID* ProveFuncList, DWORD& NumDrivers, DWORD MaxDrivers)
  291. {
  292. DRM_STATUS stat;
  293. VRoot root;
  294. PFILE_OBJECT OutPinFileObject;
  295. PDEVICE_OBJECT OutPinDeviceObject;
  296. PUNKNOWN OutInt;
  297. OutPinFileObject = NULL;
  298. OutPinDeviceObject = NULL;
  299. OutInt = NULL;
  300. {
  301. KCritical s(critMgr);
  302. StreamInfo* stream;
  303. stream=getPrimaryStream(StreamId);
  304. if(stream==NULL)return KRM_BADSTREAM;
  305. if (0 != MaxDrivers) stream->proveFuncs.empty();
  306. stream->newProveFuncs=false;
  307. stream->streamStatus=DRM_OK;
  308. if(stream->OutType==IsUndefined){
  309. NumDrivers=0;
  310. // no output stream.
  311. _DbgPrintF(DEBUGLVL_VERBOSE,("No registered output module for stream %x", StreamId));
  312. return KRM_BADSTREAM;
  313. };
  314. //
  315. // We must reference the downstream object or interface before
  316. // releasing the StreamMgr mutex (i.e., before KCritical s goes out of
  317. // scope). Otherwise the downstream object/interface might be
  318. // destroyed after we release the StreamMgr mutex but before we
  319. // initiate validation on the downstream object/interface.
  320. //
  321. if ((stream->OutType == IsHandle) && stream->OutPinFileObject && stream->OutPinDeviceObject)
  322. {
  323. OutPinFileObject = stream->OutPinFileObject;
  324. OutPinDeviceObject = stream->OutPinDeviceObject;
  325. }
  326. else if ((stream->OutType == IsInterface) && stream->OutInt)
  327. {
  328. OutInt = stream->OutInt;
  329. }
  330. if (OutPinFileObject) ObReferenceObject(OutPinFileObject);
  331. if (OutInt) OutInt->AddRef();
  332. }
  333. if (OutPinFileObject) stat = root.initiateValidation(OutPinFileObject, OutPinDeviceObject, StreamId);
  334. if (OutInt) stat = root.initiateValidation(OutInt, StreamId);
  335. if (OutPinFileObject) ObDereferenceObject(OutPinFileObject);
  336. if (OutInt) OutInt->Release();
  337. {
  338. KCritical s(critMgr);
  339. StreamInfo* stream;
  340. // If STATUS_NOT_IMPLEMENTED, see if stream had DRM_RIGHTSNOTSUPPORTED logged as an error
  341. if (STATUS_NOT_IMPLEMENTED == stat) {
  342. DWORD errorStream;
  343. if (DRM_OK == TheStreamMgr->getStreamErrorCode(StreamId, errorStream)) {
  344. if (DRM_RIGHTSNOTSUPPORTED == errorStream) {
  345. stat = errorStream;
  346. }
  347. }
  348. }
  349. //Check to see if the stream had DRM_BADDRMLEVEL set. This return
  350. //code indicates that one or more drivers called
  351. //DrmForwardContentToFileObject, but otherwise no fatal errors
  352. //occurred. This should be treated as a success with the return
  353. //code propagated to the caller.
  354. {
  355. DWORD errorStream;
  356. if (DRM_OK == TheStreamMgr->getStreamErrorCode(StreamId, errorStream)) {
  357. if (DRM_BADDRMLEVEL == errorStream) {
  358. stat = errorStream;
  359. }
  360. }
  361. }
  362. // Although it would probably be due to a user-mode bug, we should not
  363. // assume that stream is still valid. Let's get the stream once again
  364. // from the StreamId
  365. stream=getPrimaryStream(StreamId);
  366. if(stream==NULL)return KRM_BADSTREAM;
  367. // pass out the array of ProveFuncs (there might've been an error, but we pass out what we can)
  368. POS p=stream->proveFuncs.getHeadPosition();
  369. DWORD count=0;
  370. while(p!=NULL){
  371. PVOID pf=stream->proveFuncs.getNext(p);
  372. if(count<MaxDrivers){
  373. ProveFuncList[count]=pf;
  374. };
  375. count++;
  376. };
  377. NumDrivers=count;
  378. // if there was an error on the walk, return that too.
  379. if((stat!=DRM_OK) && (DRM_BADDRMLEVEL!=stat)){
  380. // bug - todo - return some useful information
  381. _DbgPrintF(DEBUGLVL_VERBOSE,("VRoot::initiateValidation(streeamId=%d) returned (%d, %x)", StreamId, stat, stat));
  382. NumDrivers=0;
  383. return stat;
  384. };
  385. // if checking stack and new funcs were added
  386. if ((0 == MaxDrivers) && (stream->newProveFuncs))
  387. return DRM_AUTHREQUIRED;
  388. // and finally, inform if there was insufficient buffer space.
  389. if((0 == MaxDrivers) || (count<MaxDrivers))
  390. return (DRM_OK == stat) ? KRM_OK : stat;
  391. else
  392. return KRM_BUFSIZE;
  393. }
  394. };
  395. //------------------------------------------------------------------------------
  396. DRM_STATUS StreamMgr::setRecipient(DWORD StreamId, PFILE_OBJECT OutPinFileObject, PDEVICE_OBJECT OutPinDeviceObject){
  397. KCritical s(critMgr);
  398. StreamInfo* stream=getPrimaryStream(StreamId);
  399. if(stream==NULL)return KRM_BADSTREAM;
  400. stream->OutPinFileObject=OutPinFileObject;
  401. stream->OutPinDeviceObject=OutPinDeviceObject;
  402. stream->OutType=IsHandle;
  403. return DRM_OK;
  404. };
  405. //------------------------------------------------------------------------------
  406. DRM_STATUS StreamMgr::setRecipient(DWORD StreamId, PUNKNOWN OutInt){
  407. KCritical s(critMgr);
  408. StreamInfo* stream=getPrimaryStream(StreamId);
  409. if(stream==NULL)return KRM_BADSTREAM;
  410. stream->OutInt=OutInt;
  411. stream->OutType=IsInterface;
  412. return DRM_OK;
  413. };
  414. //------------------------------------------------------------------------------
  415. DRM_STATUS StreamMgr::clearRecipient(IN DWORD StreamId){
  416. KCritical s(critMgr);
  417. StreamInfo* stream=getPrimaryStream(StreamId);
  418. if(stream==NULL)return KRM_BADSTREAM;
  419. stream->OutType=IsUndefined;
  420. stream->OutPinFileObject = NULL;
  421. stream->OutPinDeviceObject = NULL;
  422. stream->OutInt = NULL;
  423. return DRM_OK;
  424. };
  425. //------------------------------------------------------------------------------
  426. void StreamMgr::logErrorToStream(IN DWORD StreamId, DWORD ErrorCode){
  427. KCritical s(critMgr);
  428. logErrorToStreamWorker(StreamId, ErrorCode);
  429. return;
  430. };
  431. //------------------------------------------------------------------------------
  432. void StreamMgr::logErrorToStreamWorker(IN DWORD StreamId, DWORD ErrorCode){
  433. // don't allow an error to be cancelled too easily
  434. if(ErrorCode==0)return;
  435. if(isPrimaryStream(StreamId)){
  436. StreamInfo* info=getPrimaryStream(StreamId);
  437. if(info==NULL){
  438. _DbgPrintF(DEBUGLVL_BLAB,("Bad primary stream (logErrorToStreamWorker) %x", StreamId));
  439. // if a primary stream does not exist, this is not considered
  440. // to be sufficient to set the panic flag.
  441. return;
  442. };
  443. info->streamStatus=ErrorCode;
  444. return;
  445. };
  446. CompositeStreamInfo* comp=getCompositeStream(StreamId);
  447. ASSERT(comp!=NULL);
  448. if(comp==NULL){
  449. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad streamId %x", StreamId));
  450. // if the secondary stream does not exist, we do not know what streams
  451. // are affected by the error, so the only safe thing is to panic.
  452. setFatalError(KRM_BADSTREAM);
  453. return;
  454. };
  455. // log the error with all of the streams parents, recursing back to the
  456. // primary streams.
  457. POS p=comp->parents.getHeadPosition();
  458. while(p!=NULL){
  459. DWORD parentId=comp->parents.getNext(p);
  460. logErrorToStreamWorker(parentId, ErrorCode);
  461. };
  462. return;
  463. };
  464. //------------------------------------------------------------------------------
  465. DRM_STATUS StreamMgr::getStreamErrorCode(IN DWORD StreamId, OUT DWORD& ErrorCode){
  466. KCritical s(critMgr);
  467. StreamInfo* info=getPrimaryStream(StreamId);
  468. ErrorCode=DRM_AUTHFAILURE;
  469. if(info==NULL){
  470. _DbgPrintF(DEBUGLVL_BLAB,("Bad primary stream(getStreamErrorCode) %x", StreamId));
  471. return KRM_BADSTREAM;
  472. };
  473. ErrorCode=info->streamStatus;
  474. return DRM_OK;
  475. };
  476. //------------------------------------------------------------------------------
  477. DRM_STATUS StreamMgr::clearStreamError(IN DWORD StreamId){
  478. KCritical s(critMgr);
  479. StreamInfo* info=getPrimaryStream(StreamId);
  480. if(info==NULL){
  481. _DbgPrintF(DEBUGLVL_BLAB,("Bad primary stream (clearStreamError) %x", StreamId));
  482. return KRM_BADSTREAM;
  483. };
  484. info->streamStatus=DRM_OK;
  485. return DRM_OK;
  486. };
  487. //------------------------------------------------------------------------------
  488. void StreamMgr::setFatalError(DWORD ErrorCode){
  489. if(criticalErrorCode!=STATUS_SUCCESS) return;
  490. criticalErrorCode=ErrorCode;
  491. };
  492. //------------------------------------------------------------------------------
  493. NTSTATUS StreamMgr::getFatalError(){
  494. return criticalErrorCode;
  495. };
  496. //------------------------------------------------------------------------------