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

988 lines
25 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. purchase.c
  5. Abstract:
  6. Author:
  7. Arthur Hanson (arth) 03-Jan-1995
  8. Revision History:
  9. Jeff Parham (jeffparh) 05-Dec-1995
  10. o Added support for uniting per seat and per server purchase models.
  11. o Added extra parameters and code to support secure certificates and
  12. certificate database.
  13. --*/
  14. #include <stdlib.h>
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <dsgetdc.h>
  20. #include <debug.h>
  21. #include "llsevent.h"
  22. #include "llsapi.h"
  23. #include "llsutil.h"
  24. #include "llssrv.h"
  25. #include "mapping.h"
  26. #include "msvctbl.h"
  27. #include "purchase.h"
  28. #include "svctbl.h"
  29. #include "perseat.h"
  30. #include "registry.h"
  31. #include "llsrpc_s.h"
  32. #include "certdb.h"
  33. #include "server.h"
  34. //
  35. // Initialized in ReplicationInit in repl.c.
  36. //
  37. extern PLLS_CONNECT_W pLlsConnectW;
  38. extern PLLS_CLOSE pLlsClose;
  39. extern PLLS_LICENSE_ADD_W pLlsLicenseAddW;
  40. ULONG LicenseServiceListSize = 0;
  41. PLICENSE_SERVICE_RECORD *LicenseServiceList = NULL;
  42. ULONG PerServerLicenseServiceListSize = 0;
  43. PLICENSE_SERVICE_RECORD *PerServerLicenseServiceList = NULL;
  44. PLICENSE_PURCHASE_RECORD PurchaseList = NULL;
  45. ULONG PurchaseListSize = 0;
  46. RTL_RESOURCE LicenseListLock;
  47. static
  48. NTSTATUS
  49. LicenseAdd_UpdateQuantity(
  50. LPTSTR ServiceName,
  51. LONG Quantity,
  52. BOOL UsePerServerList,
  53. PLICENSE_SERVICE_RECORD * ppService,
  54. BOOL * pChangeLicense,
  55. LONG * pNewLicenses,
  56. PMASTER_SERVICE_RECORD * pmService
  57. );
  58. NTSTATUS
  59. ReplicationInitDelayed();
  60. /////////////////////////////////////////////////////////////////////////
  61. NTSTATUS
  62. LicenseListInit()
  63. /*++
  64. Routine Description:
  65. Arguments:
  66. None.
  67. Return Value:
  68. None.
  69. --*/
  70. {
  71. NTSTATUS status = STATUS_SUCCESS;
  72. try
  73. {
  74. RtlInitializeResource(&LicenseListLock);
  75. } except(EXCEPTION_EXECUTE_HANDLER ) {
  76. status = GetExceptionCode();
  77. }
  78. return status;
  79. } // LicenseListInit
  80. /////////////////////////////////////////////////////////////////////////
  81. int __cdecl LicenseServiceListCompare(const void *arg1, const void *arg2) {
  82. PLICENSE_SERVICE_RECORD Svc1, Svc2;
  83. Svc1 = (PLICENSE_SERVICE_RECORD) *((PLICENSE_SERVICE_RECORD *) arg1);
  84. Svc2 = (PLICENSE_SERVICE_RECORD) *((PLICENSE_SERVICE_RECORD *) arg2);
  85. return lstrcmpi( Svc1->ServiceName, Svc2->ServiceName);
  86. } // LicenseServiceListCompare
  87. /////////////////////////////////////////////////////////////////////////
  88. PLICENSE_SERVICE_RECORD
  89. LicenseServiceListFind(
  90. LPTSTR ServiceName,
  91. BOOL UsePerServerList
  92. )
  93. /*++
  94. Routine Description:
  95. Arguments:
  96. ServiceName -
  97. (JeffParh 95-10-31)
  98. UsePerServerList - Determines whether the license record is searched for
  99. in the per seat list (as in 3.51) or in the per server list (new for
  100. SUR). The license purchase models are now unified, so there is now
  101. a purchase history for both per seat and per server licenses.
  102. Return Value:
  103. Pointer to found service table entry or NULL if not found.
  104. --*/
  105. {
  106. LONG begin = 0;
  107. LONG end = (LONG) LicenseServiceListSize - 1;
  108. LONG cur;
  109. int match;
  110. PLICENSE_SERVICE_RECORD Service;
  111. PLICENSE_SERVICE_RECORD * ServiceList;
  112. #if DBG
  113. if (TraceFlags & TRACE_FUNCTION_TRACE)
  114. dprintf(TEXT("LLS TRACE: LicenseServiceListFind\n"));
  115. #endif
  116. if (ServiceName == NULL)
  117. return NULL;
  118. if ( UsePerServerList )
  119. {
  120. end = PerServerLicenseServiceListSize - 1;
  121. ServiceList = PerServerLicenseServiceList;
  122. }
  123. else
  124. {
  125. end = LicenseServiceListSize - 1;
  126. ServiceList = LicenseServiceList;
  127. }
  128. while (end >= begin) {
  129. // go halfway in-between
  130. cur = (begin + end) / 2;
  131. Service = ServiceList[cur];
  132. // compare the two result into match
  133. match = lstrcmpi(ServiceName, Service->ServiceName);
  134. if (match < 0)
  135. // move new begin
  136. end = cur - 1;
  137. else
  138. begin = cur + 1;
  139. if (match == 0)
  140. return Service;
  141. }
  142. return NULL;
  143. } // LicenseServiceListFind
  144. /////////////////////////////////////////////////////////////////////////
  145. PLICENSE_SERVICE_RECORD
  146. LicenseServiceListAdd(
  147. LPTSTR ServiceName,
  148. BOOL UsePerServerList
  149. )
  150. /*++
  151. Routine Description:
  152. Arguments:
  153. ServiceName -
  154. (JeffParh 95-10-31)
  155. UsePerServerList - Determines whether the license record is added to
  156. the per seat list (as in 3.51) or the per server list (new for
  157. SUR). The license purchase models are now unified, so there is now
  158. a purchase history for both per seat and per server licenses.
  159. Return Value:
  160. Pointer to added service table entry, or NULL if failed.
  161. --*/
  162. {
  163. PLICENSE_SERVICE_RECORD Service;
  164. LPTSTR NewServiceName;
  165. PLICENSE_SERVICE_RECORD ** pServiceList;
  166. LPDWORD pServiceListSize;
  167. PLICENSE_SERVICE_RECORD * pServiceListTmp;
  168. #if DBG
  169. if (TraceFlags & TRACE_FUNCTION_TRACE)
  170. dprintf(TEXT("LLS TRACE: LicenseServiceListAdd\n"));
  171. #endif
  172. //
  173. // We do a double check here to see if another thread just got done
  174. // adding the service, between when we checked last and actually got
  175. // the write lock.
  176. //
  177. Service = LicenseServiceListFind(ServiceName, UsePerServerList);
  178. if (Service != NULL) {
  179. return Service;
  180. }
  181. if ( UsePerServerList )
  182. {
  183. pServiceList = &PerServerLicenseServiceList;
  184. pServiceListSize = &PerServerLicenseServiceListSize;
  185. }
  186. else
  187. {
  188. pServiceList = &LicenseServiceList;
  189. pServiceListSize = &LicenseServiceListSize;
  190. }
  191. //
  192. // Allocate space for table (zero init it).
  193. //
  194. if (*pServiceList == NULL)
  195. pServiceListTmp = (PLICENSE_SERVICE_RECORD *) LocalAlloc(LPTR, sizeof(PLICENSE_SERVICE_RECORD) * (*pServiceListSize + 1));
  196. else
  197. pServiceListTmp = (PLICENSE_SERVICE_RECORD *) LocalReAlloc(*pServiceList, sizeof(PLICENSE_SERVICE_RECORD) * (*pServiceListSize + 1), LHND);
  198. //
  199. // Make sure we could allocate service table
  200. //
  201. if (pServiceListTmp == NULL) {
  202. return NULL;
  203. } else {
  204. *pServiceList = pServiceListTmp;
  205. }
  206. Service = (PLICENSE_SERVICE_RECORD) LocalAlloc(LPTR, sizeof(LICENSE_SERVICE_RECORD));
  207. if (Service == NULL) {
  208. ASSERT(FALSE);
  209. return NULL;
  210. }
  211. //
  212. // Create space for saving off the name.
  213. //
  214. NewServiceName = (LPTSTR) LocalAlloc(LPTR, (lstrlen(ServiceName) + 1) * sizeof(TCHAR));
  215. if (NewServiceName == NULL) {
  216. ASSERT(FALSE);
  217. LocalFree(Service);
  218. return NULL;
  219. }
  220. // now copy it over...
  221. Service->ServiceName = NewServiceName;
  222. lstrcpy(NewServiceName, ServiceName);
  223. (*pServiceList)[*pServiceListSize] = Service;
  224. Service->NumberLicenses = 0;
  225. Service->Index = *pServiceListSize;
  226. (*pServiceListSize)++;
  227. // Have added the entry - now need to sort it in order of the service names
  228. qsort((void *) *pServiceList, (size_t) *pServiceListSize, sizeof(PLICENSE_SERVICE_RECORD), LicenseServiceListCompare);
  229. return Service;
  230. } // LicenseServiceListAdd
  231. /////////////////////////////////////////////////////////////////////////
  232. ULONG
  233. ProductLicensesGet(
  234. LPTSTR ServiceName,
  235. BOOL UsePerServerList
  236. )
  237. /*++
  238. Routine Description:
  239. Arguments:
  240. ServiceName -
  241. (JeffParh 95-10-31)
  242. UsePerServerList - Determines whether the number of licenses is retirved
  243. from the per seat list (as in 3.51) or the per server list (new for
  244. SUR). The license purchase models are now unified, so there is now
  245. a purchase history for both per seat and per server licenses.
  246. Return Value:
  247. --*/
  248. {
  249. PLICENSE_SERVICE_RECORD Service;
  250. ULONG NumLicenses = 0;
  251. #if DBG
  252. if (TraceFlags & TRACE_FUNCTION_TRACE)
  253. dprintf(TEXT("LLS TRACE: ProductLicenseGet\n"));
  254. #endif
  255. //
  256. // Try to find the service.
  257. //
  258. RtlAcquireResourceShared(&LicenseListLock, TRUE);
  259. Service = LicenseServiceListFind(ServiceName, UsePerServerList);
  260. if (Service != NULL)
  261. NumLicenses = Service->NumberLicenses;
  262. RtlReleaseResource(&LicenseListLock);
  263. return NumLicenses;
  264. } // ProductLicensesGet
  265. /////////////////////////////////////////////////////////////////////////
  266. NTSTATUS
  267. LicenseAdd(
  268. LPTSTR ServiceName,
  269. LPTSTR Vendor,
  270. LONG Quantity,
  271. DWORD MaxQuantity,
  272. LPTSTR Admin,
  273. LPTSTR Comment,
  274. DWORD Date,
  275. DWORD AllowedModes,
  276. DWORD CertificateID,
  277. LPTSTR Source,
  278. DWORD ExpirationDate,
  279. LPDWORD Secrets
  280. )
  281. /*++
  282. Routine Description:
  283. Arguments:
  284. Return Value:
  285. --*/
  286. {
  287. static DWORD NullSecrets[ LLS_NUM_SECRETS ] = { 0, 0, 0, 0 };
  288. BOOL ChangeLicense = FALSE;
  289. PLICENSE_SERVICE_RECORD Service = NULL;
  290. PLICENSE_PURCHASE_RECORD PurchaseRecord;
  291. LONG NewLicenses = 0;
  292. NTSTATUS Status;
  293. BOOL PerServerChangeLicense = FALSE;
  294. PLICENSE_SERVICE_RECORD PerServerService = NULL;
  295. LONG PerServerNewLicenses = 0;
  296. LPTSTR NewName,NewAdmin,NewComment,NewSource,NewVendor;
  297. PMASTER_SERVICE_RECORD mService;
  298. LLS_LICENSE_INFO_1 lic;
  299. #if DBG
  300. if (TraceFlags & TRACE_FUNCTION_TRACE)
  301. dprintf(TEXT("LLS TRACE: LicenseAdd\n"));
  302. #endif
  303. if ( ( 0 == CertificateID ) && ( ServiceIsSecure( ServiceName ) ) )
  304. {
  305. return STATUS_ACCESS_DENIED;
  306. }
  307. if ( ( 0 != ExpirationDate ) && ( ExpirationDate < DateSystemGet() ) )
  308. {
  309. // certificate has expired
  310. return STATUS_ACCOUNT_EXPIRED;
  311. }
  312. if ( ( NULL == ServiceName )
  313. || ( NULL == Vendor )
  314. || ( 0 == Quantity )
  315. || ( ( 0 != CertificateID ) && ( 0 == MaxQuantity ) )
  316. || ( NULL == Admin )
  317. || ( NULL == Comment )
  318. || ( 0 == ( AllowedModes & ( LLS_LICENSE_MODE_ALLOW_PER_SEAT | LLS_LICENSE_MODE_ALLOW_PER_SERVER ) ) )
  319. || ( NULL == Source ) )
  320. {
  321. // invalid parameter
  322. return STATUS_INVALID_PARAMETER;
  323. }
  324. if ( NULL == Secrets )
  325. {
  326. Secrets = NullSecrets;
  327. }
  328. //
  329. // ** NEW - NT 5.0 **
  330. //
  331. // All per seat purchase requests are deferred to the site license master
  332. // server. Per server is still handled individually at each server.
  333. //
  334. if ( AllowedModes & 1 ) {
  335. //
  336. // Update enterprise information, in case the site license master
  337. // has changed.
  338. //
  339. #if DELAY_INITIALIZATION
  340. EnsureInitialized();
  341. #endif
  342. ConfigInfoUpdate(NULL);
  343. //
  344. // Connect to the site license master server, if this server is
  345. // not the master.
  346. //
  347. RtlEnterCriticalSection(&ConfigInfoLock);
  348. if ( !ConfigInfo.IsMaster && (ConfigInfo.SiteServer != NULL)) {
  349. // Make sure function pointers are initialized
  350. ReplicationInitDelayed();
  351. if ( pLlsConnectW != NULL ) {
  352. LLS_HANDLE LlsHandle;
  353. Status = (*pLlsConnectW)(ConfigInfo.SiteServer,
  354. &LlsHandle);
  355. if ( Status == STATUS_SUCCESS ) {
  356. LLS_LICENSE_INFO_0 LicenseInfo0;
  357. LicenseInfo0.Product = ServiceName;
  358. LicenseInfo0.Quantity = Quantity;
  359. LicenseInfo0.Date = Date;
  360. LicenseInfo0.Admin = Admin;
  361. LicenseInfo0.Comment = Comment;
  362. Status = (*pLlsLicenseAddW)(LlsHandle,
  363. 0,
  364. (LPBYTE)&LicenseInfo0);
  365. (*pLlsClose)(LlsHandle);
  366. }
  367. }
  368. else {
  369. //
  370. // Not the best error, but we must return something should
  371. // this obscure error condition become true.
  372. //
  373. Status = STATUS_INVALID_PARAMETER;
  374. }
  375. RtlLeaveCriticalSection(&ConfigInfoLock);
  376. return Status;
  377. }
  378. RtlLeaveCriticalSection(&ConfigInfoLock);
  379. }
  380. RtlAcquireResourceExclusive(&LicenseListLock, TRUE);
  381. if ( 0 != CertificateID )
  382. {
  383. lic.Product = ServiceName;
  384. lic.Vendor = Vendor;
  385. lic.Quantity = Quantity;
  386. lic.MaxQuantity = MaxQuantity;
  387. lic.Admin = Admin;
  388. lic.Comment = Comment;
  389. lic.Date = Date;
  390. lic.AllowedModes = AllowedModes;
  391. lic.CertificateID = CertificateID;
  392. lic.Source = Source;
  393. lic.ExpirationDate = ExpirationDate;
  394. memcpy( lic.Secrets, Secrets, LLS_NUM_SECRETS * sizeof( *Secrets ) );
  395. if ( !CertDbClaimApprove( &lic ) )
  396. {
  397. // no way, hoser!
  398. RtlReleaseResource( &LicenseListLock );
  399. return STATUS_OBJECT_NAME_EXISTS;
  400. }
  401. }
  402. // update totals for per seat / per server mode licenses
  403. Status = STATUS_SUCCESS;
  404. if ( AllowedModes & 1 )
  405. {
  406. // per seat allowed; add to per seat license tally
  407. Status = LicenseAdd_UpdateQuantity( ServiceName,
  408. Quantity,
  409. FALSE,
  410. &Service,
  411. &ChangeLicense,
  412. &NewLicenses,
  413. &mService );
  414. }
  415. if ( ( STATUS_SUCCESS == Status ) && ( AllowedModes & 2 ) )
  416. {
  417. // per server allowed; add to per server license tally
  418. Status = LicenseAdd_UpdateQuantity( ServiceName,
  419. Quantity,
  420. TRUE,
  421. &PerServerService,
  422. &PerServerChangeLicense,
  423. &PerServerNewLicenses,
  424. &mService );
  425. }
  426. if ( STATUS_SUCCESS != Status )
  427. {
  428. RtlReleaseResource( &LicenseListLock );
  429. return Status;
  430. }
  431. //
  432. // Service now points to the service table entry - now update purchase
  433. // History.
  434. //
  435. //
  436. // First allocate members, then new struct
  437. //
  438. //
  439. // Create space for saving off the Admin Name
  440. //
  441. NewName = (LPTSTR) LocalAlloc(LPTR, (lstrlen(Admin) + 1) * sizeof(TCHAR));
  442. if (NewName == NULL)
  443. {
  444. ASSERT(FALSE);
  445. RtlReleaseResource(&LicenseListLock);
  446. return STATUS_NO_MEMORY;
  447. }
  448. // now copy it over...
  449. lstrcpy(NewName, Admin);
  450. //
  451. // Create space for saving off the Comment
  452. //
  453. NewComment = (LPTSTR) LocalAlloc(LPTR, (lstrlen(Comment) + 1) * sizeof(TCHAR));
  454. if (NewComment == NULL)
  455. {
  456. ASSERT(FALSE);
  457. LocalFree(NewName);
  458. RtlReleaseResource(&LicenseListLock);
  459. return STATUS_NO_MEMORY;
  460. }
  461. // now copy it over...
  462. lstrcpy(NewComment, Comment);
  463. //
  464. // Create space for saving off the Source
  465. //
  466. NewSource = (LPTSTR) LocalAlloc(LPTR, (lstrlen(Source) + 1) * sizeof(TCHAR));
  467. if (NewSource == NULL)
  468. {
  469. ASSERT(FALSE);
  470. LocalFree(NewName);
  471. LocalFree(NewComment);
  472. RtlReleaseResource(&LicenseListLock);
  473. return STATUS_NO_MEMORY;
  474. }
  475. // now copy it over...
  476. lstrcpy(NewSource, Source);
  477. //
  478. // Create space for saving off the Vendor
  479. //
  480. NewVendor = (LPTSTR) LocalAlloc(LPTR, (lstrlen(Vendor) + 1) * sizeof(TCHAR));
  481. if (NewVendor == NULL)
  482. {
  483. ASSERT(FALSE);
  484. LocalFree(NewName);
  485. LocalFree(NewComment);
  486. LocalFree(NewSource);
  487. RtlReleaseResource(&LicenseListLock);
  488. return STATUS_NO_MEMORY;
  489. }
  490. // now copy it over...
  491. lstrcpy(NewVendor, Vendor);
  492. if (PurchaseList == NULL)
  493. PurchaseList = (PLICENSE_PURCHASE_RECORD) LocalAlloc(LPTR, sizeof(LICENSE_PURCHASE_RECORD) * (PurchaseListSize + 1));
  494. else
  495. {
  496. PLICENSE_PURCHASE_RECORD PurchaseListTemp = NULL;
  497. PurchaseListTemp = (PLICENSE_PURCHASE_RECORD) LocalReAlloc(PurchaseList, sizeof(LICENSE_PURCHASE_RECORD) * (PurchaseListSize + 1), LHND);
  498. if (PurchaseListTemp != NULL)
  499. {
  500. PurchaseList = PurchaseListTemp;
  501. } else
  502. {
  503. ASSERT(FALSE);
  504. LocalFree(NewName);
  505. LocalFree(NewComment);
  506. LocalFree(NewSource);
  507. LocalFree(NewVendor);
  508. RtlReleaseResource(&LicenseListLock);
  509. return STATUS_NO_MEMORY;
  510. }
  511. }
  512. //
  513. // Make sure we could allocate service table
  514. //
  515. if (PurchaseList == NULL)
  516. {
  517. ASSERT(FALSE);
  518. PurchaseListSize = 0;
  519. LocalFree(NewName);
  520. LocalFree(NewComment);
  521. LocalFree(NewSource);
  522. LocalFree(NewVendor);
  523. RtlReleaseResource(&LicenseListLock);
  524. return STATUS_NO_MEMORY;
  525. }
  526. PurchaseRecord = &PurchaseList[PurchaseListSize];
  527. PurchaseRecord->Admin = NewName;
  528. PurchaseRecord->Comment = NewComment;
  529. PurchaseRecord->Source = NewSource;
  530. PurchaseRecord->Vendor = NewVendor;
  531. //
  532. // Update the rest of the stuff.
  533. //
  534. PurchaseRecord->NumberLicenses = Quantity;
  535. PurchaseRecord->MaxQuantity = MaxQuantity;
  536. PurchaseRecord->Service = Service;
  537. PurchaseRecord->PerServerService = PerServerService;
  538. PurchaseRecord->AllowedModes = AllowedModes;
  539. PurchaseRecord->CertificateID = CertificateID;
  540. PurchaseRecord->ExpirationDate = ExpirationDate;
  541. memcpy( PurchaseRecord->Secrets, Secrets, LLS_NUM_SECRETS * sizeof( *Secrets ) );
  542. if (Date == 0)
  543. PurchaseRecord->Date = DateSystemGet();
  544. else
  545. PurchaseRecord->Date = Date;
  546. PurchaseListSize++;
  547. RtlReleaseResource(&LicenseListLock);
  548. if ( 0 != CertificateID )
  549. {
  550. // these should still be set from above
  551. ASSERT( lic.Product == ServiceName );
  552. ASSERT( lic.Vendor == Vendor );
  553. ASSERT( lic.Quantity == Quantity );
  554. ASSERT( lic.MaxQuantity == MaxQuantity );
  555. ASSERT( lic.Admin == Admin );
  556. ASSERT( lic.Comment == Comment );
  557. ASSERT( lic.Date == Date );
  558. ASSERT( lic.AllowedModes == AllowedModes );
  559. ASSERT( lic.CertificateID == CertificateID );
  560. ASSERT( lic.Source == Source );
  561. ASSERT( lic.ExpirationDate == ExpirationDate );
  562. ASSERT( 0 == memcmp( PurchaseRecord->Secrets, Secrets, LLS_NUM_SECRETS * sizeof( *Secrets ) ) );
  563. CertDbClaimEnter( NULL, &lic, FALSE, 0 );
  564. }
  565. //
  566. // Now check if we need to re-scan the user list and update licenses
  567. //
  568. if (ChangeLicense)
  569. {
  570. if ( NewLicenses < 0 )
  571. UserListLicenseDelete( mService, NewLicenses );
  572. if ( NewLicenses > 0 )
  573. FamilyLicenseUpdate ( mService->Family );
  574. }
  575. if ( AllowedModes & 2 )
  576. {
  577. // per server licenses modified
  578. LocalServiceListConcurrentLimitSet();
  579. LocalServerServiceListUpdate();
  580. ServiceListResynch();
  581. }
  582. return STATUS_SUCCESS;
  583. } // LicenseAdd
  584. /////////////////////////////////////////////////////////////////////////
  585. static
  586. NTSTATUS
  587. LicenseAdd_UpdateQuantity(
  588. LPTSTR ServiceName,
  589. LONG Quantity,
  590. BOOL UsePerServerList,
  591. PLICENSE_SERVICE_RECORD * ppService,
  592. BOOL * pChangeLicense,
  593. LONG * pNewLicenses,
  594. PMASTER_SERVICE_RECORD * pmService
  595. )
  596. {
  597. BOOL ChangeLicense = FALSE;
  598. PLICENSE_SERVICE_RECORD Service;
  599. PLICENSE_PURCHASE_RECORD PurchaseRecord;
  600. PMASTER_SERVICE_RECORD mService;
  601. LONG NewLicenses = 0;
  602. Service = LicenseServiceListFind( ServiceName, UsePerServerList );
  603. //
  604. // If we didn't find it we will need to add it.
  605. //
  606. if (Service == NULL)
  607. {
  608. if (Quantity < 0)
  609. {
  610. #if DBG
  611. dprintf(TEXT("Releasing Licenses from Non-existant product!\n"));
  612. #endif
  613. // ASSERT(FALSE);
  614. return STATUS_UNSUCCESSFUL;
  615. }
  616. else
  617. {
  618. Service = LicenseServiceListAdd(ServiceName, UsePerServerList);
  619. }
  620. }
  621. //
  622. // Check to make sure we found or added it. The only way we can fail is
  623. // if we couldn't alloc memory for it.
  624. //
  625. if (Service == NULL)
  626. {
  627. ASSERT(FALSE);
  628. return STATUS_NO_MEMORY;
  629. }
  630. if (((LONG) Service->NumberLicenses + Quantity) < 0)
  631. {
  632. return STATUS_UNSUCCESSFUL;
  633. }
  634. //
  635. // Update license count in service record
  636. //
  637. Service->NumberLicenses += Quantity;
  638. //
  639. // Now in master Service Record
  640. //
  641. RtlAcquireResourceShared(&MasterServiceListLock, TRUE);
  642. mService = MasterServiceListFind(ServiceName);
  643. if (mService != NULL)
  644. {
  645. //
  646. // if we were out of license and added more, then we need to update
  647. // the user list.
  648. //
  649. if ( ( Quantity > 0 )
  650. && ( (mService->LicensesUsed > mService->Licenses) || (mService == BackOfficeRec) ) )
  651. {
  652. ChangeLicense = TRUE;
  653. }
  654. //
  655. // Can only add a number of licenses up to licensed amount
  656. //
  657. if ( ChangeLicense )
  658. {
  659. // Get current unlicensed delta
  660. NewLicenses = mService->LicensesUsed - mService->Licenses;
  661. if ((NewLicenses <= 0) || (NewLicenses > Quantity))
  662. {
  663. NewLicenses = Quantity;
  664. }
  665. }
  666. if ( UsePerServerList )
  667. {
  668. // this will be done by LicenseAdd() in LocalServerServiceListUpdate()
  669. // mService->MaxSessionCount += Quantity;
  670. }
  671. else
  672. {
  673. mService->Licenses += Quantity;
  674. }
  675. //
  676. // if we we subtracted licenses and are out of licenses, then we
  677. // need to scan the user list.
  678. //
  679. if (Quantity < 0)
  680. {
  681. if (mService->LicensesUsed > mService->Licenses)
  682. {
  683. ChangeLicense = TRUE;
  684. //
  685. // Only remove # of licenses past limit
  686. //
  687. NewLicenses = mService->Licenses - mService->LicensesUsed;
  688. if (NewLicenses < Quantity)
  689. {
  690. NewLicenses = Quantity;
  691. }
  692. }
  693. }
  694. }
  695. RtlReleaseResource(&MasterServiceListLock);
  696. *ppService = Service;
  697. *pChangeLicense = ChangeLicense;
  698. *pNewLicenses = NewLicenses;
  699. *pmService = mService;
  700. return STATUS_SUCCESS;
  701. }
  702. #if DBG
  703. /////////////////////////////////////////////////////////////////////////
  704. VOID
  705. LicenseListDebugDump( )
  706. /*++
  707. Routine Description:
  708. Arguments:
  709. Return Value:
  710. --*/
  711. {
  712. ULONG i = 0;
  713. ULONG j = 0;
  714. //
  715. // Need to scan list so get read access.
  716. //
  717. RtlAcquireResourceShared(&LicenseListLock, TRUE);
  718. //
  719. // Dump License Service List first
  720. //
  721. dprintf(TEXT("Per Seat License Service Table, # Entries: %lu\n"), LicenseServiceListSize);
  722. if (LicenseServiceList != NULL)
  723. {
  724. for (i = 0; i < LicenseServiceListSize; i++)
  725. dprintf(TEXT(" %2lu) Tot Licenses: %lu Product: %s\n"), i, LicenseServiceList[i]->NumberLicenses, LicenseServiceList[i]->ServiceName);
  726. }
  727. dprintf(TEXT("\nPer Server License Service Table, # Entries: %lu\n"), PerServerLicenseServiceListSize);
  728. if (PerServerLicenseServiceList != NULL)
  729. {
  730. for (i = 0; i < PerServerLicenseServiceListSize; i++)
  731. dprintf(TEXT(" %2lu) Tot Licenses: %lu Product: %s\n"), i, PerServerLicenseServiceList[i]->NumberLicenses, PerServerLicenseServiceList[i]->ServiceName);
  732. }
  733. //
  734. // Now do purchase history
  735. //
  736. dprintf(TEXT("\nPurchase History, # Entries: %lu\n"), PurchaseListSize);
  737. if (PurchaseList != NULL)
  738. {
  739. for (i = 0; i < PurchaseListSize; i++)
  740. {
  741. TCHAR szExpirationDate[ 40 ];
  742. lstrcpy( szExpirationDate, TimeToString( PurchaseList[i].ExpirationDate ) );
  743. dprintf( TEXT(" %3lu) Product : %s\n" )
  744. TEXT( " Vendor : %s\n" )
  745. TEXT( " Allowed Modes :%s%s\n" )
  746. TEXT( " Licenses : %d\n" )
  747. TEXT( " Max Licenses : %lu\n" )
  748. TEXT( " Date Entered : %s\n" )
  749. TEXT( " Date Expires : %s\n" )
  750. TEXT( " Certificate ID : %lu\n" )
  751. TEXT( " Secrets :" ),
  752. i,
  753. ( PurchaseList[i].AllowedModes & LLS_LICENSE_MODE_ALLOW_PER_SEAT )
  754. ? PurchaseList[i].Service->ServiceName
  755. : PurchaseList[i].PerServerService->ServiceName,
  756. PurchaseList[i].Vendor,
  757. ( PurchaseList[i].AllowedModes & LLS_LICENSE_MODE_ALLOW_PER_SEAT )
  758. ? TEXT(" PERSEAT")
  759. : TEXT(""),
  760. ( PurchaseList[i].AllowedModes & LLS_LICENSE_MODE_ALLOW_PER_SERVER )
  761. ? TEXT(" PERSERVER")
  762. : TEXT(""),
  763. PurchaseList[i].NumberLicenses,
  764. PurchaseList[i].MaxQuantity,
  765. TimeToString( PurchaseList[i].Date ),
  766. szExpirationDate,
  767. PurchaseList[i].CertificateID
  768. );
  769. for ( j=0; j < LLS_NUM_SECRETS; j++ )
  770. {
  771. dprintf( TEXT( " %08X" ), PurchaseList[i].Secrets[j] );
  772. }
  773. dprintf( TEXT( "\n" )
  774. TEXT( " Source : %s\n" )
  775. TEXT( " Admin : %s\n" )
  776. TEXT( " Comment : %s\n\n" ),
  777. PurchaseList[i].Source,
  778. PurchaseList[i].Admin,
  779. PurchaseList[i].Comment
  780. );
  781. }
  782. }
  783. RtlReleaseResource(&LicenseListLock);
  784. return;
  785. } // LicenseListDebugDump
  786. #endif