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.

1529 lines
48 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. certdb.c
  5. Abstract:
  6. License Logging Service certificate database implementation. This database
  7. tracks license certificates to help ensure that no more licenses from a
  8. single certificate are installe don the license enterprise than are allowed
  9. by the certificate's license agreement.
  10. The certificate database at the top level is an unsorted array of
  11. certificate headers. There is exactly one header per unique certificate.
  12. A unique certificate is identified by a combination of product name,
  13. certificate ID, certificate capacity (max. licenses legally installable),
  14. and expiration date.
  15. Each header has an attached array of certificate claims. There is exactly
  16. one claim per machine that (a) replicates to this machine, directly or
  17. indirectly, and (b) has licenses from this certificate installed. Each
  18. claim contains the server name to which it corresponds, the number of
  19. licenses installed on it, and the date this information was replicated.
  20. If a claim is not updated after LLS_CERT_DB_REPLICATION_DATE_DELTA_MAX
  21. seconds (3 days as of this writing), the claim is considered forfeit and
  22. is erased.
  23. Author:
  24. Jeff Parham (jeffparh) 08-Dec-1995
  25. Revision History:
  26. --*/
  27. #include <stdlib.h>
  28. #include <limits.h>
  29. #include <nt.h>
  30. #include <ntrtl.h>
  31. #include <nturtl.h>
  32. #include <windows.h>
  33. #include <rpc.h>
  34. #include <rpcndr.h>
  35. #include <dsgetdc.h>
  36. #include "debug.h"
  37. #include "llsutil.h"
  38. #include "llssrv.h"
  39. #include "llsapi.h"
  40. #include "llsevent.h"
  41. #include "llsrpc_s.h"
  42. #include "certdb.h"
  43. #include "purchase.h"
  44. #include "registry.h"
  45. #include <strsafe.h> //include last
  46. RTL_RESOURCE CertDbHeaderListLock;
  47. static PLLS_CERT_DB_CERTIFICATE_HEADER CertDbHeaderList = NULL;
  48. static DWORD CertDbHeaderListSize = 0;
  49. static HANDLE CertDbFile = NULL;
  50. ///////////////////////////////////////////////////////////////////////////////
  51. NTSTATUS CertDbClaimEnter( LPTSTR pszServerName,
  52. PLLS_LICENSE_INFO_1 pLicense,
  53. BOOL bIsTotal,
  54. DWORD ReplicationDate )
  55. /*++
  56. Routine Description:
  57. Enter a claim into the database.
  58. Arguments:
  59. pszServerName (LPTSTR)
  60. The server for which to enter this claim. A value of NULL indicates the
  61. local server.
  62. pLicense (PLLS_LICENSE_INFO_1)
  63. License information to enter into the database.
  64. bIsTotal (BOOL)
  65. If TRUE, indicates that this license information represents the total
  66. licenses installed on the machine and should therefore replace the
  67. current claim (if any). Otherwise, indicates this license information
  68. should be added to the current claim (if any).
  69. ReplicationDate (DWORD)
  70. Indicates the date which this information was last replicated. A value
  71. of 0 will be replaced with the current system time.
  72. Return Value:
  73. STATUS_SUCCESS
  74. STATUS_INVALID_PARAMETER
  75. STATUS_INVALID_COMPUTER_NAME
  76. STATUS_NO_MEMORY
  77. --*/
  78. {
  79. NTSTATUS nt;
  80. HRESULT hr;
  81. if ( ( NULL == pLicense ) || ( 0 == pLicense->CertificateID ) )
  82. {
  83. ASSERT( FALSE );
  84. nt = STATUS_INVALID_PARAMETER;
  85. }
  86. else
  87. {
  88. TCHAR szComputerName[ 1 + MAX_COMPUTERNAME_LENGTH ];
  89. if ( NULL == pszServerName )
  90. {
  91. // use local server name
  92. DWORD cchComputerName = sizeof( szComputerName ) / sizeof( *szComputerName );
  93. BOOL ok;
  94. ok = GetComputerName( szComputerName, &cchComputerName );
  95. ASSERT( ok );
  96. if ( ok )
  97. {
  98. pszServerName = szComputerName;
  99. }
  100. }
  101. else
  102. {
  103. // remove leading backslashes (if any) from server name
  104. while ( TEXT('\\') == *pszServerName )
  105. {
  106. pszServerName++;
  107. }
  108. }
  109. if ( ( NULL == pszServerName ) || !*pszServerName || ( lstrlen( pszServerName ) > MAX_COMPUTERNAME_LENGTH ) )
  110. {
  111. ASSERT( FALSE );
  112. nt = STATUS_INVALID_COMPUTER_NAME;
  113. }
  114. else
  115. {
  116. PLLS_CERT_DB_CERTIFICATE_HEADER pHeader;
  117. RtlAcquireResourceExclusive( &CertDbHeaderListLock, TRUE );
  118. // is the certificate in the db?
  119. pHeader = CertDbHeaderFind( pLicense );
  120. if ( NULL == pHeader )
  121. {
  122. // certificate not yet in db; add it
  123. pHeader = CertDbHeaderAdd( pLicense );
  124. }
  125. if ( NULL == pHeader )
  126. {
  127. // could not find or add header
  128. ASSERT( FALSE );
  129. nt = STATUS_NO_MEMORY;
  130. }
  131. else
  132. {
  133. // now have header; is this claim already filed?
  134. int iClaim;
  135. iClaim = CertDbClaimFind( pHeader, pszServerName );
  136. if ( iClaim < 0 )
  137. {
  138. PLLS_CERT_DB_CERTIFICATE_CLAIM pClaimsTmp;
  139. // claim does not yet exist; add it
  140. if ( NULL == pHeader->Claims )
  141. {
  142. pClaimsTmp = LocalAlloc( LPTR, ( 1 + pHeader->NumClaims ) * sizeof( LLS_CERT_DB_CERTIFICATE_CLAIM ) );
  143. }
  144. else
  145. {
  146. pClaimsTmp = LocalReAlloc( pHeader->Claims, ( 1 + pHeader->NumClaims ) * sizeof( LLS_CERT_DB_CERTIFICATE_CLAIM ), LHND );
  147. }
  148. if ( NULL != pClaimsTmp )
  149. {
  150. // memory allocation succeeded
  151. // claim list expanded; save server name
  152. pHeader->Claims = pClaimsTmp;
  153. iClaim = pHeader->NumClaims;
  154. hr = StringCbCopy( pHeader->Claims[ iClaim ].ServerName, sizeof(pHeader->Claims[iClaim].ServerName), pszServerName );
  155. ASSERT(SUCCEEDED(hr));
  156. pHeader->Claims[ iClaim ].Quantity = 0;
  157. pHeader->NumClaims++;
  158. }
  159. }
  160. if ( iClaim < 0 )
  161. {
  162. // could not find or add claim to header
  163. ASSERT( FALSE );
  164. nt = STATUS_NO_MEMORY;
  165. }
  166. else
  167. {
  168. // claim found or added; update info
  169. ASSERT( !lstrcmpi( pszServerName, pHeader->Claims[ iClaim ].ServerName ) );
  170. pHeader->Claims[ iClaim ].ReplicationDate = ReplicationDate ? ReplicationDate : DateSystemGet();
  171. if ( bIsTotal )
  172. {
  173. // the given value is the new total
  174. pHeader->Claims[ iClaim ].Quantity = pLicense->Quantity;
  175. nt = STATUS_SUCCESS;
  176. }
  177. else if ( pHeader->Claims[ iClaim ].Quantity + pLicense->Quantity >= 0 )
  178. {
  179. // the given value is added to the current sum to make the total
  180. pHeader->Claims[ iClaim ].Quantity += pLicense->Quantity;
  181. nt = STATUS_SUCCESS;
  182. }
  183. else
  184. {
  185. // overflow
  186. nt = STATUS_INVALID_PARAMETER;
  187. }
  188. }
  189. }
  190. RtlReleaseResource( &CertDbHeaderListLock );
  191. if ( STATUS_SUCCESS == nt )
  192. {
  193. // any product that has licenses with non-0 certificate IDs
  194. // must be secure; this code is here such that when certificates
  195. // are replicated, the "product is secure" info is replicated, too
  196. // this will also help recover from the case where someone deletes
  197. // the registry key that lists all secure products
  198. ServiceSecuritySet( pLicense->Product );
  199. }
  200. }
  201. }
  202. return nt;
  203. }
  204. ///////////////////////////////////////////////////////////////////////////////
  205. BOOL CertDbClaimApprove( PLLS_LICENSE_INFO_1 pLicense )
  206. /*++
  207. Routine Description:
  208. Check to see if adding the given licenses is legal. This call is typically
  209. made before adding a license into the system to verify that doing so does
  210. not violate the certificate's license agreement.
  211. Arguments:
  212. pLicense (PLLS_LICENSE_INFO_1)
  213. License information for which approval is sought.
  214. Return Value:
  215. TRUE (approved) or FALSE (rejected).
  216. --*/
  217. {
  218. BOOL bOkToAdd = TRUE;
  219. PLLS_CERT_DB_CERTIFICATE_HEADER pHeader;
  220. TCHAR szComputerName[ 1 + MAX_COMPUTERNAME_LENGTH ];
  221. DWORD cchComputerName = sizeof( szComputerName ) / sizeof( *szComputerName );
  222. BOOL ok;
  223. ASSERT(NULL != pLicense);
  224. if ( ( pLicense->Quantity > 0 ) && ( (DWORD)pLicense->Quantity > pLicense->MaxQuantity ) )
  225. {
  226. // certificate add request exceeds its capacity all by itself!
  227. bOkToAdd = FALSE;
  228. }
  229. else
  230. {
  231. ok = GetComputerName( szComputerName, &cchComputerName );
  232. ASSERT( ok );
  233. if ( !ok )
  234. {
  235. // deletions will fail...
  236. *szComputerName = TEXT( '\0' );
  237. }
  238. // do we have a record of this certificate?
  239. RtlAcquireResourceShared( &CertDbHeaderListLock, TRUE );
  240. pHeader = CertDbHeaderFind( pLicense );
  241. if ( NULL == pHeader )
  242. {
  243. // don't have any record of this certificate; ok to add if Quantity > 0
  244. bOkToAdd = ( pLicense->Quantity > 0 );
  245. }
  246. else
  247. {
  248. LONG lTotalQuantity = 0;
  249. int iClaim;
  250. // we have seen this certificate; are there enough licenses available?
  251. for ( iClaim=0; (DWORD)iClaim < pHeader->NumClaims; iClaim++ )
  252. {
  253. // for license remove requests, tally only local licenses
  254. // for license add requests, tally all licenses
  255. if ( ( ( pLicense->Quantity > 0 )
  256. || ( !lstrcmpi( pHeader->Claims[ iClaim ].ServerName, szComputerName ) ) )
  257. && ( lTotalQuantity + pHeader->Claims[ iClaim ].Quantity >= 0 ) )
  258. {
  259. // add to tally
  260. lTotalQuantity += pHeader->Claims[ iClaim ].Quantity;
  261. }
  262. }
  263. if ( lTotalQuantity + pLicense->Quantity < 0 )
  264. {
  265. // overflow or underflow
  266. bOkToAdd = FALSE;
  267. }
  268. else if ( (DWORD)(lTotalQuantity + pLicense->Quantity) > pHeader->MaxQuantity )
  269. {
  270. // exceeds certificate capacity
  271. bOkToAdd = FALSE;
  272. }
  273. else
  274. {
  275. // okay by me
  276. bOkToAdd = TRUE;
  277. }
  278. }
  279. RtlReleaseResource( &CertDbHeaderListLock );
  280. }
  281. return bOkToAdd;
  282. }
  283. ///////////////////////////////////////////////////////////////////////////////
  284. PLLS_CERT_DB_CERTIFICATE_HEADER CertDbHeaderFind( PLLS_LICENSE_INFO_1 pLicense )
  285. /*++
  286. Routine Description:
  287. Find a certificate header in the database.
  288. Arguments:
  289. pLicense (PLLS_LICENSE_INFO_1)
  290. License information for which to find the appropriate header.
  291. Return Value:
  292. A pointer to the found header, or NULL if not found.
  293. --*/
  294. {
  295. // assumes db is already locked for shared or exclusive access
  296. PLLS_CERT_DB_CERTIFICATE_HEADER pHeader = NULL;
  297. int iHeader;
  298. for ( iHeader=0; ( NULL == pHeader ) && ( (DWORD)iHeader < CertDbHeaderListSize ); iHeader++ )
  299. {
  300. if ( ( CertDbHeaderList[ iHeader ].CertificateID == pLicense->CertificateID )
  301. && ( CertDbHeaderList[ iHeader ].MaxQuantity == pLicense->MaxQuantity )
  302. && ( CertDbHeaderList[ iHeader ].ExpirationDate == pLicense->ExpirationDate )
  303. && ( !lstrcmpi( CertDbHeaderList[ iHeader ].Product, pLicense->Product ) ) )
  304. {
  305. // header found!
  306. pHeader = &CertDbHeaderList[ iHeader ];
  307. }
  308. }
  309. return pHeader;
  310. }
  311. ///////////////////////////////////////////////////////////////////////////////
  312. PLLS_CERT_DB_CERTIFICATE_HEADER CertDbHeaderAdd( PLLS_LICENSE_INFO_1 pLicense )
  313. /*++
  314. Routine Description:
  315. Add a certificate header to the database.
  316. Arguments:
  317. pLicense (PLLS_LICENSE_INFO_1)
  318. License information for which to add the header.
  319. Return Value:
  320. A pointer to the added header, or NULL if memory could not be allocated.
  321. --*/
  322. {
  323. // assumes caller has made sure the header does not already exist
  324. // assumes db is locked for exclusive access
  325. HRESULT hr;
  326. size_t cch;
  327. PLLS_CERT_DB_CERTIFICATE_HEADER pHeader;
  328. if ( CertDbHeaderListSize )
  329. {
  330. pHeader = LocalReAlloc( CertDbHeaderList, ( 1 + CertDbHeaderListSize ) * sizeof( LLS_CERT_DB_CERTIFICATE_HEADER ), LHND );
  331. }
  332. else
  333. {
  334. pHeader = LocalAlloc( LPTR, ( 1 + CertDbHeaderListSize ) * sizeof( LLS_CERT_DB_CERTIFICATE_HEADER ) );
  335. }
  336. if ( NULL != pHeader )
  337. {
  338. CertDbHeaderList = pHeader;
  339. // allocate space for product name
  340. ASSERT(NULL != pLicense);
  341. cch = 1 + lstrlen( pLicense->Product );
  342. CertDbHeaderList[ CertDbHeaderListSize ].Product = LocalAlloc( LPTR, sizeof( TCHAR ) * cch );
  343. if ( NULL == CertDbHeaderList[ CertDbHeaderListSize ].Product )
  344. {
  345. // memory allocation failed
  346. ASSERT( FALSE );
  347. pHeader = NULL;
  348. }
  349. else
  350. {
  351. // success!
  352. pHeader = &CertDbHeaderList[ CertDbHeaderListSize ];
  353. CertDbHeaderListSize++;
  354. hr = StringCchCopy( pHeader->Product, cch, pLicense->Product );
  355. ASSERT(SUCCEEDED(hr));
  356. pHeader->CertificateID = pLicense->CertificateID;
  357. pHeader->MaxQuantity = pLicense->MaxQuantity;
  358. pHeader->ExpirationDate = pLicense->ExpirationDate;
  359. }
  360. }
  361. return pHeader;
  362. }
  363. ///////////////////////////////////////////////////////////////////////////////
  364. int CertDbClaimFind( PLLS_CERT_DB_CERTIFICATE_HEADER pHeader, LPTSTR pszServerName )
  365. /*++
  366. Routine Description:
  367. Find a certificate claim for a specific server in the claim list.
  368. Arguments:
  369. pHeader (PLLS_CERT_DB_CERTIFICATE_HEADER)
  370. Header containing the claim list to search.
  371. pszServerName (LPTSTR)
  372. Name of the server for which the claim is sought.
  373. Return Value:
  374. The index of the found claim, or -1 if not found.
  375. --*/
  376. {
  377. // assumes db is already locked for shared or exclusive access
  378. int iClaim;
  379. for ( iClaim=0; (DWORD)iClaim < pHeader->NumClaims; iClaim++ )
  380. {
  381. if ( !lstrcmpi( pHeader->Claims[ iClaim ].ServerName, pszServerName ) )
  382. {
  383. break;
  384. }
  385. }
  386. if ( (DWORD)iClaim >= pHeader->NumClaims )
  387. {
  388. iClaim = -1;
  389. }
  390. return iClaim;
  391. }
  392. ///////////////////////////////////////////////////////////////////////////////
  393. void CertDbPrune()
  394. /*++
  395. Routine Description:
  396. Remove entries in the database which have expired. Entries expire if they
  397. have not been re-replicated in LLS_CERT_DB_REPLICATION_DATE_DELTA_MAX
  398. seconds (3 days as of this writing).
  399. Arguments:
  400. None.
  401. Return Value:
  402. None.
  403. --*/
  404. {
  405. int iHeader;
  406. int iClaim;
  407. DWORD CurrentDate;
  408. DWORD MinimumDate;
  409. TCHAR szComputerName[ 1 + MAX_COMPUTERNAME_LENGTH ] = TEXT("");
  410. DWORD cchComputerName = sizeof( szComputerName ) / sizeof( *szComputerName );
  411. BOOL ok;
  412. ok = GetComputerName( szComputerName, &cchComputerName );
  413. ASSERT( ok );
  414. if ( ok )
  415. {
  416. RtlAcquireResourceExclusive( &CertDbHeaderListLock, TRUE );
  417. CurrentDate = DateSystemGet();
  418. MinimumDate = CurrentDate - LLS_CERT_DB_REPLICATION_DATE_DELTA_MAX;
  419. for ( iHeader=0; (DWORD)iHeader < CertDbHeaderListSize; iHeader++ )
  420. {
  421. for ( iClaim=0; (DWORD)iClaim < CertDbHeaderList[ iHeader ].NumClaims; )
  422. {
  423. // Note that we prune entries made in the future, too, to avoid having an incorrect date
  424. // forcing us to keep an entry forever.
  425. //
  426. // For this application, it's better to keep fewer entries rather than more, as the
  427. // fewer entries we have, the less restrictive the system is.
  428. //
  429. // Don't prune local entries.
  430. if ( ( ( CertDbHeaderList[ iHeader ].Claims[ iClaim ].ReplicationDate < MinimumDate )
  431. || ( CertDbHeaderList[ iHeader ].Claims[ iClaim ].ReplicationDate > CurrentDate ) )
  432. && lstrcmpi( szComputerName, CertDbHeaderList[ iHeader ].Claims[ iClaim ].ServerName ) )
  433. {
  434. // remove claim
  435. MoveMemory( &CertDbHeaderList[ iHeader ].Claims[ iClaim ],
  436. &CertDbHeaderList[ iHeader ].Claims[ iClaim+1 ],
  437. CertDbHeaderList[ iHeader ].NumClaims - ( iClaim + 1 ) );
  438. CertDbHeaderList[ iHeader ].NumClaims--;
  439. }
  440. else
  441. {
  442. // keep this claim
  443. iClaim++;
  444. }
  445. }
  446. }
  447. RtlReleaseResource( &CertDbHeaderListLock );
  448. }
  449. }
  450. ///////////////////////////////////////////////////////////////////////////////
  451. void CertDbRemoveLocalClaims()
  452. /*++
  453. Routine Description:
  454. Remove entries in the database corresponding to the local server.
  455. Arguments:
  456. None.
  457. Return Value:
  458. None.
  459. --*/
  460. {
  461. int iHeader;
  462. int iClaim;
  463. TCHAR szComputerName[ 1 + MAX_COMPUTERNAME_LENGTH ] = TEXT("");
  464. DWORD cchComputerName = sizeof( szComputerName ) / sizeof( *szComputerName );
  465. BOOL ok;
  466. ok = GetComputerName( szComputerName, &cchComputerName );
  467. ASSERT( ok );
  468. if ( ok )
  469. {
  470. RtlAcquireResourceExclusive( &CertDbHeaderListLock, TRUE );
  471. for ( iHeader=0; (DWORD)iHeader < CertDbHeaderListSize; iHeader++ )
  472. {
  473. for ( iClaim=0; (DWORD)iClaim < CertDbHeaderList[ iHeader ].NumClaims; )
  474. {
  475. if ( !lstrcmpi( szComputerName, CertDbHeaderList[ iHeader ].Claims[ iClaim ].ServerName ) )
  476. {
  477. // remove claim
  478. MoveMemory( &CertDbHeaderList[ iHeader ].Claims[ iClaim ],
  479. &CertDbHeaderList[ iHeader ].Claims[ iClaim+1 ],
  480. CertDbHeaderList[ iHeader ].NumClaims - ( iClaim + 1 ) );
  481. CertDbHeaderList[ iHeader ].NumClaims--;
  482. }
  483. else
  484. {
  485. // keep this claim
  486. iClaim++;
  487. }
  488. }
  489. }
  490. RtlReleaseResource( &CertDbHeaderListLock );
  491. }
  492. }
  493. ///////////////////////////////////////////////////////////////////////////////
  494. void CertDbLogViolations()
  495. /*++
  496. Routine Description:
  497. Log violations of certificate license agreements to the event log of the
  498. local server.
  499. Arguments:
  500. None.
  501. Return Value:
  502. None.
  503. --*/
  504. {
  505. int iHeader;
  506. int iClaim;
  507. HANDLE hEventLog;
  508. DWORD dwTotalQuantity;
  509. HINSTANCE hDll;
  510. DWORD cch;
  511. LPTSTR pszViolationServerEntryFormat;
  512. LPTSTR pszNextViolationServerEntry;
  513. TCHAR szNumLicenses[ 20 ];
  514. TCHAR szMaxLicenses[ 20 ];
  515. TCHAR szCertificateID[ 20 ];
  516. LPTSTR apszSubstStrings[ 5 ];
  517. DWORD cbViolationServerList;
  518. LPTSTR pszViolationServerList;
  519. // get rid of out-dated entries
  520. CertDbPrune();
  521. hDll = LoadLibrary( TEXT( "LLSRPC.DLL" ) );
  522. ASSERT( NULL != hDll );
  523. if ( NULL != hDll )
  524. {
  525. // format for part of logged message that lists server and #licenses
  526. cch = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER
  527. | FORMAT_MESSAGE_IGNORE_INSERTS
  528. | FORMAT_MESSAGE_FROM_HMODULE,
  529. hDll,
  530. LLS_EVENT_CERT_VIOLATION_SERVER_ENTRY,
  531. GetSystemDefaultLangID(),
  532. (LPVOID) &pszViolationServerEntryFormat,
  533. 0,
  534. NULL );
  535. if ( 0 != cch )
  536. {
  537. hEventLog = RegisterEventSource( NULL, TEXT("LicenseService") );
  538. if ( NULL != hEventLog )
  539. {
  540. RtlAcquireResourceShared( &CertDbHeaderListLock, TRUE );
  541. for ( iHeader=0; (DWORD)iHeader < CertDbHeaderListSize; iHeader++ )
  542. {
  543. dwTotalQuantity = 0;
  544. // tally the number of licenses claimed against this certificate
  545. for ( iClaim=0; (DWORD)iClaim < CertDbHeaderList[ iHeader ].NumClaims; iClaim++ )
  546. {
  547. if ( dwTotalQuantity + (DWORD)CertDbHeaderList[ iHeader ].Claims[ iClaim ].Quantity < dwTotalQuantity )
  548. {
  549. // overflow!
  550. dwTotalQuantity = ULONG_MAX;
  551. break;
  552. }
  553. else
  554. {
  555. // add to tally
  556. dwTotalQuantity += CertDbHeaderList[ iHeader ].Claims[ iClaim ].Quantity;
  557. }
  558. }
  559. if ( dwTotalQuantity > CertDbHeaderList[ iHeader ].MaxQuantity )
  560. {
  561. // this certificate is in violation
  562. // create message we're going to log
  563. cbViolationServerList = CertDbHeaderList[ iHeader ].NumClaims
  564. * sizeof( TCHAR )
  565. * ( lstrlen( pszViolationServerEntryFormat )
  566. + 20
  567. + MAX_COMPUTERNAME_LENGTH );
  568. pszViolationServerList = LocalAlloc( LPTR, cbViolationServerList );
  569. ASSERT( NULL != pszViolationServerList );
  570. if ( NULL != pszViolationServerList )
  571. {
  572. // create an entry for each server in violation, stringing them
  573. // together in pszViolationServerList
  574. pszNextViolationServerEntry = pszViolationServerList;
  575. for ( iClaim=0; (DWORD)iClaim < CertDbHeaderList[ iHeader ].NumClaims; iClaim++ )
  576. {
  577. _ltow( CertDbHeaderList[ iHeader ].Claims[ iClaim ].Quantity, szNumLicenses, 10 );
  578. apszSubstStrings[ 0 ] = CertDbHeaderList[ iHeader ].Claims[ iClaim ].ServerName;
  579. apszSubstStrings[ 1 ] = szNumLicenses;
  580. cch = FormatMessage( FORMAT_MESSAGE_FROM_STRING
  581. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  582. pszViolationServerEntryFormat,
  583. (DWORD)0,
  584. (DWORD)0,
  585. pszNextViolationServerEntry,
  586. cbViolationServerList - (DWORD)( pszNextViolationServerEntry - pszViolationServerList ),
  587. (va_list *) apszSubstStrings );
  588. ASSERT( 0 != cch );
  589. pszNextViolationServerEntry += lstrlen( pszNextViolationServerEntry );
  590. }
  591. _ultow( CertDbHeaderList[ iHeader ].CertificateID, szCertificateID, 10 );
  592. _ultow( dwTotalQuantity, szNumLicenses, 10 );
  593. _ultow( CertDbHeaderList[ iHeader ].MaxQuantity, szMaxLicenses, 10 );
  594. apszSubstStrings[ 0 ] = CertDbHeaderList[ iHeader ].Product;
  595. apszSubstStrings[ 1 ] = szCertificateID;
  596. apszSubstStrings[ 2 ] = szNumLicenses;
  597. apszSubstStrings[ 3 ] = szMaxLicenses;
  598. apszSubstStrings[ 4 ] = pszViolationServerList;
  599. // log the violation
  600. if ( NULL != hEventLog )
  601. {
  602. ReportEvent( hEventLog,
  603. EVENTLOG_ERROR_TYPE,
  604. 0,
  605. LLS_EVENT_CERT_VIOLATION,
  606. NULL,
  607. 5,
  608. 0,
  609. apszSubstStrings,
  610. NULL );
  611. }
  612. LocalFree( pszViolationServerList );
  613. }
  614. }
  615. }
  616. RtlReleaseResource( &CertDbHeaderListLock );
  617. LocalFree( pszViolationServerEntryFormat );
  618. DeregisterEventSource( hEventLog );
  619. }
  620. }
  621. FreeLibrary( hDll );
  622. }
  623. }
  624. ///////////////////////////////////////////////////////////////////////////////
  625. NTSTATUS CertDbPack( LPDWORD pcchProductStrings,
  626. LPTSTR * ppchProductStrings,
  627. LPDWORD pdwNumHeaders,
  628. PREPL_CERT_DB_CERTIFICATE_HEADER_0 * ppHeaders,
  629. LPDWORD pdwNumClaims,
  630. PREPL_CERT_DB_CERTIFICATE_CLAIM_0 * ppClaims )
  631. /*++
  632. Routine Description:
  633. Pack the certificate database into manageable chunks that can be saved or
  634. replicated.
  635. Arguments:
  636. pcchProductStrings (LPDWORD)
  637. On return, holds the size (in characters) of the buffer pointed to by
  638. *ppchProductStrings.
  639. ppchProductStrings (LPTSTR *)
  640. On return, points to the buffer containing the product strings component
  641. of the database.
  642. pdwNumHeaders (LPDWORD)
  643. On return, holds the number of certificate headers in the array pointed
  644. to by *ppHeaders.
  645. ppHeaders (PREPL_CERT_DB_CERTIFICATE_HEADER_0 *)
  646. On return, holds a pointer to the certificate header array component of
  647. the database.
  648. pdwNumClaims (LPDWORD)
  649. On return, holds the number of certificate claims in the array pointed
  650. to by *ppHeaders.
  651. ppClaims (PREPL_CERT_DB_CERTIFICATE_CLAIM_0 *)
  652. On return, holds a pointer to the certificate claim array component of
  653. the database.
  654. Return Value:
  655. STATUS_SUCCESS or STATUS_NO_MEMORY.
  656. --*/
  657. {
  658. NTSTATUS nt = STATUS_SUCCESS;
  659. DWORD cchProductStrings = 0;
  660. LPTSTR pchProductStrings = NULL;
  661. DWORD dwNumHeaders = 0;
  662. PREPL_CERT_DB_CERTIFICATE_HEADER_0 pHeaders = NULL;
  663. DWORD dwNumClaims = 0;
  664. PREPL_CERT_DB_CERTIFICATE_CLAIM_0 pClaims = NULL;
  665. LPTSTR pchNextProductString;
  666. int iHeader;
  667. int iClaim;
  668. HRESULT hr;
  669. CertDbPrune();
  670. CertDbUpdateLocalClaims();
  671. RtlAcquireResourceExclusive( &CertDbHeaderListLock, TRUE );
  672. if ( 0 != CertDbHeaderListSize )
  673. {
  674. // how big are all of our strings put together?
  675. // hom many certificate claims are there?
  676. for ( iHeader=0; (DWORD)iHeader < CertDbHeaderListSize; iHeader++ )
  677. {
  678. cchProductStrings += 1 + lstrlen( CertDbHeaderList[ iHeader ].Product );
  679. dwNumClaims += CertDbHeaderList[ iHeader ].NumClaims;
  680. }
  681. dwNumHeaders = CertDbHeaderListSize;
  682. pchProductStrings = LocalAlloc( LMEM_FIXED, cchProductStrings * sizeof( TCHAR ) );
  683. pHeaders = LocalAlloc( LMEM_FIXED, dwNumHeaders * sizeof( REPL_CERT_DB_CERTIFICATE_HEADER_0 ) );
  684. pClaims = LocalAlloc( LMEM_FIXED, dwNumClaims * sizeof( REPL_CERT_DB_CERTIFICATE_CLAIM_0 ) );
  685. if ( ( NULL == pchProductStrings ) || ( NULL == pHeaders ) || ( NULL == pClaims ) )
  686. {
  687. ASSERT( FALSE );
  688. nt = STATUS_NO_MEMORY;
  689. }
  690. else
  691. {
  692. // pack the product strings
  693. pchNextProductString = pchProductStrings;
  694. for ( iHeader=0; (DWORD)iHeader < CertDbHeaderListSize; iHeader++ )
  695. {
  696. hr = StringCchCopy( pchNextProductString, cchProductStrings, CertDbHeaderList[ iHeader ].Product );
  697. ASSERT(SUCCEEDED(hr));
  698. pchNextProductString += 1 + lstrlen( pchNextProductString );
  699. }
  700. // now pack away the rest of our structures
  701. iClaim = 0;
  702. for ( iHeader=0; (DWORD)iHeader < CertDbHeaderListSize; iHeader++ )
  703. {
  704. pHeaders[ iHeader ].CertificateID = CertDbHeaderList[ iHeader ].CertificateID;
  705. pHeaders[ iHeader ].MaxQuantity = CertDbHeaderList[ iHeader ].MaxQuantity;
  706. pHeaders[ iHeader ].ExpirationDate = CertDbHeaderList[ iHeader ].ExpirationDate;
  707. pHeaders[ iHeader ].NumClaims = CertDbHeaderList[ iHeader ].NumClaims;
  708. if ( CertDbHeaderList[ iHeader ].NumClaims )
  709. {
  710. memcpy( &pClaims[ iClaim ],
  711. CertDbHeaderList[ iHeader ].Claims,
  712. CertDbHeaderList[ iHeader ].NumClaims * sizeof( LLS_CERT_DB_CERTIFICATE_CLAIM ) );
  713. iClaim += CertDbHeaderList[ iHeader ].NumClaims;
  714. }
  715. }
  716. // all done!
  717. nt = STATUS_SUCCESS;
  718. }
  719. }
  720. if ( STATUS_SUCCESS == nt )
  721. {
  722. ASSERT(NULL != pcchProductStrings &&
  723. NULL != ppchProductStrings &&
  724. NULL != pdwNumHeaders &&
  725. NULL != ppHeaders &&
  726. NULL != pdwNumClaims &&
  727. NULL != ppClaims);
  728. *pcchProductStrings = cchProductStrings;
  729. *ppchProductStrings = pchProductStrings;
  730. *pdwNumHeaders = dwNumHeaders;
  731. *ppHeaders = pHeaders;
  732. *pdwNumClaims = dwNumClaims;
  733. *ppClaims = pClaims;
  734. }
  735. else
  736. {
  737. if ( NULL != pchProductStrings ) LocalFree( pchProductStrings );
  738. if ( NULL != pHeaders ) LocalFree( pHeaders );
  739. if ( NULL != pClaims ) LocalFree( pClaims );
  740. }
  741. RtlReleaseResource( &CertDbHeaderListLock );
  742. return nt;
  743. }
  744. ///////////////////////////////////////////////////////////////////////////////
  745. NTSTATUS CertDbUnpack( DWORD cchProductStrings,
  746. LPTSTR pchProductStrings,
  747. DWORD dwNumHeaders,
  748. PREPL_CERT_DB_CERTIFICATE_HEADER_0 pHeaders,
  749. DWORD dwNumClaims,
  750. PREPL_CERT_DB_CERTIFICATE_CLAIM_0 pClaims,
  751. BOOL bReplicated )
  752. /*++
  753. Routine Description:
  754. Pack the certificate database into manageable chunks that can be saved or
  755. replicated.
  756. Arguments:
  757. cchProductStrings (DWORD)
  758. The size (in characters) of the buffer pointed to by pchProductStrings.
  759. pchProductStrings (LPTSTR)
  760. The buffer containing the product strings component of the database.
  761. dwNumHeaders (DWORD)
  762. The number of certificate headers in the array pointed to by pHeaders.
  763. pHeaders (PREPL_CERT_DB_CERTIFICATE_HEADER_0)
  764. The certificate header array component of the database.
  765. dwNumClaims (DWORD)
  766. The number of certificate claims in the array pointed to by pHeaders.
  767. pClaims (PREPL_CERT_DB_CERTIFICATE_CLAIM_0)
  768. The certificate claim array component of the database.
  769. bReplicated (BOOL)
  770. Indicates whether this information was replicated. This is used to
  771. determine the time at which this information will expire.
  772. Return Value:
  773. STATUS_SUCCESS or NTSTATUS error code.
  774. --*/
  775. {
  776. NTSTATUS nt = STATUS_SUCCESS;
  777. LPTSTR pchNextProductString;
  778. int iHeader;
  779. int iClaim;
  780. int iClaimBase;
  781. LLS_LICENSE_INFO_1 lic;
  782. TCHAR szComputerName[ 1 + MAX_COMPUTERNAME_LENGTH ];
  783. DWORD cchComputerName = sizeof( szComputerName ) / sizeof( *szComputerName );
  784. BOOL ok;
  785. UNREFERENCED_PARAMETER(cchProductStrings);
  786. UNREFERENCED_PARAMETER(dwNumClaims);
  787. ok = GetComputerName( szComputerName, &cchComputerName );
  788. ASSERT( ok );
  789. if ( !ok )
  790. {
  791. // in this case, we'll just add in the local entries, too
  792. // under normal circumstances (i.e., as long as the cert db isn't corrupt)
  793. // this is harmless and is preferrable to failing to unpack
  794. *szComputerName = TEXT( '\0' );
  795. }
  796. RtlAcquireResourceExclusive( &CertDbHeaderListLock, TRUE );
  797. pchNextProductString = pchProductStrings;
  798. // these fields are irrelevant!
  799. lic.Date = 0;
  800. lic.Admin = NULL;
  801. lic.Comment = NULL;
  802. lic.Vendor = NULL;
  803. lic.Source = NULL;
  804. lic.AllowedModes = 0;
  805. iClaimBase = 0;
  806. for ( iHeader=0; (DWORD)iHeader < dwNumHeaders; iHeader++ )
  807. {
  808. if ( 0 != pHeaders[ iHeader ].NumClaims )
  809. {
  810. // certificate-specific fields
  811. lic.Product = pchNextProductString;
  812. lic.CertificateID = pHeaders[ iHeader ].CertificateID;
  813. lic.MaxQuantity = pHeaders[ iHeader ].MaxQuantity;
  814. lic.ExpirationDate = pHeaders[ iHeader ].ExpirationDate;
  815. for ( iClaim=0; (DWORD)iClaim < pHeaders[ iHeader ].NumClaims; iClaim++ )
  816. {
  817. if ( lstrcmpi( szComputerName, pClaims[ iClaimBase + iClaim ].ServerName ) )
  818. {
  819. // not the local server
  820. // claim-specific field
  821. lic.Quantity = pClaims[ iClaimBase + iClaim ].Quantity;
  822. nt = CertDbClaimEnter( pClaims[ iClaimBase + iClaim ].ServerName, &lic, TRUE, bReplicated ? 0 : pClaims[ iClaimBase + iClaim ].ReplicationDate );
  823. ASSERT( STATUS_SUCCESS == nt );
  824. // even if we encounter an error, go ahead and unpack the rest of the records
  825. }
  826. }
  827. iClaimBase += pHeaders[ iHeader ].NumClaims;
  828. }
  829. pchNextProductString += 1 + lstrlen( pchNextProductString );
  830. }
  831. RtlReleaseResource( &CertDbHeaderListLock );
  832. return nt;
  833. }
  834. ///////////////////////////////////////////////////////////////////////////////
  835. NTSTATUS CertDbSave()
  836. /*++
  837. Routine Description:
  838. Save the certificate database.
  839. Arguments:
  840. None.
  841. Return Value:
  842. STATUS_SUCCESS, Windows error, or NTSTATUS error code.
  843. --*/
  844. {
  845. NTSTATUS nt;
  846. LLS_CERT_DB_FILE_HEADER FileHeader;
  847. DWORD cchProductStrings = 0;
  848. LPTSTR pchProductStrings = NULL;
  849. DWORD dwNumHeaders = 0;
  850. PREPL_CERT_DB_CERTIFICATE_HEADER_0 pHeaders = NULL;
  851. DWORD dwNumClaims = 0;
  852. PREPL_CERT_DB_CERTIFICATE_CLAIM_0 pClaims = NULL;
  853. DWORD dwBytesWritten;
  854. BOOL ok;
  855. nt = CertDbPack( &cchProductStrings, &pchProductStrings, &dwNumHeaders, &pHeaders, &dwNumClaims, &pClaims );
  856. if ( STATUS_SUCCESS == nt )
  857. {
  858. if ( dwNumHeaders )
  859. {
  860. nt = EBlock( pchProductStrings, cchProductStrings * sizeof( TCHAR ) );
  861. if ( STATUS_SUCCESS == nt )
  862. {
  863. nt = EBlock( pHeaders, sizeof( REPL_CERT_DB_CERTIFICATE_HEADER_0 ) * dwNumHeaders );
  864. if ( STATUS_SUCCESS == nt )
  865. {
  866. nt = EBlock( pClaims, sizeof( REPL_CERT_DB_CERTIFICATE_CLAIM_0 ) * dwNumClaims );
  867. if ( STATUS_SUCCESS == nt )
  868. {
  869. if ( NULL != CertDbFile )
  870. {
  871. CloseHandle( CertDbFile );
  872. }
  873. CertDbFile = LlsFileInit( CertDbFileName, LLS_CERT_DB_FILE_VERSION, sizeof( LLS_CERT_DB_FILE_HEADER ) );
  874. if ( NULL == CertDbFile )
  875. {
  876. nt = GetLastError();
  877. }
  878. else
  879. {
  880. FileHeader.NumCertificates = dwNumHeaders;
  881. FileHeader.ProductStringSize = cchProductStrings;
  882. FileHeader.NumClaims = dwNumClaims;
  883. ok = WriteFile( CertDbFile, &FileHeader, sizeof( FileHeader ), &dwBytesWritten, NULL );
  884. if ( ok )
  885. {
  886. ok = WriteFile( CertDbFile, pchProductStrings, FileHeader.ProductStringSize * sizeof( TCHAR ), &dwBytesWritten, NULL );
  887. if ( ok )
  888. {
  889. ok = WriteFile( CertDbFile, pHeaders, sizeof( REPL_CERT_DB_CERTIFICATE_HEADER_0 ) * FileHeader.NumCertificates, &dwBytesWritten, NULL );
  890. if ( ok )
  891. {
  892. ok = WriteFile( CertDbFile, pClaims, sizeof( REPL_CERT_DB_CERTIFICATE_CLAIM_0 ) * FileHeader.NumClaims, &dwBytesWritten, NULL );
  893. }
  894. }
  895. }
  896. if ( !ok )
  897. {
  898. nt = GetLastError();
  899. }
  900. }
  901. }
  902. }
  903. }
  904. LocalFree( pchProductStrings );
  905. LocalFree( pHeaders );
  906. LocalFree( pClaims );
  907. }
  908. }
  909. if ( STATUS_SUCCESS != nt )
  910. {
  911. LogEvent( LLS_EVENT_SAVE_CERT_DB, 0, NULL, nt );
  912. }
  913. return nt;
  914. }
  915. ///////////////////////////////////////////////////////////////////////////////
  916. NTSTATUS CertDbLoad()
  917. /*++
  918. Routine Description:
  919. Load the certificate database.
  920. Arguments:
  921. None.
  922. Return Value:
  923. STATUS_SUCCESS, Windows error, or NTSTATUS error code.
  924. --*/
  925. {
  926. NTSTATUS nt = STATUS_SUCCESS;
  927. DWORD dwVersion;
  928. DWORD dwDataSize;
  929. LLS_CERT_DB_FILE_HEADER FileHeader;
  930. LPTSTR pchProductStrings = NULL;
  931. PREPL_CERT_DB_CERTIFICATE_HEADER_0 pHeaders = NULL;
  932. PREPL_CERT_DB_CERTIFICATE_CLAIM_0 pClaims = NULL;
  933. DWORD dwBytesRead;
  934. BOOL ok;
  935. if ( NULL != CertDbFile )
  936. {
  937. CloseHandle( CertDbFile );
  938. CertDbFile = NULL;
  939. }
  940. if ( FileExists( CertDbFileName ) )
  941. {
  942. CertDbFile = LlsFileCheck( CertDbFileName, &dwVersion, &dwDataSize );
  943. if ( NULL == CertDbFile )
  944. {
  945. nt = GetLastError();
  946. }
  947. else if ( ( LLS_CERT_DB_FILE_VERSION != dwVersion )
  948. || ( sizeof( FileHeader ) != dwDataSize ) )
  949. {
  950. nt = STATUS_FILE_INVALID;
  951. }
  952. else
  953. {
  954. ok = ReadFile( CertDbFile, &FileHeader, sizeof( FileHeader ), &dwBytesRead, NULL );
  955. if ( !ok )
  956. {
  957. nt = GetLastError();
  958. }
  959. else if ( FileHeader.NumCertificates )
  960. {
  961. pchProductStrings = LocalAlloc( LMEM_FIXED, sizeof( TCHAR ) * FileHeader.ProductStringSize );
  962. pHeaders = LocalAlloc( LMEM_FIXED, sizeof( REPL_CERT_DB_CERTIFICATE_HEADER_0 ) * FileHeader.NumCertificates );
  963. pClaims = LocalAlloc( LMEM_FIXED, sizeof( REPL_CERT_DB_CERTIFICATE_CLAIM_0 ) * FileHeader.NumClaims );
  964. if ( ( NULL == pchProductStrings ) || ( NULL == pHeaders ) || ( NULL == pClaims ) )
  965. {
  966. ASSERT( FALSE );
  967. nt = STATUS_NO_MEMORY;
  968. }
  969. else
  970. {
  971. ok = ReadFile( CertDbFile, pchProductStrings, FileHeader.ProductStringSize * sizeof( TCHAR ), &dwBytesRead, NULL );
  972. if ( ok )
  973. {
  974. ok = ReadFile( CertDbFile, pHeaders, sizeof( REPL_CERT_DB_CERTIFICATE_HEADER_0 ) * FileHeader.NumCertificates, &dwBytesRead, NULL );
  975. if ( ok )
  976. {
  977. ok = ReadFile( CertDbFile, pClaims, sizeof( REPL_CERT_DB_CERTIFICATE_CLAIM_0 ) * FileHeader.NumClaims, &dwBytesRead, NULL );
  978. }
  979. }
  980. if ( !ok )
  981. {
  982. nt = GetLastError();
  983. }
  984. else
  985. {
  986. nt = DeBlock( pchProductStrings, sizeof( TCHAR ) * FileHeader.ProductStringSize );
  987. if ( STATUS_SUCCESS == nt )
  988. {
  989. nt = DeBlock( pHeaders, sizeof( REPL_CERT_DB_CERTIFICATE_HEADER_0 ) * FileHeader.NumCertificates );
  990. if ( STATUS_SUCCESS == nt )
  991. {
  992. nt = DeBlock( pClaims, sizeof( REPL_CERT_DB_CERTIFICATE_CLAIM_0 ) * FileHeader.NumClaims );
  993. if ( STATUS_SUCCESS == nt )
  994. {
  995. nt = CertDbUnpack( FileHeader.ProductStringSize,
  996. pchProductStrings,
  997. FileHeader.NumCertificates,
  998. pHeaders,
  999. FileHeader.NumClaims,
  1000. pClaims,
  1001. FALSE );
  1002. }
  1003. }
  1004. }
  1005. }
  1006. }
  1007. }
  1008. }
  1009. }
  1010. if ( NULL != pchProductStrings ) LocalFree( pchProductStrings );
  1011. if ( NULL != pHeaders ) LocalFree( pHeaders );
  1012. if ( NULL != pClaims ) LocalFree( pClaims );
  1013. if ( STATUS_SUCCESS != nt )
  1014. {
  1015. LogEvent( LLS_EVENT_LOAD_CERT_DB, 0, NULL, nt );
  1016. }
  1017. else
  1018. {
  1019. CertDbPrune();
  1020. }
  1021. return nt;
  1022. }
  1023. ///////////////////////////////////////////////////////////////////////////////
  1024. NTSTATUS CertDbInit()
  1025. /*++
  1026. Routine Description:
  1027. Initialize the certificate database.
  1028. Arguments:
  1029. None.
  1030. Return Value:
  1031. STATUS_SUCCESS.
  1032. --*/
  1033. {
  1034. CertDbFile = NULL;
  1035. try
  1036. {
  1037. RtlInitializeResource( &CertDbHeaderListLock );
  1038. } except(EXCEPTION_EXECUTE_HANDLER ) {
  1039. return GetExceptionCode();
  1040. }
  1041. return STATUS_SUCCESS;
  1042. }
  1043. ///////////////////////////////////////////////////////////////////////////////
  1044. void CertDbUpdateLocalClaims()
  1045. /*++
  1046. Routine Description:
  1047. Synchronize the certificate database with the purchase history.
  1048. Arguments:
  1049. None.
  1050. Return Value:
  1051. None.
  1052. --*/
  1053. {
  1054. DWORD dwPurchaseNdx;
  1055. LLS_LICENSE_INFO_1 lic;
  1056. PLICENSE_PURCHASE_RECORD pPurchase;
  1057. RtlAcquireResourceExclusive( &LicenseListLock, TRUE );
  1058. RtlAcquireResourceExclusive( &CertDbHeaderListLock, TRUE );
  1059. // first dump all current entries for the local server
  1060. CertDbRemoveLocalClaims();
  1061. // these fields are irrelevant!
  1062. lic.Date = 0;
  1063. lic.Admin = NULL;
  1064. lic.Comment = NULL;
  1065. lic.Source = NULL;
  1066. lic.Vendor = NULL;
  1067. lic.AllowedModes = 0;
  1068. // add in all secure purchases
  1069. for ( dwPurchaseNdx = 0; dwPurchaseNdx < PurchaseListSize; dwPurchaseNdx++ )
  1070. {
  1071. pPurchase = &PurchaseList[ dwPurchaseNdx ];
  1072. if ( 0 != pPurchase->CertificateID )
  1073. {
  1074. lic.Product = ( pPurchase->AllowedModes & LLS_LICENSE_MODE_ALLOW_PER_SEAT )
  1075. ? pPurchase->Service->ServiceName
  1076. : pPurchase->PerServerService->ServiceName;
  1077. lic.CertificateID = pPurchase->CertificateID;
  1078. lic.MaxQuantity = pPurchase->MaxQuantity;
  1079. lic.ExpirationDate = pPurchase->ExpirationDate;
  1080. lic.Quantity = pPurchase->NumberLicenses;
  1081. CertDbClaimEnter( NULL, &lic, FALSE, 0 );
  1082. }
  1083. }
  1084. RtlReleaseResource( &CertDbHeaderListLock );
  1085. RtlReleaseResource( &LicenseListLock );
  1086. }
  1087. ///////////////////////////////////////////////////////////////////////////////
  1088. NTSTATUS CertDbClaimsGet( PLLS_LICENSE_INFO_1 pLicense,
  1089. LPDWORD pdwNumClaims,
  1090. PLLS_CERTIFICATE_CLAIM_INFO_0 * ppTargets )
  1091. /*++
  1092. Routine Description:
  1093. Retrieve a list of all servers with licenses installed from a given
  1094. certificate and the number of licenses installed on each.
  1095. Arguments:
  1096. pLicense (PLLS_LICENSE_INFO_1)
  1097. License describing the certificate for which the claims are sought.
  1098. pdwNumClaims (LPDWORD)
  1099. On return, holds the number of claims in the array pointed to by
  1100. *ppTargets.
  1101. ppTargets (PLLS_CERTIFICATE_CLAIM_INFO_0 *)
  1102. On return, holds an array describing all claims made on this
  1103. certificate.
  1104. Return Value:
  1105. STATUS_SUCCESS
  1106. STATUS_NOT_FOUND
  1107. STATUS_NO_MEMORY
  1108. --*/
  1109. {
  1110. NTSTATUS nt;
  1111. PLLS_CERT_DB_CERTIFICATE_HEADER pHeader;
  1112. int iClaim;
  1113. HRESULT hr;
  1114. // is the certificate in the db?
  1115. pHeader = CertDbHeaderFind( pLicense );
  1116. if ( NULL == pHeader )
  1117. {
  1118. // not here!
  1119. nt = STATUS_NOT_FOUND;
  1120. }
  1121. else
  1122. {
  1123. ASSERT(NULL != ppTargets);
  1124. *ppTargets = MIDL_user_allocate( pHeader->NumClaims * sizeof( LLS_CERTIFICATE_CLAIM_INFO_0 ) );
  1125. if ( NULL == *ppTargets )
  1126. {
  1127. nt = STATUS_NO_MEMORY;
  1128. }
  1129. else
  1130. {
  1131. ASSERT(NULL != pdwNumClaims);
  1132. *pdwNumClaims = pHeader->NumClaims;
  1133. for ( iClaim=0; (DWORD)iClaim < pHeader->NumClaims; iClaim++ )
  1134. {
  1135. hr = StringCbCopy( (*ppTargets)[ iClaim ].ServerName, sizeof((*ppTargets)[ iClaim ].ServerName), pHeader->Claims[ iClaim ].ServerName );
  1136. ASSERT(SUCCEEDED(hr));
  1137. (*ppTargets)[ iClaim ].Quantity = pHeader->Claims[ iClaim ].Quantity;
  1138. }
  1139. nt = STATUS_SUCCESS;
  1140. }
  1141. }
  1142. return nt;
  1143. }
  1144. #if DBG
  1145. /////////////////////////////////////////////////////////////////////////
  1146. void CertDbDebugDump()
  1147. /*++
  1148. Routine Description:
  1149. Dump contents of certificate database to debug console.
  1150. Arguments:
  1151. None.
  1152. Return Value:
  1153. None.
  1154. --*/
  1155. {
  1156. int iHeader;
  1157. int iClaim;
  1158. RtlAcquireResourceShared( &CertDbHeaderListLock, TRUE );
  1159. for ( iHeader=0; (DWORD)iHeader < CertDbHeaderListSize; iHeader++ )
  1160. {
  1161. dprintf( TEXT("\n(%3d) Product : %s\n"), iHeader, CertDbHeaderList[ iHeader ].Product );
  1162. dprintf( TEXT(" CertificateID : %d\n"), CertDbHeaderList[ iHeader ].CertificateID );
  1163. dprintf( TEXT(" MaxQuantity : %d\n"), CertDbHeaderList[ iHeader ].MaxQuantity );
  1164. dprintf( TEXT(" ExpirationDate : %s\n"), TimeToString( CertDbHeaderList[ iHeader ].ExpirationDate ) );
  1165. for ( iClaim=0; (DWORD)iClaim < CertDbHeaderList[ iHeader ].NumClaims; iClaim++ )
  1166. {
  1167. dprintf( TEXT("\n (%3d) ServerName : %s\n"), iClaim, CertDbHeaderList[ iHeader ].Claims[ iClaim ].ServerName );
  1168. dprintf( TEXT(" ReplicationDate : %s\n"), TimeToString( CertDbHeaderList[ iHeader ].Claims[ iClaim ].ReplicationDate ) );
  1169. dprintf( TEXT(" Quantity : %d\n"), CertDbHeaderList[ iHeader ].Claims[ iClaim ].Quantity );
  1170. }
  1171. }
  1172. RtlReleaseResource( &CertDbHeaderListLock );
  1173. } // CertDbDebugDump
  1174. #endif