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.

3387 lines
87 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. perseat.c
  5. Abstract:
  6. Routines to handle per-seat licensing. Handles the in-memory cache
  7. of useage via the Rtl Generic table functions (these are a generic
  8. splay tree package).
  9. There can be up to three tables kept. The first table is a username
  10. table and is the main table. The second table is for SID's, which will
  11. be converted into usernames when replicated.
  12. The SID and username trees are handled in this module as they are used
  13. by all modes of the server.
  14. Author:
  15. Arthur Hanson (arth) 03-Jan-1995
  16. Revision History:
  17. Jeff Parham (jeffparh) 12-Jan-1996
  18. o Fixed possible infinite loop in UserListLicenseDelete().
  19. o In FamilyLicenseUpdate(), now rescans for BackOffice upgrades
  20. regardless of whether the family being updated was BackOffice.
  21. This fixes a problem wherein a freed BackOffice license was
  22. not being assigned to a user that needed it. (Bug #3299.)
  23. o Added support for maintaining the SUITE_USE flag when adding
  24. users to the AddCache.
  25. --*/
  26. #include <stdlib.h>
  27. #include <nt.h>
  28. #include <ntrtl.h>
  29. #include <nturtl.h>
  30. #include <windows.h>
  31. #include <lm.h>
  32. #include <dsgetdc.h>
  33. #include "debug.h"
  34. #include "llsutil.h"
  35. #include "llssrv.h"
  36. #include "mapping.h"
  37. #include "msvctbl.h"
  38. #include "svctbl.h"
  39. #include "perseat.h"
  40. #include "llsevent.h"
  41. #include "llsrtl.h"
  42. #define NO_LLS_APIS
  43. #include "llsapi.h"
  44. //
  45. // At what # of product do we switch to BackOffice
  46. //
  47. #define BACKOFFICE_SWITCH 3
  48. NTSTATUS GetDCInfo(
  49. DWORD ccDomain,
  50. WCHAR wszDomain[],
  51. DOMAIN_CONTROLLER_INFO ** ppDCInfo);
  52. /////////////////////////////////////////////////////////////////////////
  53. //
  54. // Actual User and SID Lists, and their access locks
  55. //
  56. ULONG UserListNumEntries = 0;
  57. static ULONG SidListNumEntries = 0;
  58. LLS_GENERIC_TABLE UserList;
  59. static LLS_GENERIC_TABLE SidList;
  60. RTL_RESOURCE UserListLock;
  61. static RTL_RESOURCE SidListLock;
  62. /////////////////////////////////////////////////////////////////////////
  63. //
  64. // The AddCache itself, a critical section to protect access to it and an
  65. // event to signal the server when there are items on it that need to be
  66. // processed.
  67. //
  68. PADD_CACHE AddCache = NULL;
  69. ULONG AddCacheSize = 0;
  70. RTL_CRITICAL_SECTION AddCacheLock;
  71. HANDLE LLSAddCacheEvent;
  72. DWORD LastUsedTime = 0;
  73. BOOL UsersDeleted = FALSE;
  74. static RTL_CRITICAL_SECTION GenTableLock;
  75. /////////////////////////////////////////////////////////////////////////
  76. /////////////////////////////////////////////////////////////////////////
  77. //
  78. // The License List is a linear list of all the licenses the object is
  79. // using.
  80. //
  81. // The license list is kept as part of each user and mapping record, if
  82. // the user is mapped then the mapping should contain the license list.
  83. // The structure is a sorted array of pointers to License Records, and
  84. // access is controled by the ServiceTableLock.
  85. //
  86. // The license is identified by the Service Family Name (the license list
  87. // is sorted on this).
  88. //
  89. /////////////////////////////////////////////////////////////////////////
  90. int __cdecl
  91. LicenseListCompare(const void *arg1, const void *arg2) {
  92. PUSER_LICENSE_RECORD pLic1, pLic2;
  93. pLic1 = (PUSER_LICENSE_RECORD) *((PUSER_LICENSE_RECORD *) arg1);
  94. pLic2 = (PUSER_LICENSE_RECORD) *((PUSER_LICENSE_RECORD *) arg2);
  95. return lstrcmpi( pLic1->Family->Name, pLic2->Family->Name );
  96. } // LicenseListCompare
  97. /////////////////////////////////////////////////////////////////////////
  98. PUSER_LICENSE_RECORD
  99. LicenseListFind(
  100. LPTSTR Name,
  101. PUSER_LICENSE_RECORD *pLicenseList,
  102. ULONG NumTableEntries
  103. )
  104. /*++
  105. Routine Description:
  106. Find the license in a license list for the given Family of products.
  107. Arguments:
  108. Name - Name of product family to find license for.
  109. pLicenseList - Size of the license list to search.
  110. NumTableEntries - Pointer to the license List to search.
  111. Return Value:
  112. Pointer to the found License Record, or NULL if not found.
  113. --*/
  114. {
  115. LONG begin = 0;
  116. LONG end = (LONG) NumTableEntries - 1;
  117. LONG cur;
  118. int match;
  119. #if DBG
  120. if (TraceFlags & TRACE_FUNCTION_TRACE)
  121. dprintf(TEXT("LLS TRACE: LicenseListFind\n"));
  122. #endif
  123. if ((Name == NULL) || (pLicenseList == NULL) || (NumTableEntries == 0))
  124. return NULL;
  125. while (end >= begin) {
  126. // go halfway in-between
  127. cur = (begin + end) / 2;
  128. // compare the two result into match
  129. match = lstrcmpi(Name, pLicenseList[cur]->Family->Name);
  130. if (match < 0)
  131. // move new begin
  132. end = cur - 1;
  133. else
  134. begin = cur + 1;
  135. if (match == 0)
  136. return pLicenseList[cur];
  137. }
  138. return NULL;
  139. } // LicenseListFind
  140. /////////////////////////////////////////////////////////////////////////
  141. NTSTATUS
  142. LicenseListDelete(
  143. PMASTER_SERVICE_ROOT Family,
  144. PUSER_LICENSE_RECORD **pLicenses,
  145. PULONG pLicenseListSize
  146. )
  147. /*++
  148. Routine Description:
  149. Delete the given license from the license list.
  150. Arguments:
  151. Family -
  152. pLicenses -
  153. pLicenseListSize -
  154. Return Value:
  155. STATUS_SUCCESS if successful, else error code.
  156. --*/
  157. {
  158. PUSER_LICENSE_RECORD *LicenseList;
  159. ULONG LicenseListSize;
  160. PUSER_LICENSE_RECORD LicenseRec;
  161. ULONG i;
  162. PUSER_LICENSE_RECORD *pLicenseListTmp;
  163. #if DBG
  164. if (TraceFlags & TRACE_FUNCTION_TRACE)
  165. dprintf(TEXT("LLS TRACE: LicenseListDelete\n"));
  166. #endif
  167. if ( (pLicenses == NULL) || (pLicenseListSize == NULL) )
  168. return STATUS_OBJECT_NAME_NOT_FOUND;
  169. LicenseListSize = *pLicenseListSize;
  170. LicenseList = *pLicenses;
  171. //
  172. // Get record based on name given
  173. //
  174. LicenseRec = LicenseListFind(Family->Name, LicenseList, LicenseListSize);
  175. if (LicenseRec == NULL)
  176. return STATUS_OBJECT_NAME_NOT_FOUND;
  177. //
  178. // Check if this is the last user
  179. //
  180. if (LicenseListSize == 1) {
  181. LocalFree(LicenseList);
  182. *pLicenseListSize = 0;
  183. *pLicenses = NULL;
  184. return STATUS_SUCCESS;
  185. }
  186. //
  187. // Not the last so find it in the list
  188. //
  189. i = 0;
  190. while ( (i < LicenseListSize) && (LicenseList[i]->Family != Family) )
  191. i++;
  192. //
  193. // Now move everything below it up.
  194. //
  195. i++;
  196. while (i < LicenseListSize) {
  197. LicenseList[i-1] = LicenseList[i];
  198. i++;
  199. }
  200. pLicenseListTmp = (PUSER_LICENSE_RECORD *) LocalReAlloc(LicenseList, sizeof(PUSER_LICENSE_RECORD) * (LicenseListSize - 1), LHND);
  201. //
  202. // Make sure we could allocate table
  203. //
  204. if (pLicenseListTmp != NULL) {
  205. LicenseList = pLicenseListTmp;
  206. }
  207. LicenseListSize--;
  208. LocalFree(LicenseRec);
  209. *pLicenses = LicenseList;
  210. *pLicenseListSize = LicenseListSize;
  211. return STATUS_SUCCESS;
  212. } // LicenseListDelete
  213. /////////////////////////////////////////////////////////////////////////
  214. PUSER_LICENSE_RECORD
  215. LicenseListAdd(
  216. PMASTER_SERVICE_ROOT Family,
  217. PUSER_LICENSE_RECORD **pLicenses,
  218. PULONG pLicenseListSize
  219. )
  220. /*++
  221. Routine Description:
  222. Adds an empty license record to the license list. Sets the license
  223. family, but not any of the other info.
  224. Arguments:
  225. Return Value:
  226. --*/
  227. {
  228. PUSER_LICENSE_RECORD *LicenseList;
  229. ULONG LicenseListSize;
  230. PUSER_LICENSE_RECORD LicenseRec;
  231. PUSER_LICENSE_RECORD *pLicenseListTmp;
  232. #if DBG
  233. if (TraceFlags & TRACE_FUNCTION_TRACE)
  234. dprintf(TEXT("LLS TRACE: LicenseListAdd\n"));
  235. #endif
  236. if ((Family == NULL) || (pLicenses == NULL) || (pLicenseListSize == NULL) )
  237. return NULL;
  238. LicenseList = *pLicenses;
  239. LicenseListSize = *pLicenseListSize;
  240. //
  241. // We do a double check here to see if another thread just got done
  242. // adding the Mapping, between when we checked last and actually got
  243. // the write lock.
  244. //
  245. LicenseRec = LicenseListFind(Family->Name, LicenseList, LicenseListSize );
  246. if (LicenseRec != NULL) {
  247. return LicenseRec;
  248. }
  249. LicenseRec = (PUSER_LICENSE_RECORD) LocalAlloc(LPTR, sizeof(USER_LICENSE_RECORD));
  250. if (LicenseRec == NULL) {
  251. ASSERT(FALSE);
  252. return NULL;
  253. }
  254. //
  255. // Allocate space for table (zero init it).
  256. //
  257. if (LicenseList == NULL)
  258. pLicenseListTmp = (PUSER_LICENSE_RECORD *) LocalAlloc(LPTR, sizeof(PUSER_LICENSE_RECORD));
  259. else
  260. pLicenseListTmp = (PUSER_LICENSE_RECORD *) LocalReAlloc(LicenseList, sizeof(PUSER_LICENSE_RECORD) * (LicenseListSize + 1), LHND);
  261. //
  262. // Make sure we could allocate Mapping table
  263. //
  264. if (pLicenseListTmp == NULL) {
  265. LocalFree(LicenseRec);
  266. return NULL;
  267. } else {
  268. LicenseList = pLicenseListTmp;
  269. }
  270. // now copy it over...
  271. LicenseList[LicenseListSize] = LicenseRec;
  272. LicenseRec->Family = Family;
  273. LicenseRec->Flags = LLS_FLAG_LICENSED;
  274. LicenseRec->RefCount = 0;
  275. LicenseRec->Service = NULL;
  276. LicenseRec->LicensesNeeded = 0;
  277. LicenseListSize++;
  278. // Have added the entry - now need to sort it in order of the names
  279. qsort((void *) LicenseList, (size_t) LicenseListSize, sizeof(PUSER_LICENSE_RECORD), LicenseListCompare);
  280. *pLicenses = LicenseList;
  281. *pLicenseListSize = LicenseListSize;
  282. return LicenseRec;
  283. } // LicenseListAdd
  284. /////////////////////////////////////////////////////////////////////////
  285. // These routines are specific to the license list in the user and
  286. // mapping records.
  287. /////////////////////////////////////////////////////////////////////////
  288. /////////////////////////////////////////////////////////////////////////
  289. VOID
  290. UserLicenseListFree (
  291. PUSER_RECORD pUser
  292. )
  293. /*++
  294. Routine Description:
  295. Walks the license list deleting all entries and freeing up any claimed
  296. licenses from the service table. This only cleans up the licenses
  297. in a user record (not a mapping) so the # licenses is always 1.
  298. Arguments:
  299. Return Value:
  300. --*/
  301. {
  302. ULONG i;
  303. BOOL ReScan = FALSE;
  304. #if DBG
  305. if (TraceFlags & TRACE_FUNCTION_TRACE)
  306. dprintf(TEXT("LLS TRACE: UserLicenseListFree\n"));
  307. #endif
  308. //
  309. // Walk license table and free all licenses
  310. //
  311. for (i = 0; i < pUser->LicenseListSize; i++) {
  312. pUser->LicenseList[i]->Service->LicensesUsed -= 1;
  313. pUser->LicenseList[i]->Service->LicensesClaimed -= (1 - pUser->LicenseList[i]->LicensesNeeded);
  314. pUser->LicenseList[i]->Service->Family->Flags |= LLS_FLAG_UPDATE;
  315. ReScan = TRUE;
  316. LocalFree(pUser->LicenseList[i]);
  317. }
  318. //
  319. // Free related entries in user list
  320. //
  321. if (pUser->LicenseList != NULL)
  322. LocalFree(pUser->LicenseList);
  323. pUser->LicenseList = NULL;
  324. pUser->LicenseListSize = 0;
  325. pUser->LicensedProducts = 0;
  326. //
  327. // Get rid of pointers in services table
  328. //
  329. for (i = 0; i < pUser->ServiceTableSize; i++)
  330. pUser->Services[i].License = NULL;
  331. //
  332. // Check if we freed up licenses and need to re-scan the user-table
  333. //
  334. if (ReScan) {
  335. //
  336. // Set to licensed so scan doesn't assign to ourself
  337. //
  338. pUser->Flags |= LLS_FLAG_LICENSED;
  339. for (i = 0; i < RootServiceListSize; i++) {
  340. if (RootServiceList[i]->Flags & LLS_FLAG_UPDATE) {
  341. RootServiceList[i]->Flags &= ~LLS_FLAG_UPDATE;
  342. FamilyLicenseUpdate( RootServiceList[i] );
  343. }
  344. }
  345. if (pUser->ServiceTableSize > 0)
  346. pUser->Flags &= ~LLS_FLAG_LICENSED;
  347. }
  348. } // UserLicenseListFree
  349. /////////////////////////////////////////////////////////////////////////
  350. VOID
  351. MappingLicenseListFree (
  352. PMAPPING_RECORD pMap
  353. )
  354. /*++
  355. Routine Description:
  356. Walks the license list in a mapping freeing up any claimed licenses.
  357. Like UserLicenseListFree, but for a mapping.
  358. Arguments:
  359. Return Value:
  360. --*/
  361. {
  362. ULONG i;
  363. BOOL ReScan = FALSE;
  364. #if DBG
  365. if (TraceFlags & TRACE_FUNCTION_TRACE)
  366. dprintf(TEXT("LLS TRACE: MappingLicenseListFree\n"));
  367. #endif
  368. //
  369. // Walk license table and free all licenses
  370. //
  371. for (i = 0; i < pMap->LicenseListSize; i++) {
  372. pMap->LicenseList[i]->Service->LicensesUsed -= pMap->Licenses;
  373. pMap->LicenseList[i]->Service->LicensesClaimed -= (pMap->Licenses - pMap->LicenseList[i]->LicensesNeeded);
  374. pMap->LicenseList[i]->Service->Family->Flags |= LLS_FLAG_UPDATE;
  375. ReScan = TRUE;
  376. LocalFree(pMap->LicenseList[i]);
  377. }
  378. //
  379. // Free related entries in mapping list
  380. //
  381. if (pMap->LicenseList != NULL)
  382. LocalFree(pMap->LicenseList);
  383. pMap->LicenseList = NULL;
  384. pMap->LicenseListSize = 0;
  385. //
  386. // Check if we freed up licenses and need to re-scan the user-table
  387. //
  388. if (ReScan)
  389. for (i = 0; i < RootServiceListSize; i++) {
  390. if (RootServiceList[i]->Flags & LLS_FLAG_UPDATE) {
  391. RootServiceList[i]->Flags &= ~LLS_FLAG_UPDATE;
  392. FamilyLicenseUpdate( RootServiceList[i] );
  393. }
  394. }
  395. } // MappingLicenseListFree
  396. /////////////////////////////////////////////////////////////////////////
  397. /////////////////////////////////////////////////////////////////////////
  398. //
  399. // The service table is a linear array of records pointed to by the
  400. // user record. Each entry contains a pointer into the service table
  401. // identifying the service, some statistical useage information and a
  402. // pointer into the license table identifying the license used by the
  403. // service.
  404. //
  405. /////////////////////////////////////////////////////////////////////////
  406. int __cdecl
  407. SvcListCompare(
  408. const void *arg1,
  409. const void *arg2
  410. )
  411. {
  412. PSVC_RECORD pSvc1, pSvc2;
  413. pSvc1 = (PSVC_RECORD) arg1;
  414. pSvc2 = (PSVC_RECORD) arg2;
  415. return lstrcmpi( pSvc1->Service->Name, pSvc2->Service->Name );
  416. } // SvcListCompare
  417. /////////////////////////////////////////////////////////////////////////
  418. PSVC_RECORD
  419. SvcListFind(
  420. LPTSTR DisplayName,
  421. PSVC_RECORD ServiceList,
  422. ULONG NumTableEntries
  423. )
  424. /*++
  425. Routine Description:
  426. Internal routine to actually do binary search on Service List in user
  427. record. This is a binary search, however since the string pointers are
  428. from the service table and therefore the pointers are fixed, we only
  429. need to compare the pointers, not the strings themselves to find a
  430. match.
  431. Arguments:
  432. ServiceName -
  433. Return Value:
  434. Pointer to found service table entry or NULL if not found.
  435. --*/
  436. {
  437. LONG begin = 0;
  438. LONG end = (LONG) NumTableEntries - 1;
  439. LONG cur;
  440. int match;
  441. #if DBG
  442. if (TraceFlags & TRACE_FUNCTION_TRACE)
  443. dprintf(TEXT("LLS TRACE: SvcListFind\n"));
  444. #endif
  445. if ((DisplayName == NULL) || (ServiceList == NULL) || (NumTableEntries == 0))
  446. return NULL;
  447. while (end >= begin) {
  448. // go halfway in-between
  449. cur = (begin + end) / 2;
  450. // compare the two result into match
  451. match = lstrcmpi(DisplayName, ServiceList[cur].Service->Name);
  452. if (match < 0)
  453. // move new begin
  454. end = cur - 1;
  455. else
  456. begin = cur + 1;
  457. if (match == 0)
  458. return &ServiceList[cur];
  459. }
  460. return NULL;
  461. } // SvcListFind
  462. /////////////////////////////////////////////////////////////////////////
  463. NTSTATUS
  464. SvcListDelete(
  465. LPTSTR UserName,
  466. LPTSTR ServiceName
  467. )
  468. /*++
  469. Routine Description:
  470. Deletes a service record from the service table.
  471. Arguments:
  472. Return Value:
  473. --*/
  474. {
  475. PUSER_RECORD pUserRec;
  476. PSVC_RECORD pService;
  477. PSVC_RECORD SvcTable = NULL;
  478. PUSER_LICENSE_RECORD License = NULL;
  479. ULONG NumLicenses = 1;
  480. ULONG i;
  481. BOOL ReScan = FALSE;
  482. PMASTER_SERVICE_ROOT Family = NULL;
  483. PSVC_RECORD pSvcTableTmp;
  484. #if DBG
  485. if (TraceFlags & TRACE_FUNCTION_TRACE)
  486. dprintf(TEXT("LLS TRACE: SvcListDelete\n"));
  487. #endif
  488. pUserRec = UserListFind(UserName);
  489. if (pUserRec == NULL)
  490. return STATUS_OBJECT_NAME_NOT_FOUND;
  491. RtlEnterCriticalSection(&pUserRec->ServiceTableLock);
  492. pService = SvcListFind( ServiceName, pUserRec->Services, pUserRec->ServiceTableSize );
  493. //
  494. // If we couldn't find it then get out.
  495. //
  496. if (pService == NULL) {
  497. RtlLeaveCriticalSection(&pUserRec->ServiceTableLock);
  498. return STATUS_OBJECT_NAME_NOT_FOUND;
  499. }
  500. Family = pService->Service->Family;
  501. //
  502. // If we are a mapping then we may use more then one license
  503. //
  504. if (pUserRec->Mapping != NULL)
  505. NumLicenses = pUserRec->Mapping->Licenses;
  506. License = pService->License;
  507. if (License != NULL) {
  508. License->RefCount--;
  509. //
  510. // If this is the last service that uses this license then we need
  511. // to get rid of it.
  512. //
  513. if (License->RefCount == 0) {
  514. License->Service->LicensesUsed -= NumLicenses;
  515. NumLicenses -= License->LicensesNeeded;
  516. License->Service->LicensesClaimed -= NumLicenses;
  517. //
  518. // Do we need to delete it from the mapping or user license table?
  519. //
  520. if (pUserRec->Mapping != NULL) {
  521. if ((License->Service == BackOfficeRec) && (pUserRec->Mapping->Flags & LLS_FLAG_SUITE_AUTO))
  522. pUserRec->Mapping->Flags &= ~LLS_FLAG_SUITE_USE;
  523. LicenseListDelete(License->Service->Family, &pUserRec->Mapping->LicenseList, &pUserRec->Mapping->LicenseListSize );
  524. } else {
  525. if ((License->Service == BackOfficeRec) && (pUserRec->Flags & LLS_FLAG_SUITE_AUTO))
  526. pUserRec->Flags &= ~LLS_FLAG_SUITE_USE;
  527. LicenseListDelete(License->Service->Family, &pUserRec->LicenseList, &pUserRec->LicenseListSize );
  528. }
  529. //
  530. // Freed a license so need to scan and adjust counts
  531. //
  532. ReScan = TRUE;
  533. }
  534. }
  535. if (pService->Flags & LLS_FLAG_LICENSED)
  536. pUserRec->LicensedProducts--;
  537. else {
  538. //
  539. // This was an unlicensed product - see if this makes the user
  540. // licensed
  541. //
  542. if (pUserRec->LicensedProducts == (pUserRec->ServiceTableSize - 1))
  543. pUserRec->Flags |= LLS_FLAG_LICENSED;
  544. }
  545. //
  546. // First check if this is the only entry in the table
  547. //
  548. if (pUserRec->ServiceTableSize == 1) {
  549. LocalFree(pUserRec->Services);
  550. pUserRec->Services = NULL;
  551. goto SvcListDeleteExit;
  552. }
  553. //
  554. // Find this record linearly in the table.
  555. //
  556. i = 0;
  557. while ((i < pUserRec->ServiceTableSize) && (lstrcmpi(pUserRec->Services[i].Service->Name, ServiceName)))
  558. i++;
  559. //
  560. // Now move everything below it up.
  561. //
  562. i++;
  563. while (i < pUserRec->ServiceTableSize) {
  564. memcpy(&pUserRec->Services[i-1], &pUserRec->Services[i], sizeof(SVC_RECORD));
  565. i++;
  566. }
  567. pSvcTableTmp = (PSVC_RECORD) LocalReAlloc( pUserRec->Services, sizeof(SVC_RECORD) * (pUserRec->ServiceTableSize - 1), LHND);
  568. if (pSvcTableTmp == NULL) {
  569. pUserRec->ServiceTableSize--;
  570. RtlLeaveCriticalSection(&pUserRec->ServiceTableLock);
  571. return STATUS_SUCCESS;
  572. } else {
  573. SvcTable = pSvcTableTmp;
  574. }
  575. pUserRec->Services = SvcTable;
  576. SvcListDeleteExit:
  577. pUserRec->ServiceTableSize--;
  578. if (pUserRec->ServiceTableSize == 0)
  579. pUserRec->Services = NULL;
  580. RtlLeaveCriticalSection(&pUserRec->ServiceTableLock);
  581. if (ReScan)
  582. FamilyLicenseUpdate ( Family );
  583. return STATUS_SUCCESS;
  584. } // SvcListDelete
  585. /////////////////////////////////////////////////////////////////////////
  586. VOID
  587. SvcListLicenseFree(
  588. PUSER_RECORD pUser
  589. )
  590. /*++
  591. Routine Description:
  592. Walk the services table and free up any licenses they are using. If the
  593. licenses are then no longer needed (refCount == 0) then the license is
  594. deleted.
  595. Arguments:
  596. Return Value:
  597. --*/
  598. {
  599. ULONG i;
  600. ULONG NumLicenses = 1;
  601. PUSER_LICENSE_RECORD License = NULL;
  602. BOOL ReScan = FALSE;
  603. #if DBG
  604. if (TraceFlags & TRACE_FUNCTION_TRACE)
  605. dprintf(TEXT("LLS TRACE: SvcListLicenseFree\n"));
  606. #endif
  607. //
  608. // If we are a mapping then we may use more then one license
  609. //
  610. for (i = 0; i < pUser->ServiceTableSize; i++) {
  611. if (pUser->Mapping != NULL)
  612. NumLicenses = pUser->Mapping->Licenses;
  613. else
  614. NumLicenses = 1;
  615. License = pUser->Services[i].License;
  616. if (License != NULL) {
  617. License->RefCount--;
  618. //
  619. // If this is the last service that uses this license then we need
  620. // to get rid of it.
  621. //
  622. if (License->RefCount == 0) {
  623. if ( (pUser->Mapping != NULL) && (License->Service == BackOfficeRec) && (pUser->Mapping->Flags & LLS_FLAG_SUITE_AUTO) )
  624. pUser->Mapping->Flags &= ~LLS_FLAG_SUITE_USE;
  625. License->Service->LicensesUsed -= NumLicenses;
  626. NumLicenses -= License->LicensesNeeded;
  627. if (License->Service->LicensesClaimed > 0) {
  628. //
  629. // Freed a license so need to scan and adjust counts
  630. //
  631. License->Service->Family->Flags |= LLS_FLAG_UPDATE;
  632. ReScan = TRUE;
  633. }
  634. License->Service->LicensesClaimed -= NumLicenses;
  635. if (pUser->Mapping != NULL)
  636. LicenseListDelete(License->Service->Family, &pUser->Mapping->LicenseList, &pUser->Mapping->LicenseListSize );
  637. else
  638. LicenseListDelete(License->Service->Family, &pUser->LicenseList, &pUser->LicenseListSize );
  639. }
  640. }
  641. pUser->Services[i].License = NULL;
  642. }
  643. pUser->LicensedProducts = 0;
  644. //
  645. // Check if we freed up licenses and need to re-scan the user-table
  646. //
  647. if (ReScan) {
  648. //
  649. // Flag license so rescan won't worry about this user
  650. //
  651. pUser->Flags |= LLS_FLAG_LICENSED;
  652. for (i = 0; i < RootServiceListSize; i++) {
  653. if (RootServiceList[i]->Flags & LLS_FLAG_UPDATE) {
  654. RootServiceList[i]->Flags &= ~LLS_FLAG_UPDATE;
  655. FamilyLicenseUpdate( RootServiceList[i] );
  656. }
  657. }
  658. }
  659. } // SvcListLicenseFree
  660. /////////////////////////////////////////////////////////////////////////
  661. VOID
  662. SvcListLicenseUpdate(
  663. PUSER_RECORD pUser
  664. )
  665. /*++
  666. Routine Description:
  667. Walk the services table and assign the appropriate license to each
  668. service. This is the opposite of the SvcListLicenseFree Routine.
  669. Arguments:
  670. Return Value:
  671. --*/
  672. {
  673. ULONG i;
  674. ULONG Claimed = 0;
  675. PUSER_LICENSE_RECORD License = NULL;
  676. #if DBG
  677. if (TraceFlags & TRACE_FUNCTION_TRACE)
  678. dprintf(TEXT("LLS TRACE: SvcListLicenseUpdate\n"));
  679. #endif
  680. //
  681. // Check if user is set to use BackOffice
  682. if ( pUser->Flags & LLS_FLAG_SUITE_USE ) {
  683. //
  684. // Go grab a backoffice license to fulfill the suite useage
  685. //
  686. License = LicenseListAdd(BackOfficeRec->Family, &pUser->LicenseList, &pUser->LicenseListSize);
  687. ASSERT(License != NULL);
  688. if (License != NULL) {
  689. License->Service = BackOfficeRec;
  690. RtlAcquireResourceExclusive(&MasterServiceListLock, TRUE);
  691. // Can only claim a # of licenses that we have
  692. if ( BackOfficeRec->LicensesClaimed < BackOfficeRec->Licenses) {
  693. Claimed = BackOfficeRec->Licenses - BackOfficeRec->LicensesClaimed;
  694. if (Claimed > 1)
  695. Claimed = 1;
  696. }
  697. //
  698. // Adjust license counts
  699. //
  700. BackOfficeRec->LicensesUsed += 1;
  701. BackOfficeRec->LicensesClaimed += Claimed;
  702. License->LicensesNeeded = 1 - Claimed;
  703. //
  704. // Figure out if we are licensed or not.
  705. //
  706. if (License->LicensesNeeded > 0) {
  707. //
  708. // Not licensed
  709. //
  710. License->Flags &= ~LLS_FLAG_LICENSED;
  711. pUser->Flags &= ~LLS_FLAG_LICENSED;
  712. for (i = 0; i < pUser->ServiceTableSize; i++) {
  713. pUser->Services[i].Flags &= ~LLS_FLAG_LICENSED;
  714. pUser->Services[i].License = License;
  715. License->RefCount++;
  716. }
  717. } else {
  718. //
  719. // Licensed
  720. //
  721. License->Flags |= LLS_FLAG_LICENSED;
  722. pUser->Flags |= LLS_FLAG_LICENSED;
  723. for (i = 0; i < pUser->ServiceTableSize; i++) {
  724. pUser->LicensedProducts++;
  725. pUser->Services[i].Flags |= LLS_FLAG_LICENSED;
  726. pUser->Services[i].License = License;
  727. License->RefCount++;
  728. }
  729. }
  730. RtlReleaseResource(&MasterServiceListLock);
  731. }
  732. } else {
  733. BOOL Licensed = TRUE;
  734. //
  735. // Loop through all the services and make sure they are all
  736. // licensed.
  737. //
  738. for (i = 0; i < pUser->ServiceTableSize; i++) {
  739. SvcLicenseUpdate(pUser, &pUser->Services[i]);
  740. if ( pUser->Services[i].Flags & LLS_FLAG_LICENSED )
  741. pUser->LicensedProducts++;
  742. else
  743. Licensed = FALSE;
  744. }
  745. if (Licensed)
  746. pUser->Flags |= LLS_FLAG_LICENSED;
  747. else
  748. pUser->Flags &= ~LLS_FLAG_LICENSED;
  749. }
  750. } // SvcListLicenseUpdate
  751. /////////////////////////////////////////////////////////////////////////
  752. VOID
  753. SvcLicenseUpdate(
  754. PUSER_RECORD pUser,
  755. PSVC_RECORD Svc
  756. )
  757. /*++
  758. Routine Description:
  759. For a given service record for a user check and update license compliance.
  760. Is a single service record version of SvcListLicenseUpdate.
  761. Arguments:
  762. Return Value:
  763. --*/
  764. {
  765. ULONG NumLicenses = 1;
  766. PUSER_LICENSE_RECORD License = NULL;
  767. BOOL UseMapping = FALSE;
  768. PMASTER_SERVICE_RECORD LicenseService = NULL;
  769. PMASTER_SERVICE_RECORD Service;
  770. BOOL ReScan = FALSE;
  771. DWORD Flags = 0;
  772. #if DBG
  773. if (TraceFlags & TRACE_FUNCTION_TRACE)
  774. dprintf(TEXT("LLS TRACE: SvcLicenseUpdate\n"));
  775. #endif
  776. if ((pUser == NULL) || (Svc == NULL))
  777. return;
  778. Flags = pUser->Flags;
  779. //
  780. // If we are a mapping then we may use more then one license
  781. //
  782. if (pUser->Mapping != NULL) {
  783. NumLicenses = pUser->Mapping->Licenses;
  784. UseMapping = TRUE;
  785. Flags = pUser->Mapping->Flags;
  786. }
  787. //
  788. // Try to find a license record in the license list of the user or mapping
  789. // to use. If we are using BackOffice then look for BackOffice license
  790. // instead of the service license.
  791. if (Flags & LLS_FLAG_SUITE_USE) {
  792. Service = BackOfficeRec;
  793. if (UseMapping)
  794. License = LicenseListFind(BackOfficeStr, pUser->Mapping->LicenseList, pUser->Mapping->LicenseListSize);
  795. else
  796. License = LicenseListFind(BackOfficeStr, pUser->LicenseList, pUser->LicenseListSize);
  797. } else {
  798. //
  799. // Not BackOffice - so look for normal service license
  800. //
  801. Service = Svc->Service;
  802. ASSERT(Service != NULL);
  803. //
  804. // Try to find a license for this family of products
  805. //
  806. if (UseMapping)
  807. License = LicenseListFind(Service->Family->Name, pUser->Mapping->LicenseList, pUser->Mapping->LicenseListSize);
  808. else
  809. License = LicenseListFind(Service->Family->Name, pUser->LicenseList, pUser->LicenseListSize);
  810. }
  811. //
  812. // Check if we couldn't find a license. If we didn't find it then we need
  813. // to create a new license for this.
  814. //
  815. if (License == NULL) {
  816. ULONG LicenseListSize;
  817. PUSER_LICENSE_RECORD *LicenseList;
  818. //
  819. // The license list to use depends if we are part of a mapping or not.
  820. //
  821. if (UseMapping) {
  822. LicenseListSize = pUser->Mapping->LicenseListSize;
  823. LicenseList = pUser->Mapping->LicenseList;
  824. } else {
  825. LicenseListSize = pUser->LicenseListSize;
  826. LicenseList = pUser->LicenseList;
  827. }
  828. //
  829. // Check if we need to add a license for BackOffice or just the service
  830. // itself.
  831. //
  832. if (Flags & LLS_FLAG_SUITE_USE)
  833. License = LicenseListAdd(BackOfficeRec->Family, &LicenseList, &LicenseListSize);
  834. else
  835. License = LicenseListAdd(Service->Family, &LicenseList, &LicenseListSize);
  836. //
  837. // Now update the couters in the parent record
  838. //
  839. if (UseMapping) {
  840. pUser->Mapping->LicenseListSize = LicenseListSize;
  841. pUser->Mapping->LicenseList = LicenseList;
  842. } else {
  843. pUser->LicenseListSize = LicenseListSize;
  844. pUser->LicenseList = LicenseList;
  845. }
  846. if (License != NULL)
  847. License->LicensesNeeded = NumLicenses;
  848. }
  849. //
  850. // We have either found an old license or added a new one, either way
  851. // License points to it.
  852. //
  853. if (License != NULL) {
  854. RtlAcquireResourceExclusive(&MasterServiceListLock, TRUE);
  855. //
  856. // if we have a license for this family already and the product
  857. // version >= current then we are okay, else need to get new license
  858. //
  859. if ( (License->Service != NULL) && (License->Service->Version >= Service->Version) ) {
  860. LicenseService = License->Service;
  861. } else {
  862. //
  863. // we have an old license for this family, but the version
  864. // isn't adequate, so we need to try and get a new license.
  865. // Walk the family tree looking for the licenses we
  866. // need.
  867. //
  868. LicenseService = Service;
  869. while ((LicenseService != NULL) && ( (LicenseService->LicensesUsed + NumLicenses) > LicenseService->Licenses) )
  870. if (LicenseService->next > 0)
  871. LicenseService = MasterServiceTable[LicenseService->next - 1];
  872. else
  873. LicenseService = NULL;
  874. //
  875. // if we couldn't find a license just use the old
  876. // service.
  877. if (LicenseService == NULL)
  878. LicenseService = Service;
  879. else {
  880. //
  881. // Need to clean up old stuff
  882. //
  883. if (License->Service != NULL) {
  884. //
  885. // If we actually free up any licenses then mark that we need
  886. // to rescan to allocate these freed licenses.
  887. //
  888. if ((NumLicenses - License->LicensesNeeded) > 0)
  889. ReScan = TRUE;
  890. License->Service->LicensesUsed -= NumLicenses;
  891. License->Service->LicensesClaimed -= (NumLicenses - License->LicensesNeeded);
  892. License->LicensesNeeded = NumLicenses;
  893. License->Service = NULL;
  894. }
  895. }
  896. }
  897. if (LicenseService != NULL) {
  898. ULONG Claimed = 0;
  899. //
  900. // If we switched services then adjust LicensesUsed
  901. //
  902. if (License->Service != LicenseService) {
  903. LicenseService->LicensesUsed += NumLicenses;
  904. if (License->Service != NULL) {
  905. License->Service->LicensesUsed -= NumLicenses;
  906. }
  907. }
  908. // Can only claim a # of licenses that we have
  909. if ( LicenseService->LicensesClaimed < LicenseService->Licenses) {
  910. Claimed = LicenseService->Licenses - LicenseService->LicensesClaimed;
  911. if (Claimed > License->LicensesNeeded)
  912. Claimed = License->LicensesNeeded;
  913. }
  914. LicenseService->LicensesClaimed += Claimed;
  915. License->Service = LicenseService;
  916. License->LicensesNeeded -= Claimed;
  917. if (License->LicensesNeeded != 0)
  918. License->Flags &= ~LLS_FLAG_LICENSED;
  919. else
  920. License->Flags |= LLS_FLAG_LICENSED;
  921. }
  922. RtlReleaseResource(&MasterServiceListLock);
  923. if (License->Flags & LLS_FLAG_LICENSED)
  924. Svc->Flags |= LLS_FLAG_LICENSED;
  925. else
  926. Svc->Flags &= ~LLS_FLAG_LICENSED;
  927. } else
  928. Svc->Flags &= ~LLS_FLAG_LICENSED;
  929. if ((Svc->License != License) && (License != NULL))
  930. License->RefCount++;
  931. Svc->License = License;
  932. if (ReScan)
  933. FamilyLicenseUpdate ( Service->Family );
  934. } // SvcLicenseUpdate
  935. /////////////////////////////////////////////////////////////////////////
  936. /////////////////////////////////////////////////////////////////////////
  937. //
  938. // Misc licensing Routines.
  939. //
  940. // BackOffice and Mappings have a special affect on LicenseUseage and so
  941. // there are a couple miscelanous routines to handle them.
  942. //
  943. // There are also two special cases that cause us to re-walk our lists to
  944. // fixup the licenses:
  945. //
  946. // 1. Sometimes when we add licenses we free up some we already had claimed.
  947. // Ex: Users of a LicenseGroup used 5 SQL 4.0 licenses but could only
  948. // claim 2 (there weren't enough). Later we add 5 SQL 5.0 licenses,
  949. // since we can use these to get into license compliance we free the
  950. // 2 previously claimed licenses and take the 5 SQL 5.0 licenses. Now
  951. // we need to re-walk the user table to try and apply the 2 freed
  952. // licenses.
  953. //
  954. // If we switch a user to BackOffice then it will also free up licenses
  955. // causing us to re-walk the table.
  956. //
  957. // 2. If we ever apply new licenses to a user in a mapping then we need
  958. // to re-walk all the other users in the mapping and update their
  959. // license compliance.
  960. //
  961. /////////////////////////////////////////////////////////////////////////
  962. VOID
  963. MappingLicenseUpdate (
  964. PMAPPING_RECORD Mapping,
  965. BOOL ReSynch
  966. )
  967. /*++
  968. Routine Description:
  969. Go through all user records for a given mapping and recalc license
  970. compliance.
  971. Arguments:
  972. Mapping - the Mapping to recalc licenses for.
  973. ReSync - If true all previous licenses are destroyed before the licenses
  974. are checked, else only services that currently don't have a
  975. license assignment are touched.
  976. Return Value:
  977. --*/
  978. {
  979. ULONG i, j;
  980. PUSER_LICENSE_RECORD License = NULL;
  981. PUSER_RECORD pUser;
  982. PSVC_RECORD SvcTable = NULL;
  983. BOOL BackOfficeCheck = FALSE;
  984. ULONG Claimed;
  985. BOOL Licensed = TRUE;
  986. #if DBG
  987. if (TraceFlags & TRACE_FUNCTION_TRACE)
  988. dprintf(TEXT("LLS TRACE: MappingLicenseUpdate\n"));
  989. #endif
  990. //
  991. // Run through all the users in the mapping - adjust their licenses
  992. // based on the licenses the mapping has...
  993. //
  994. RtlAcquireResourceExclusive(&MappingListLock, TRUE);
  995. for (i = 0; i < Mapping->LicenseListSize; i++)
  996. if (!(Mapping->LicenseList[i]->Flags & LLS_FLAG_LICENSED))
  997. Licensed = FALSE;
  998. if (Licensed)
  999. Mapping->Flags |= LLS_FLAG_LICENSED;
  1000. else
  1001. Mapping->Flags &= ~LLS_FLAG_LICENSED;
  1002. //
  1003. // If we want to resynch then blow away all old references
  1004. //
  1005. if (ReSynch)
  1006. for (i = 0; i < Mapping->LicenseListSize; i++)
  1007. Mapping->LicenseList[i]->RefCount = 0;
  1008. //
  1009. // Special handling if the Mapping uses BackOffice
  1010. //
  1011. if (Mapping->Flags & LLS_FLAG_SUITE_USE) {
  1012. License = LicenseListFind(BackOfficeStr, Mapping->LicenseList, Mapping->LicenseListSize);
  1013. //
  1014. // If there isn't one (can happen if all users were deleted from
  1015. // the mapping with BackOffice flag set). Then update everything.
  1016. //
  1017. if (License == NULL) {
  1018. License = LicenseListAdd(BackOfficeRec->Family, &Mapping->LicenseList, &Mapping->LicenseListSize);
  1019. ASSERT(License != NULL);
  1020. if (License != NULL) {
  1021. License->Service = BackOfficeRec;
  1022. // Can only claim a # of licenses that we have
  1023. if ( BackOfficeRec->LicensesClaimed < BackOfficeRec->Licenses) {
  1024. Claimed = BackOfficeRec->Licenses - BackOfficeRec->LicensesClaimed;
  1025. if (Claimed > Mapping->Licenses)
  1026. Claimed = Mapping->Licenses;
  1027. }
  1028. BackOfficeRec->LicensesUsed += Mapping->Licenses;
  1029. BackOfficeRec->LicensesClaimed += Claimed;
  1030. License->LicensesNeeded = Mapping->Licenses - Claimed;
  1031. Mapping->Flags |= LLS_FLAG_LICENSED;
  1032. if (License->LicensesNeeded > 0) {
  1033. License->Flags &= ~LLS_FLAG_LICENSED;
  1034. Mapping->Flags &= ~LLS_FLAG_LICENSED;
  1035. }
  1036. }
  1037. }
  1038. }
  1039. //
  1040. // Run through all the members in the Mapping and update their license
  1041. // Compliance.
  1042. //
  1043. for (i = 0; i < Mapping->NumMembers; i++) {
  1044. pUser = UserListFind(Mapping->Members[i]);
  1045. if ( (pUser != NULL) && (pUser->Mapping == Mapping) ) {
  1046. RtlEnterCriticalSection(&pUser->ServiceTableLock);
  1047. SvcTable = pUser->Services;
  1048. pUser->LicensedProducts = 0;
  1049. if (Mapping->Flags & LLS_FLAG_SUITE_USE) {
  1050. if (Mapping->Flags & LLS_FLAG_LICENSED) {
  1051. pUser->Flags |= LLS_FLAG_LICENSED;
  1052. pUser->LicensedProducts = pUser->ServiceTableSize;
  1053. } else
  1054. pUser->Flags &= ~LLS_FLAG_LICENSED;
  1055. //
  1056. // All Services and users are flagged as per BackOffice
  1057. //
  1058. for (j = 0; j < pUser->ServiceTableSize; j++) {
  1059. if (ReSynch)
  1060. SvcTable[j].License = NULL;
  1061. if (SvcTable[j].License == NULL) {
  1062. SvcTable[j].License = License;
  1063. License->RefCount++;
  1064. }
  1065. if (Mapping->Flags & LLS_FLAG_LICENSED) {
  1066. SvcTable[j].Flags |= LLS_FLAG_LICENSED;
  1067. } else
  1068. SvcTable[j].Flags &= ~LLS_FLAG_LICENSED;
  1069. }
  1070. } else {
  1071. BOOL Licensed = TRUE;
  1072. //
  1073. // Fixup all the service records
  1074. //
  1075. for (j = 0; j < pUser->ServiceTableSize; j++) {
  1076. if (ReSynch)
  1077. SvcTable[j].License = NULL;
  1078. if (SvcTable[j].License == NULL) {
  1079. SvcLicenseUpdate(pUser, &SvcTable[j]);
  1080. BackOfficeCheck = TRUE;
  1081. }
  1082. }
  1083. //
  1084. // Now run through the services again and see if this user is
  1085. // actually licenses for all the products.
  1086. //
  1087. pUser->LicensedProducts = 0;
  1088. for (j = 0; j < pUser->ServiceTableSize; j++)
  1089. if ( (SvcTable[j].License != NULL) && (SvcTable[j].License->Flags & LLS_FLAG_LICENSED) ) {
  1090. SvcTable[j].Flags |= LLS_FLAG_LICENSED;
  1091. pUser->LicensedProducts++;
  1092. } else {
  1093. SvcTable[j].Flags &= ~LLS_FLAG_LICENSED;
  1094. Licensed = FALSE;
  1095. }
  1096. if (Licensed)
  1097. pUser->Flags |= LLS_FLAG_LICENSED;
  1098. else
  1099. pUser->Flags &= ~LLS_FLAG_LICENSED;
  1100. }
  1101. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1102. }
  1103. }
  1104. RtlReleaseResource(&MappingListLock);
  1105. //
  1106. // Check if we need to re-check for BackOffice
  1107. //
  1108. if (BackOfficeCheck && (pUser != NULL))
  1109. UserBackOfficeCheck( pUser );
  1110. } // MappingLicenseUpdate
  1111. /////////////////////////////////////////////////////////////////////////
  1112. VOID
  1113. UserMappingAdd (
  1114. PMAPPING_RECORD Mapping,
  1115. PUSER_RECORD pUser
  1116. )
  1117. /*++
  1118. Routine Description:
  1119. Takes care of re-adjusting the licenses when we add a user to a mapping.
  1120. We need to free up any old licenses they have and point them to use
  1121. the licenses the mapping has.
  1122. Arguments:
  1123. Return Value:
  1124. --*/
  1125. {
  1126. ULONG i, j;
  1127. PUSER_LICENSE_RECORD License = NULL;
  1128. PSVC_RECORD SvcTable = NULL;
  1129. BOOL ReScan = FALSE;
  1130. #if DBG
  1131. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1132. dprintf(TEXT("LLS TRACE: UserMappingAdd\n"));
  1133. #endif
  1134. if ( (pUser == NULL) || (Mapping == NULL) )
  1135. return;
  1136. //
  1137. // Run though and clean up all old licenses
  1138. //
  1139. RtlEnterCriticalSection(&pUser->ServiceTableLock);
  1140. SvcListLicenseFree(pUser);
  1141. UserLicenseListFree(pUser);
  1142. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1143. pUser->Mapping = Mapping;
  1144. MappingLicenseUpdate(Mapping, FALSE);
  1145. } // UserMappingAdd
  1146. /////////////////////////////////////////////////////////////////////////
  1147. VOID
  1148. FamilyLicenseUpdate (
  1149. PMASTER_SERVICE_ROOT Family
  1150. )
  1151. /*++
  1152. Routine Description:
  1153. Used when licenses are freed-up or added to a given family of products.
  1154. Goes through the user list looking for out-of-license conditions for the
  1155. given family of products and distributes the new licenses.
  1156. Arguments:
  1157. Return Value:
  1158. --*/
  1159. {
  1160. ULONG NumLicenses = 1;
  1161. PUSER_LICENSE_RECORD License = NULL;
  1162. PMASTER_SERVICE_RECORD LicenseService = NULL;
  1163. ULONG i, j;
  1164. PUSER_RECORD pUser;
  1165. BOOL UseMapping = FALSE;
  1166. BOOL ReScan = TRUE;
  1167. #if DBG
  1168. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1169. dprintf(TEXT("LLS TRACE: FamilyLicenseUpdate\n"));
  1170. #endif
  1171. RtlAcquireResourceExclusive(&UserListLock, TRUE);
  1172. while (ReScan) {
  1173. //
  1174. // Walk user list in order of entry - adding any licenses
  1175. //
  1176. ReScan = FALSE;
  1177. i = 0;
  1178. while (i < UserListNumEntries) {
  1179. pUser = LLSGetElementGenericTable(&UserList, i);
  1180. if (pUser != NULL) {
  1181. //
  1182. // only worry about un-licensed users
  1183. //
  1184. if ( !(pUser->Flags & LLS_FLAG_LICENSED ) ) {
  1185. //
  1186. // Find the License?
  1187. //
  1188. RtlEnterCriticalSection(&pUser->ServiceTableLock);
  1189. if (pUser->Mapping != NULL) {
  1190. License = LicenseListFind(Family->Name, pUser->Mapping->LicenseList, pUser->Mapping->LicenseListSize);
  1191. NumLicenses = pUser->Mapping->Licenses;
  1192. } else {
  1193. License = LicenseListFind(Family->Name, pUser->LicenseList, pUser->LicenseListSize);
  1194. NumLicenses = 1;
  1195. }
  1196. //
  1197. // Make sure we need any extra licenses for this product
  1198. //
  1199. if ( (License != NULL) && (License->LicensesNeeded > 0) ) {
  1200. //
  1201. // We have found a user using this family of products in need
  1202. // of more licenses...
  1203. //
  1204. LicenseService = License->Service;
  1205. if (pUser->Mapping != NULL)
  1206. pUser->Mapping->Flags |= LLS_FLAG_UPDATE;
  1207. //
  1208. // Check if we can satisfy licenses using currently
  1209. // assigned service
  1210. //
  1211. if ((LicenseService->Licenses - LicenseService->LicensesClaimed) >= License->LicensesNeeded) {
  1212. LicenseService->LicensesClaimed += License->LicensesNeeded;
  1213. License->LicensesNeeded = 0;
  1214. } else {
  1215. //
  1216. // See if any other service will satisfy it...
  1217. //
  1218. while ((LicenseService != NULL) && ((LicenseService->Licenses - LicenseService->LicensesClaimed) < NumLicenses ) )
  1219. if (LicenseService->next > 0)
  1220. LicenseService = MasterServiceTable[LicenseService->next - 1];
  1221. else
  1222. LicenseService = NULL;
  1223. //
  1224. // check if we found a service to satisfy licensing needs
  1225. //
  1226. if (LicenseService != NULL) {
  1227. //
  1228. // Free up any stuff - since we are freeing licenses
  1229. // we need to re-scan.
  1230. //
  1231. ReScan = TRUE;
  1232. License->Service->LicensesUsed -= NumLicenses;
  1233. License->Service->LicensesClaimed -= (NumLicenses - License->LicensesNeeded);
  1234. //
  1235. // Now do new stuff
  1236. //
  1237. License->Service = LicenseService;
  1238. License->Service->LicensesUsed += NumLicenses;
  1239. License->Service->LicensesClaimed += NumLicenses;
  1240. License->LicensesNeeded = 0;
  1241. } else {
  1242. //
  1243. // Eat any unclaimed licenses
  1244. //
  1245. LicenseService = License->Service;
  1246. if (LicenseService->Licenses > LicenseService->LicensesClaimed) {
  1247. License->LicensesNeeded -= (LicenseService->Licenses - LicenseService->LicensesClaimed);
  1248. LicenseService->LicensesClaimed = LicenseService->Licenses;
  1249. }
  1250. }
  1251. }
  1252. //
  1253. // Check if we got into license
  1254. //
  1255. if (License->LicensesNeeded == 0) {
  1256. BOOL Licensed = TRUE;
  1257. License->Flags |= LLS_FLAG_LICENSED;
  1258. //
  1259. // this license is fulfilled so scan product list and
  1260. // adjust flags on any product using this license.
  1261. //
  1262. for (j = 0; j < pUser->ServiceTableSize; j++) {
  1263. if (pUser->Services[j].License == License) {
  1264. pUser->Services[j].Flags |= LLS_FLAG_LICENSED;
  1265. } else
  1266. if (!(pUser->Services[j].Flags & LLS_FLAG_LICENSED))
  1267. Licensed = FALSE;
  1268. }
  1269. //
  1270. // Recalc how many products are licensed
  1271. //
  1272. pUser->LicensedProducts = 0;
  1273. for (j = 0; j < pUser->ServiceTableSize; j++) {
  1274. if (pUser->Services[j].Flags & LLS_FLAG_LICENSED)
  1275. pUser->LicensedProducts++;
  1276. }
  1277. if (Licensed)
  1278. pUser->Flags |= LLS_FLAG_LICENSED;
  1279. }
  1280. }
  1281. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1282. }
  1283. }
  1284. i++;
  1285. }
  1286. }
  1287. //
  1288. // If this license is for BackOffice, we have applied any licenses to
  1289. // anything set to use BackOffice. If there are still licenses left
  1290. // then see if any users should be auto-switched to BackOffice.
  1291. //
  1292. // if (Family == BackOfficeRec->Family) {
  1293. i = 0;
  1294. while ( (BackOfficeRec->LicensesClaimed < BackOfficeRec->Licenses) && (i < UserListNumEntries) ) {
  1295. pUser = LLSGetElementGenericTable(&UserList, i);
  1296. if (pUser != NULL)
  1297. UserBackOfficeCheck(pUser);
  1298. i++;
  1299. }
  1300. // }
  1301. //
  1302. // Run through mapping and re-adjust any that need it.
  1303. //
  1304. RtlAcquireResourceExclusive(&MappingListLock, TRUE);
  1305. for (i = 0; i < MappingListSize; i++) {
  1306. if (MappingList[i]->Flags & LLS_FLAG_UPDATE) {
  1307. MappingList[i]->Flags &= ~LLS_FLAG_UPDATE;
  1308. MappingLicenseUpdate( MappingList[i], FALSE );
  1309. }
  1310. }
  1311. RtlReleaseResource(&MappingListLock);
  1312. RtlReleaseResource(&UserListLock);
  1313. } // FamilyLicenseUpdate
  1314. /////////////////////////////////////////////////////////////////////////
  1315. VOID
  1316. UserListLicenseDelete(
  1317. PMASTER_SERVICE_RECORD Service,
  1318. LONG Quantity
  1319. )
  1320. /*++
  1321. Routine Description:
  1322. This is used when licenses are deleted. It must walk the user-list in
  1323. the reverse order they were entered (since licenses are applied in a
  1324. FIFO manner they are removed in a LIFO manner) and delete the required
  1325. number of licenses from those consumed.
  1326. Arguments:
  1327. Return Value:
  1328. --*/
  1329. {
  1330. LONG Licenses;
  1331. ULONG i, j;
  1332. PUSER_RECORD pUser;
  1333. PSVC_RECORD pService;
  1334. ULONG NumLicenses = 1;
  1335. PUSER_LICENSE_RECORD License = NULL;
  1336. BOOL UseMapping = FALSE;
  1337. LONG Claimed;
  1338. #if DBG
  1339. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1340. dprintf(TEXT("LLS TRACE: UserListLicenseDelete\n"));
  1341. #endif
  1342. RtlAcquireResourceExclusive(&UserListLock, TRUE);
  1343. Licenses = 0 - Quantity;
  1344. //
  1345. // Walk user list in opposite order of entry - removing licenses
  1346. //
  1347. i = UserListNumEntries - 1;
  1348. while (((LONG)i >= 0) && (Licenses > 0)) {
  1349. pUser = LLSGetElementGenericTable(&UserList, i);
  1350. if (pUser != NULL) {
  1351. NumLicenses = 1;
  1352. UseMapping = FALSE;
  1353. //
  1354. // If we are a mapping then we may use more then one license
  1355. //
  1356. if (pUser->Mapping != NULL) {
  1357. NumLicenses = pUser->Mapping->Licenses;
  1358. UseMapping = TRUE;
  1359. }
  1360. //
  1361. // Try to find a license for this family of products
  1362. //
  1363. if (UseMapping)
  1364. License = LicenseListFind(Service->Family->Name, pUser->Mapping->LicenseList, pUser->Mapping->LicenseListSize);
  1365. else
  1366. License = LicenseListFind(Service->Family->Name, pUser->LicenseList, pUser->LicenseListSize);
  1367. if (License != NULL) {
  1368. //
  1369. // Check if same as product we adjusted
  1370. //
  1371. if (License->Service == Service) {
  1372. //
  1373. // Can only release how many we took
  1374. //
  1375. Claimed = NumLicenses - License->LicensesNeeded;
  1376. if (Claimed > 0) {
  1377. if (Claimed > Licenses) {
  1378. License->LicensesNeeded += Licenses;
  1379. License->Service->LicensesClaimed -= Licenses;
  1380. Licenses = 0;
  1381. } else {
  1382. License->LicensesNeeded = NumLicenses;
  1383. License->Service->LicensesClaimed -= Claimed;
  1384. Licenses -= Claimed;
  1385. }
  1386. License->Flags &= ~LLS_FLAG_LICENSED;
  1387. //
  1388. // Flag any mapping that we need to recalc uses in the
  1389. // mapping
  1390. //
  1391. if (UseMapping)
  1392. pUser->Mapping->Flags |= LLS_FLAG_UPDATE;
  1393. //
  1394. // Scan product list and adjust flags on any
  1395. // product using this license.
  1396. //
  1397. RtlEnterCriticalSection(&pUser->ServiceTableLock);
  1398. for (j = 0; j < pUser->ServiceTableSize; j++)
  1399. if (pUser->Services[j].License == License)
  1400. pUser->Services[j].Flags &= ~LLS_FLAG_LICENSED;
  1401. //
  1402. // Recalc how many products are licensed
  1403. //
  1404. pUser->LicensedProducts = 0;
  1405. for (j = 0; j < pUser->ServiceTableSize; j++) {
  1406. if (pUser->Services[j].Flags & LLS_FLAG_LICENSED)
  1407. pUser->LicensedProducts++;
  1408. }
  1409. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1410. pUser->Flags &= ~LLS_FLAG_LICENSED;
  1411. }
  1412. }
  1413. }
  1414. }
  1415. i--;
  1416. }
  1417. //
  1418. // Run through mapping and re-adjust any that need it.
  1419. //
  1420. RtlAcquireResourceExclusive(&MappingListLock, TRUE);
  1421. for (i = 0; i < MappingListSize; i++) {
  1422. if (MappingList[i]->Flags & LLS_FLAG_UPDATE) {
  1423. MappingList[i]->Flags &= ~LLS_FLAG_UPDATE;
  1424. MappingLicenseUpdate( MappingList[i], FALSE );
  1425. }
  1426. }
  1427. RtlReleaseResource(&MappingListLock);
  1428. RtlReleaseResource(&UserListLock);
  1429. } // UserListLicenseDelete
  1430. /////////////////////////////////////////////////////////////////////////
  1431. VOID
  1432. UserBackOfficeCheck (
  1433. PUSER_RECORD pUser
  1434. )
  1435. /*++
  1436. Routine Description:
  1437. Checks if the user should switch to BackOffice, and if so - does so. If
  1438. we switch to BackOffice then we need to free up any old licenes the
  1439. user may be using and claim a BackOffice License.
  1440. Note: We will only switch to BackOffice if there are enough BackOffice
  1441. licenses available to satisfy our needs.
  1442. Arguments:
  1443. Return Value:
  1444. --*/
  1445. {
  1446. DWORD Flags;
  1447. ULONG i;
  1448. ULONG LicenseListSize;
  1449. ULONG NumLicenses = 1;
  1450. PSVC_RECORD SvcTable = NULL;
  1451. PUSER_LICENSE_RECORD *LicenseList = NULL;
  1452. PUSER_LICENSE_RECORD License = NULL;
  1453. #if DBG
  1454. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1455. dprintf(TEXT("LLS TRACE: UserBackOfficeCheck\n"));
  1456. #endif
  1457. RtlEnterCriticalSection(&pUser->ServiceTableLock);
  1458. if (pUser->Mapping != NULL) {
  1459. Flags = pUser->Mapping->Flags;
  1460. LicenseListSize = pUser->Mapping->LicenseListSize;
  1461. LicenseList = pUser->Mapping->LicenseList;
  1462. NumLicenses = pUser->Mapping->Licenses;
  1463. } else {
  1464. Flags = pUser->Flags;
  1465. LicenseListSize = pUser->LicenseListSize;
  1466. LicenseList = pUser->LicenseList;
  1467. }
  1468. //
  1469. // If we are already using BackOffice - get out
  1470. //
  1471. if (Flags & LLS_FLAG_SUITE_USE) {
  1472. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1473. return;
  1474. }
  1475. if ( Flags & LLS_FLAG_SUITE_AUTO )
  1476. //
  1477. // if we aren't licensed, or the # services == auto switch threshold
  1478. // then switch to using BackOffice
  1479. //
  1480. if ((!(Flags & LLS_FLAG_LICENSED)) || ((LicenseListSize + 1) >= BACKOFFICE_SWITCH) ) {
  1481. //
  1482. // Make sure we have licenses for this
  1483. //
  1484. RtlAcquireResourceExclusive(&MasterServiceListLock, TRUE);
  1485. if ( BackOfficeRec->Licenses >= (NumLicenses + BackOfficeRec->LicensesClaimed) ) {
  1486. //
  1487. // Free up the old licenses - temporarily claim the BackOffice
  1488. // licenses so somebody else won't.
  1489. //
  1490. BackOfficeRec->LicensesClaimed += NumLicenses;
  1491. UserLicenseListFree(pUser);
  1492. BackOfficeRec->LicensesClaimed -= NumLicenses;
  1493. //
  1494. // UserLicenseListFree might have assigned us a license in
  1495. // the rescan if we are part of a mapping so check this.
  1496. //
  1497. if (pUser->Mapping != NULL)
  1498. Flags = pUser->Mapping->Flags;
  1499. else
  1500. Flags = pUser->Flags;
  1501. //
  1502. // If we are already using BackOffice - get out
  1503. //
  1504. if (Flags & LLS_FLAG_SUITE_USE) {
  1505. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1506. RtlReleaseResource(&MasterServiceListLock);
  1507. return;
  1508. }
  1509. //
  1510. // And if part of a mapping free those up
  1511. //
  1512. if (pUser->Mapping != NULL)
  1513. MappingLicenseListFree(pUser->Mapping);
  1514. //
  1515. // Now add the BackOffice License
  1516. //
  1517. if (pUser->Mapping != NULL) {
  1518. pUser->Mapping->LicenseList = NULL;
  1519. pUser->Mapping->LicenseListSize = 0;
  1520. License = LicenseListAdd(BackOfficeRec->Family, &pUser->Mapping->LicenseList, &pUser->Mapping->LicenseListSize);
  1521. LicenseList = pUser->Mapping->LicenseList;
  1522. LicenseListSize = pUser->Mapping->LicenseListSize;
  1523. } else {
  1524. pUser->LicenseList = NULL;
  1525. pUser->LicenseListSize = 0;
  1526. License = LicenseListAdd(BackOfficeRec->Family, &pUser->LicenseList, &pUser->LicenseListSize);
  1527. LicenseList = pUser->LicenseList;
  1528. LicenseListSize = pUser->LicenseListSize;
  1529. }
  1530. ASSERT(License != NULL);
  1531. if (License != NULL)
  1532. License->Service = BackOfficeRec;
  1533. //
  1534. // if mapping adjust mapping records then go through all users and
  1535. // adjust them
  1536. //
  1537. if (pUser->Mapping != NULL) {
  1538. pUser->Mapping->Flags |= LLS_FLAG_SUITE_USE;
  1539. pUser->Mapping->Flags |= LLS_FLAG_LICENSED;
  1540. BackOfficeRec->LicensesUsed += NumLicenses;
  1541. BackOfficeRec->LicensesClaimed += NumLicenses;
  1542. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1543. RtlReleaseResource(&MasterServiceListLock);
  1544. MappingLicenseUpdate(pUser->Mapping, TRUE);
  1545. return;
  1546. } else {
  1547. pUser->Flags |= LLS_FLAG_SUITE_USE;
  1548. pUser->Flags |= LLS_FLAG_LICENSED;
  1549. pUser->LicensedProducts = pUser->ServiceTableSize;
  1550. BackOfficeRec->LicensesUsed += NumLicenses;
  1551. BackOfficeRec->LicensesClaimed += NumLicenses;
  1552. //
  1553. // Run through products & licenses adjusting licenses
  1554. //
  1555. SvcTable = pUser->Services;
  1556. for (i = 0; i < pUser->ServiceTableSize; i++) {
  1557. SvcTable[i].Flags |= LLS_FLAG_LICENSED;
  1558. SvcTable[i].License = License;
  1559. SvcTable[i].License->RefCount++;
  1560. }
  1561. }
  1562. }
  1563. RtlReleaseResource(&MasterServiceListLock);
  1564. }
  1565. RtlLeaveCriticalSection(&pUser->ServiceTableLock);
  1566. } // UserBackOfficeCheck
  1567. /////////////////////////////////////////////////////////////////////////
  1568. /////////////////////////////////////////////////////////////////////////
  1569. //
  1570. // Utility routines for managing the user and SID lists - used mostly
  1571. // by the splay table routines.
  1572. /////////////////////////////////////////////////////////////////////////
  1573. LLS_GENERIC_COMPARE_RESULTS
  1574. SidListCompare (
  1575. struct _LLS_GENERIC_TABLE *Table,
  1576. PVOID FirstStruct,
  1577. PVOID SecondStruct
  1578. )
  1579. /*++
  1580. Routine Description:
  1581. Arguments:
  1582. Table -
  1583. FirstStruct -
  1584. SecondStruct -
  1585. Return Value:
  1586. --*/
  1587. {
  1588. PUSER_RECORD UseRec1, UseRec2;
  1589. int ret;
  1590. if ((FirstStruct == NULL) || (SecondStruct == NULL))
  1591. return LLSGenericEqual;
  1592. UseRec1 = (PUSER_RECORD) FirstStruct;
  1593. UseRec2 = (PUSER_RECORD) SecondStruct;
  1594. if (UseRec1->IDSize == UseRec2->IDSize) {
  1595. ret = memcmp((PVOID) UseRec1->UserID, (PVOID) UseRec2->UserID, UseRec1->IDSize);
  1596. if (ret < 0)
  1597. return LLSGenericLessThan;
  1598. else if (ret > 0)
  1599. return LLSGenericGreaterThan;
  1600. else
  1601. return LLSGenericEqual;
  1602. } else
  1603. //
  1604. // Not same size, so just compare length
  1605. //
  1606. if (UseRec1->IDSize > UseRec2->IDSize)
  1607. return LLSGenericGreaterThan;
  1608. else
  1609. return LLSGenericLessThan;
  1610. } // SidListCompare
  1611. /////////////////////////////////////////////////////////////////////////
  1612. LLS_GENERIC_COMPARE_RESULTS
  1613. UserListCompare (
  1614. struct _LLS_GENERIC_TABLE *Table,
  1615. PVOID FirstStruct,
  1616. PVOID SecondStruct
  1617. )
  1618. /*++
  1619. Routine Description:
  1620. Arguments:
  1621. Table -
  1622. FirstStruct -
  1623. SecondStruct -
  1624. Return Value:
  1625. --*/
  1626. {
  1627. PUSER_RECORD UseRec1, UseRec2;
  1628. int ret;
  1629. if ((FirstStruct == NULL) || (SecondStruct == NULL))
  1630. return LLSGenericEqual;
  1631. UseRec1 = (PUSER_RECORD) FirstStruct;
  1632. UseRec2 = (PUSER_RECORD) SecondStruct;
  1633. ret = lstrcmpi((LPTSTR) UseRec1->UserID, (LPTSTR) UseRec2->UserID);
  1634. if (ret < 0)
  1635. return LLSGenericLessThan;
  1636. else if (ret > 0)
  1637. return LLSGenericGreaterThan;
  1638. else
  1639. return LLSGenericEqual;
  1640. } // UserListCompare
  1641. /////////////////////////////////////////////////////////////////////////
  1642. PVOID
  1643. UserListAlloc (
  1644. struct _LLS_GENERIC_TABLE *Table,
  1645. CLONG ByteSize
  1646. )
  1647. /*++
  1648. Routine Description:
  1649. Arguments:
  1650. Table -
  1651. ByteSize -
  1652. Return Value:
  1653. --*/
  1654. {
  1655. return (PVOID) LocalAlloc(LPTR, ByteSize);
  1656. } // UserListAlloc
  1657. /////////////////////////////////////////////////////////////////////////
  1658. VOID
  1659. UserListFree (
  1660. struct _LLS_GENERIC_TABLE *Table,
  1661. PVOID Buffer
  1662. )
  1663. /*++
  1664. Routine Description:
  1665. Arguments:
  1666. Table -
  1667. Buffer -
  1668. Return Value:
  1669. --*/
  1670. {
  1671. PUSER_RECORD UserRec;
  1672. if (Buffer == NULL)
  1673. return;
  1674. UserRec = (PUSER_RECORD) Buffer;
  1675. LocalFree(UserRec->UserID);
  1676. LocalFree(UserRec);
  1677. } // UserListFree
  1678. /////////////////////////////////////////////////////////////////////////
  1679. PUSER_RECORD
  1680. UserListFind(
  1681. LPTSTR UserName
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. Arguments:
  1686. Return Value:
  1687. --*/
  1688. {
  1689. USER_RECORD UserRec;
  1690. PUSER_RECORD pUserRec;
  1691. #if DBG
  1692. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1693. dprintf(TEXT("LLS TRACE: UserListFind\n"));
  1694. #endif
  1695. UserRec.UserID = (PVOID) UserName;
  1696. RtlEnterCriticalSection(&GenTableLock);
  1697. pUserRec = (PUSER_RECORD) LLSLookupElementGenericTable(&UserList, &UserRec);
  1698. RtlLeaveCriticalSection(&GenTableLock);
  1699. return pUserRec;
  1700. } // UserListFind
  1701. /////////////////////////////////////////////////////////////////////////
  1702. /////////////////////////////////////////////////////////////////////////
  1703. /////////////////////////////////////////////////////////////////////////
  1704. /////////////////////////////////////////////////////////////////////////
  1705. VOID
  1706. UserListAdd(
  1707. PMASTER_SERVICE_RECORD Service,
  1708. ULONG DataType,
  1709. ULONG DataLength,
  1710. PVOID Data,
  1711. ULONG AccessCount,
  1712. DWORD LastAccess,
  1713. DWORD FlagsParam
  1714. )
  1715. /*++
  1716. Routine Description:
  1717. Routine called by the Add cache routine to update the user and/or SID
  1718. lists with the new service information.
  1719. Arguments:
  1720. Return Value:
  1721. --*/
  1722. {
  1723. USER_RECORD UserRec;
  1724. PUSER_RECORD pUserRec;
  1725. BOOLEAN Added;
  1726. PSVC_RECORD pService;
  1727. PSVC_RECORD SvcTable = NULL;
  1728. PLLS_GENERIC_TABLE pTable = NULL;
  1729. PRTL_RESOURCE pLock = NULL;
  1730. BOOL SIDSwitch = FALSE;
  1731. BOOL UserLock = FALSE;
  1732. PMAPPING_RECORD pMap = NULL;
  1733. ULONG ProductLicenses, ProductLicensesUsed, i;
  1734. BOOL SwitchToBackOffice = FALSE;
  1735. NTSTATUS status;
  1736. PSVC_RECORD pSvcTableTmp;
  1737. #if DBG
  1738. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1739. dprintf(TEXT("LLS TRACE: UserListAdd\n"));
  1740. #endif
  1741. // only 2 bits are used
  1742. ASSERT( FlagsParam == ( FlagsParam & ( LLS_FLAG_SUITE_USE | LLS_FLAG_SUITE_AUTO ) ) );
  1743. //
  1744. // Set up lock and table pointers based on if data is SID or username...
  1745. //
  1746. UserRec.UserID = Data;
  1747. if (DataType == DATA_TYPE_USERNAME) {
  1748. pTable = &UserList;
  1749. pLock = &UserListLock;
  1750. } else if (DataType == DATA_TYPE_SID) {
  1751. pTable = &SidList;
  1752. pLock = &SidListLock;
  1753. }
  1754. if (pTable == NULL)
  1755. return;
  1756. //
  1757. // The generic table package copies the record so the record is
  1758. // temporary, but since we store the string as a pointer the pointer is
  1759. // copied but the actual memory that is pointed to is kept around
  1760. // permenantly.
  1761. //
  1762. // We have already allocated memory for the Data
  1763. //
  1764. UserRec.UserID = Data;
  1765. UserRec.IDSize = DataLength;
  1766. UserRec.Flags = FlagsParam;
  1767. UserRec.LicensedProducts = 0;
  1768. UserRec.LastReplicated = 0;
  1769. UserRec.ServiceTableSize = 0;
  1770. UserRec.Services = NULL;
  1771. UserRec.Mapping = NULL;
  1772. UserRec.LicenseListSize = 0;
  1773. UserRec.LicenseList = NULL;
  1774. //
  1775. // Assume that the user is licensed - we will blast it if they aren't
  1776. // down below.
  1777. //
  1778. UserRec.Flags |= LLS_FLAG_LICENSED;
  1779. //
  1780. // Need to update list so get exclusive access. First get Add/Enum lock
  1781. // so we don't block reads if doing an enum.
  1782. //
  1783. RtlAcquireResourceExclusive(pLock, TRUE);
  1784. pUserRec = (PUSER_RECORD) LLSInsertElementGenericTable(pTable, (PVOID) &UserRec, sizeof(USER_RECORD), &Added);
  1785. if (pUserRec == NULL) {
  1786. ASSERT(FALSE);
  1787. LocalFree(UserRec.UserID);
  1788. RtlReleaseResource(pLock);
  1789. return;
  1790. }
  1791. pUserRec->Flags &= ~LLS_FLAG_DELETED;
  1792. // if auto suite is ever turned off, it's gone for good
  1793. if ( ! ( FlagsParam & LLS_FLAG_SUITE_AUTO ) )
  1794. {
  1795. // set suite use to be that specified in the function parameters
  1796. pUserRec->Flags &= ~LLS_FLAG_SUITE_AUTO;
  1797. pUserRec->Flags |= ( FlagsParam & LLS_FLAG_SUITE_USE );
  1798. }
  1799. //
  1800. // If for some reason the record is already there then we need to
  1801. // clean-up the name we allocated.
  1802. //
  1803. if (Added == FALSE) {
  1804. LocalFree(UserRec.UserID);
  1805. //
  1806. // If this is a SID then check the SID record to find the corresponding
  1807. // USER_RECORD (it better be there) and update that instead.. Note: We
  1808. // kludge this by storing the pointer to the user table in the
  1809. // LastReplicated field.
  1810. //
  1811. if ((DataType == DATA_TYPE_SID) && (pUserRec->LastReplicated != 0)) {
  1812. //
  1813. // Switch data as approp.
  1814. //
  1815. SIDSwitch = TRUE;
  1816. }
  1817. } else {
  1818. //
  1819. // Do this here so when we release to READ access another thread
  1820. // won't AV when trying to get access to it.
  1821. //
  1822. status = RtlInitializeCriticalSection(&pUserRec->ServiceTableLock);
  1823. if (!NT_SUCCESS(status))
  1824. {
  1825. // We're out of memory. Fail to add the user
  1826. return;
  1827. }
  1828. if (DataType == DATA_TYPE_USERNAME) {
  1829. pMap = MappingListUserFind(UserRec.UserID);
  1830. pUserRec->Mapping = pMap;
  1831. UserListNumEntries++;
  1832. } else
  1833. SidListNumEntries++;
  1834. }
  1835. //
  1836. // If this is a SID, and we haven't gotten an appropriate user-rec
  1837. // then try to de-reference this and get the appropriate user-rec.
  1838. //
  1839. if ((DataType == DATA_TYPE_SID) && (pUserRec->LastReplicated == 0)) {
  1840. TCHAR UserName[MAX_USERNAME_LENGTH + 1];
  1841. TCHAR DomainName[MAX_DOMAINNAME_LENGTH + 1];
  1842. TCHAR FullName[MAX_USERNAME_LENGTH + MAX_DOMAINNAME_LENGTH + 2];
  1843. SID_NAME_USE snu;
  1844. PUSER_RECORD pUserRec2;
  1845. DWORD unSize, dnSize;
  1846. unSize = sizeof(UserName);
  1847. dnSize = sizeof(DomainName);
  1848. if (LookupAccountSid(NULL, (PSID) Data, UserName, &unSize, DomainName, &dnSize, &snu)) {
  1849. //
  1850. // Okay, de-referenced the SID, so go get the user-rec, but pre-pend
  1851. // domain first...
  1852. //
  1853. lstrcpy(FullName, DomainName);
  1854. lstrcat(FullName, TEXT("\\"));
  1855. lstrcat(FullName, UserName);
  1856. UserRec.UserID = FullName;
  1857. UserRec.IDSize = (lstrlen(FullName) + 1) * sizeof(TCHAR);
  1858. //
  1859. // Get locks, we will try shared first.
  1860. //
  1861. RtlAcquireResourceExclusive(&UserListLock, TRUE);
  1862. UserLock = TRUE;
  1863. SIDSwitch = TRUE;
  1864. RtlEnterCriticalSection(&GenTableLock);
  1865. pUserRec2 = (PUSER_RECORD) LLSLookupElementGenericTable(&UserList, &UserRec);
  1866. RtlLeaveCriticalSection(&GenTableLock);
  1867. if (pUserRec2 != NULL) {
  1868. //
  1869. // Tarnation! we found it - so use it.
  1870. //
  1871. pUserRec->LastReplicated = (ULONG_PTR) pUserRec2;
  1872. } else {
  1873. //
  1874. // Dang it all... It ain't in the dern table, so we're gonna
  1875. // put it there. First need to alloc perm storage for UserID
  1876. //
  1877. UserRec.UserID = LocalAlloc(LPTR, UserRec.IDSize);
  1878. if (UserRec.UserID != NULL) {
  1879. lstrcpy((LPTSTR) UserRec.UserID, FullName);
  1880. //
  1881. // Need to update list so get exclusive access. First get
  1882. // Add/Enum lock so we don't block reads if doing an enum.
  1883. //
  1884. pUserRec2 = (PUSER_RECORD) LLSInsertElementGenericTable(&UserList, (PVOID) &UserRec, sizeof(USER_RECORD), &Added);
  1885. }
  1886. //
  1887. // If we couldn't insert it then seomthing is wrong, clean up
  1888. // and exit.
  1889. //
  1890. if (pUserRec2 == NULL) {
  1891. ASSERT(FALSE);
  1892. if (UserRec.UserID != NULL)
  1893. LocalFree(UserRec.UserID);
  1894. RtlReleaseResource(pLock);
  1895. RtlReleaseResource(&UserListLock);
  1896. return;
  1897. }
  1898. //
  1899. // Update SID USER_REC pointer (LastReplicated) and then finally
  1900. // free up the SID lock
  1901. //
  1902. pUserRec->LastReplicated = (ULONG_PTR) pUserRec2;
  1903. if (Added == TRUE) {
  1904. //
  1905. // Do this here so when we release to READ access another
  1906. // thread won't AV when trying to get access to it.
  1907. //
  1908. status = RtlInitializeCriticalSection(&pUserRec2->ServiceTableLock);
  1909. if (!NT_SUCCESS(status))
  1910. {
  1911. // We're out of memory. Fail to add the user
  1912. return;
  1913. }
  1914. pMap = MappingListUserFind(UserRec.UserID);
  1915. pUserRec2->Mapping = pMap;
  1916. UserListNumEntries++;
  1917. }
  1918. }
  1919. //
  1920. // We have found or added a USER_REC for the SID which pUserRec2
  1921. // points to. Now we need to switch locks and tables.
  1922. //
  1923. }
  1924. }
  1925. //
  1926. // If we need to munge from SID to User tables, then do so...
  1927. //
  1928. if (SIDSwitch) {
  1929. //
  1930. // Switch data as approp.
  1931. //
  1932. pUserRec = (PUSER_RECORD) pUserRec->LastReplicated;
  1933. DataType = DATA_TYPE_USERNAME;
  1934. //
  1935. // Release locks on SID Table
  1936. //
  1937. RtlReleaseResource(pLock);
  1938. //
  1939. // Now switch locks to User Table
  1940. //
  1941. pTable = &UserList;
  1942. pLock = &UserListLock;
  1943. if (!UserLock)
  1944. RtlAcquireResourceExclusive(pLock, TRUE);
  1945. }
  1946. //
  1947. // At this point we have either found the old record, or added a new
  1948. // one. In either case pUserRec points to the correct record.
  1949. //
  1950. if (pUserRec != NULL) {
  1951. //
  1952. // Check Service table to make sure our service is already there
  1953. //
  1954. RtlEnterCriticalSection(&pUserRec->ServiceTableLock);
  1955. pService = SvcListFind( Service->Name, pUserRec->Services, pUserRec->ServiceTableSize );
  1956. if (pService != NULL) {
  1957. //
  1958. // Found entry in service table so just increment count
  1959. //
  1960. if (pService->AccessCount + AccessCount < MAX_ACCESS_COUNT)
  1961. pService->AccessCount += AccessCount;
  1962. else
  1963. pService->AccessCount = MAX_ACCESS_COUNT;
  1964. pService->LastAccess = LastAccess;
  1965. } else {
  1966. //
  1967. // Need to add more entries to service table (or create it...)
  1968. //
  1969. if (pUserRec->Services == NULL)
  1970. pSvcTableTmp = (PSVC_RECORD) LocalAlloc( LPTR, sizeof(SVC_RECORD));
  1971. else
  1972. pSvcTableTmp = (PSVC_RECORD) LocalReAlloc( pUserRec->Services, sizeof(SVC_RECORD) * (pUserRec->ServiceTableSize + 1), LHND);
  1973. if (pSvcTableTmp != NULL) {
  1974. SvcTable = pSvcTableTmp;
  1975. } else {
  1976. // why is this a void function?
  1977. ASSERT(FALSE);
  1978. return;
  1979. }
  1980. pUserRec->Services = SvcTable;
  1981. if (SvcTable != NULL) {
  1982. DWORD Flags;
  1983. if (pUserRec->Mapping != NULL)
  1984. Flags = pUserRec->Mapping->Flags;
  1985. else
  1986. Flags = pUserRec->Flags;
  1987. SvcTable[pUserRec->ServiceTableSize].Service = Service;
  1988. SvcTable[pUserRec->ServiceTableSize].LastAccess = LastAccess;
  1989. //
  1990. // Update AccessCount field, but make sure we don't roll over
  1991. //
  1992. if (AccessCount < MAX_ACCESS_COUNT)
  1993. SvcTable[pUserRec->ServiceTableSize].AccessCount = AccessCount;
  1994. else
  1995. SvcTable[pUserRec->ServiceTableSize].AccessCount = MAX_ACCESS_COUNT;
  1996. SvcTable[pUserRec->ServiceTableSize].Flags = LLS_FLAG_LICENSED;
  1997. //
  1998. // Now update the actual license info
  1999. //
  2000. SvcLicenseUpdate(pUserRec, &SvcTable[pUserRec->ServiceTableSize]);
  2001. pUserRec->ServiceTableSize += 1;
  2002. if (SvcTable[pUserRec->ServiceTableSize - 1].Flags & LLS_FLAG_LICENSED)
  2003. pUserRec->LicensedProducts++;
  2004. //
  2005. // If the added product isn't licensed then update user flag
  2006. //
  2007. if (IsMaster && !(SvcTable[pUserRec->ServiceTableSize - 1].Flags & LLS_FLAG_LICENSED) )
  2008. pUserRec->Flags &= ~LLS_FLAG_LICENSED;
  2009. // Now that it is all setup - sort the table (so search will work)
  2010. qsort((void *) pUserRec->Services, (size_t) pUserRec->ServiceTableSize, sizeof(SVC_RECORD), SvcListCompare);
  2011. UserBackOfficeCheck ( pUserRec );
  2012. }
  2013. }
  2014. RtlLeaveCriticalSection(&pUserRec->ServiceTableLock);
  2015. }
  2016. RtlReleaseResource(pLock);
  2017. } // UserListAdd
  2018. /////////////////////////////////////////////////////////////////////////
  2019. /////////////////////////////////////////////////////////////////////////
  2020. //
  2021. // The AddCache routines are a queue of User Identifiers (Username or
  2022. // SID's) and the service being accessed. Records are dequeued by a
  2023. // background thread and handed off to the UserListAdd function.
  2024. /////////////////////////////////////////////////////////////////////////
  2025. VOID
  2026. AddCacheManager (
  2027. IN PVOID ThreadParameter
  2028. )
  2029. /*++
  2030. Routine Description:
  2031. Arguments:
  2032. ThreadParameter - Not used.
  2033. Return Value:
  2034. This thread never exits.
  2035. --*/
  2036. {
  2037. NTSTATUS Status;
  2038. PADD_CACHE pAdd;
  2039. //
  2040. // Loop forever waiting to be given the opportunity to serve the
  2041. // greater good.
  2042. //
  2043. for ( ; ; ) {
  2044. //
  2045. // Wait to be notified that there is work to be done
  2046. //
  2047. Status = NtWaitForSingleObject( LLSAddCacheEvent, TRUE, NULL );
  2048. //
  2049. // Take an item from the add cache.
  2050. //
  2051. RtlEnterCriticalSection(&AddCacheLock);
  2052. while (AddCache != NULL) {
  2053. pAdd = AddCache;
  2054. AddCache = AddCache->prev;
  2055. AddCacheSize--;
  2056. RtlLeaveCriticalSection(&AddCacheLock);
  2057. if (pAdd != NULL) {
  2058. UserListAdd(pAdd->Service, pAdd->DataType, pAdd->DataLength, pAdd->Data, pAdd->AccessCount, pAdd->LastAccess, pAdd->Flags);
  2059. LocalFree(pAdd);
  2060. }
  2061. Sleep(0);
  2062. //
  2063. // Need to re-enter critical section to check in the while loop
  2064. RtlEnterCriticalSection(&AddCacheLock);
  2065. }
  2066. RtlLeaveCriticalSection(&AddCacheLock);
  2067. }
  2068. } // AddCacheManager
  2069. /////////////////////////////////////////////////////////////////////////
  2070. /////////////////////////////////////////////////////////////////////////
  2071. /////////////////////////////////////////////////////////////////////////
  2072. /////////////////////////////////////////////////////////////////////////
  2073. NTSTATUS
  2074. UserListInit()
  2075. /*++
  2076. Routine Description:
  2077. Arguments:
  2078. Return Value:
  2079. --*/
  2080. {
  2081. NTSTATUS Status;
  2082. HANDLE Thread;
  2083. DOMAIN_CONTROLLER_INFO * pDCInfo = NULL;
  2084. //
  2085. // Initialize the generic table.
  2086. //
  2087. LLSInitializeGenericTable ( &UserList,
  2088. UserListCompare,
  2089. UserListAlloc,
  2090. UserListFree,
  2091. (PVOID) TEXT("LLS Table") );
  2092. Status = RtlInitializeCriticalSection(&GenTableLock);
  2093. if (!NT_SUCCESS(Status))
  2094. return Status;
  2095. try
  2096. {
  2097. RtlInitializeResource(&UserListLock);
  2098. } except(EXCEPTION_EXECUTE_HANDLER ) {
  2099. Status = GetExceptionCode();
  2100. }
  2101. if (!NT_SUCCESS(Status))
  2102. return Status;
  2103. //
  2104. // Initialize the SID table.
  2105. //
  2106. LLSInitializeGenericTable ( &SidList,
  2107. SidListCompare,
  2108. UserListAlloc,
  2109. UserListFree,
  2110. (PVOID) TEXT("LLS SID Table") );
  2111. try
  2112. {
  2113. RtlInitializeResource(&SidListLock);
  2114. } except(EXCEPTION_EXECUTE_HANDLER ) {
  2115. Status = GetExceptionCode();
  2116. }
  2117. if (!NT_SUCCESS(Status))
  2118. return Status;
  2119. //
  2120. // Now our add cache
  2121. //
  2122. Status = RtlInitializeCriticalSection(&AddCacheLock);
  2123. if (!NT_SUCCESS(Status))
  2124. return Status;
  2125. //
  2126. // Get MyDomain
  2127. //
  2128. GetDCInfo(MAX_COMPUTERNAME_LENGTH + 2,
  2129. MyDomain,
  2130. &pDCInfo);
  2131. lstrcat(MyDomain, TEXT("\\"));
  2132. MyDomainSize = (lstrlen(MyDomain) + 1) * sizeof(TCHAR);
  2133. if (pDCInfo != NULL) {
  2134. NetApiBufferFree(pDCInfo);
  2135. }
  2136. //
  2137. // Create the Add Cache Management event
  2138. //
  2139. Status = NtCreateEvent(
  2140. &LLSAddCacheEvent,
  2141. EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE,
  2142. NULL,
  2143. SynchronizationEvent,
  2144. FALSE
  2145. );
  2146. if (!NT_SUCCESS(Status))
  2147. return Status;
  2148. //
  2149. // Create the Add Cache management thread
  2150. //
  2151. Thread = CreateThread(
  2152. NULL,
  2153. 0L,
  2154. (LPTHREAD_START_ROUTINE) AddCacheManager,
  2155. 0L,
  2156. 0L,
  2157. NULL
  2158. );
  2159. if (NULL != Thread)
  2160. CloseHandle(Thread);
  2161. LastUsedTime = DateSystemGet();
  2162. return STATUS_SUCCESS;
  2163. } // UserListInit
  2164. /////////////////////////////////////////////////////////////////////////
  2165. VOID
  2166. UserListUpdate(
  2167. ULONG DataType,
  2168. PVOID Data,
  2169. PSERVICE_RECORD Service
  2170. )
  2171. /*++
  2172. Routine Description:
  2173. Actual start of the perseat license code. Given a SID or UserName find
  2174. the record in the appropriate table and check the given service. If the
  2175. service is already there then the info is updated, if it isn't there then
  2176. the record is put onto the add cache queue for background processing.
  2177. Arguments:
  2178. Return Value:
  2179. --*/
  2180. {
  2181. USER_RECORD UserRec;
  2182. PUSER_RECORD pUserRec;
  2183. BOOLEAN Added;
  2184. ULONG DataLength;
  2185. PSVC_RECORD pService;
  2186. PSVC_RECORD SvcTable = NULL;
  2187. PLLS_GENERIC_TABLE pTable = NULL;
  2188. PRTL_RESOURCE pLock = NULL;
  2189. PADD_CACHE pAdd = NULL;
  2190. NTSTATUS NtStatus;
  2191. BOOL ToAddCache = FALSE;
  2192. BOOL FullName = TRUE;
  2193. LPTSTR pName;
  2194. #if DBG
  2195. if (TraceFlags & TRACE_FUNCTION_TRACE)
  2196. dprintf(TEXT("LLS TRACE: UserListUpdate\n"));
  2197. #endif
  2198. //
  2199. // Setup table and lock pointers based if Data is UserName or SID
  2200. //
  2201. UserRec.UserID = Data;
  2202. if (DataType == DATA_TYPE_USERNAME) {
  2203. pTable = &UserList;
  2204. pLock = &UserListLock;
  2205. DataLength = (lstrlen((LPWSTR) Data) + 1) * sizeof(TCHAR);
  2206. } else if (DataType == DATA_TYPE_SID) {
  2207. pTable = &SidList;
  2208. pLock = &SidListLock;
  2209. DataLength = RtlLengthSid((PSID) Data);
  2210. }
  2211. if (pTable == NULL)
  2212. return;
  2213. //
  2214. // Searching so don't need exclusive access
  2215. //
  2216. RtlAcquireResourceExclusive(pLock, TRUE);
  2217. RtlEnterCriticalSection(&GenTableLock);
  2218. pUserRec = (PUSER_RECORD) LLSLookupElementGenericTable(pTable, &UserRec);
  2219. RtlLeaveCriticalSection(&GenTableLock);
  2220. if (pUserRec == NULL)
  2221. ToAddCache = TRUE;
  2222. else {
  2223. //
  2224. // pUserRec now points to the record we must update.
  2225. //
  2226. // Check Service table to make sure our service is already there
  2227. //
  2228. pUserRec->Flags &= ~LLS_FLAG_DELETED;
  2229. RtlEnterCriticalSection(&pUserRec->ServiceTableLock);
  2230. pService = SvcListFind( Service->DisplayName, pUserRec->Services, pUserRec->ServiceTableSize );
  2231. if (pService == NULL)
  2232. ToAddCache = TRUE;
  2233. else {
  2234. //
  2235. // Found entry in service table so just increment count
  2236. //
  2237. pService->AccessCount += 1;
  2238. pService->LastAccess = LastUsedTime;
  2239. }
  2240. RtlLeaveCriticalSection(&pUserRec->ServiceTableLock);
  2241. }
  2242. RtlReleaseResource(pLock);
  2243. if (ToAddCache) {
  2244. //
  2245. // Couldn't find the specific user/service, so put it on the Add Cache.
  2246. // First alloc memory for the name and Add Cache record.
  2247. //
  2248. pAdd = LocalAlloc(LPTR, sizeof(ADD_CACHE));
  2249. if (pAdd == NULL) {
  2250. ASSERT(FALSE);
  2251. return;
  2252. }
  2253. if (DataType == DATA_TYPE_USERNAME) {
  2254. FullName = FALSE;
  2255. pName = (LPTSTR) Data;
  2256. //
  2257. // Make sure first char isn't backslash, if not then look for
  2258. // backslash as domain-name. If first char is backslash then get
  2259. // rid of it.
  2260. //
  2261. if (*pName != TEXT('\\'))
  2262. while ((*pName != TEXT('\0')) && !FullName) {
  2263. if (*pName == TEXT('\\'))
  2264. FullName = TRUE;
  2265. pName++;
  2266. }
  2267. else
  2268. ((LPTSTR) Data)++;
  2269. }
  2270. //
  2271. // If we don't have a fully qualified Domain\Username, then tack the
  2272. // Domain name onto the name.
  2273. //
  2274. if (!FullName) {
  2275. UserRec.UserID = LocalAlloc( LPTR, DataLength + MyDomainSize);
  2276. if (UserRec.UserID == NULL) {
  2277. ASSERT(FALSE);
  2278. LocalFree(pAdd);
  2279. return;
  2280. }
  2281. pAdd->Data = UserRec.UserID;
  2282. lstrcpy((LPTSTR) pAdd->Data, MyDomain);
  2283. lstrcat((LPTSTR) pAdd->Data, (LPTSTR) Data);
  2284. pAdd->DataLength = DataLength + MyDomainSize;
  2285. } else {
  2286. UserRec.UserID = LocalAlloc( LPTR, DataLength);
  2287. if (UserRec.UserID == NULL) {
  2288. ASSERT(FALSE);
  2289. LocalFree(pAdd);
  2290. return;
  2291. }
  2292. pAdd->Data = UserRec.UserID;
  2293. memcpy(pAdd->Data, Data, DataLength);
  2294. pAdd->DataLength = DataLength;
  2295. }
  2296. //
  2297. // copy over all the data fields into the newly created Add Cache
  2298. // record.
  2299. //
  2300. pAdd->DataType = DataType;
  2301. pAdd->Service = Service->MasterService;
  2302. pAdd->AccessCount = 1;
  2303. pAdd->LastAccess = LastUsedTime;
  2304. pAdd->Flags = LLS_FLAG_SUITE_AUTO;
  2305. //
  2306. // Now update the actual Add Cache
  2307. //
  2308. RtlEnterCriticalSection(&AddCacheLock);
  2309. pAdd->prev = AddCache;
  2310. AddCache = pAdd;
  2311. AddCacheSize++;
  2312. RtlLeaveCriticalSection(&AddCacheLock);
  2313. //
  2314. // Now must signal the event so we can pull off the new record.
  2315. //
  2316. NtStatus = NtSetEvent( LLSAddCacheEvent, NULL );
  2317. ASSERT(NT_SUCCESS(NtStatus));
  2318. }
  2319. } // UserListUpdate
  2320. #if DBG
  2321. /////////////////////////////////////////////////////////////////////////
  2322. VOID
  2323. AddCacheDebugDump ( )
  2324. /*++
  2325. Routine Description:
  2326. Arguments:
  2327. Return Value:
  2328. --*/
  2329. {
  2330. NTSTATUS Status;
  2331. PADD_CACHE pAdd;
  2332. UNICODE_STRING UString;
  2333. ULONG i = 0;
  2334. RtlEnterCriticalSection(&AddCacheLock);
  2335. dprintf(TEXT("Add Cache Dump. Record Size: %4lu # Entries: %lu\n"), sizeof(ADD_CACHE), AddCacheSize);
  2336. pAdd = AddCache;
  2337. while (pAdd != NULL) {
  2338. if (pAdd->DataType == DATA_TYPE_USERNAME)
  2339. dprintf(TEXT("%4lu) Svc: %s User: [%2lu] %s\n"),
  2340. ++i,
  2341. pAdd->Service,
  2342. pAdd->DataLength,
  2343. pAdd->Data);
  2344. else if (pAdd->DataType == DATA_TYPE_SID) {
  2345. Status = RtlConvertSidToUnicodeString(&UString, (PSID) pAdd->Data, TRUE);
  2346. dprintf(TEXT("%4lu) Svc: %s User: [%2lu] %s\n"),
  2347. ++i,
  2348. pAdd->Service,
  2349. pAdd->DataLength,
  2350. UString.Buffer);
  2351. RtlFreeUnicodeString(&UString);
  2352. }
  2353. pAdd = pAdd->prev;
  2354. }
  2355. RtlLeaveCriticalSection(&AddCacheLock);
  2356. } // AddCacheDebugDump
  2357. /////////////////////////////////////////////////////////////////////////
  2358. VOID
  2359. UserListDebugDump( )
  2360. /*++
  2361. Routine Description:
  2362. Arguments:
  2363. Return Value:
  2364. --*/
  2365. {
  2366. ULONG i = 0;
  2367. PUSER_RECORD UserRec = NULL;
  2368. PVOID RestartKey = NULL;
  2369. RtlAcquireResourceShared(&UserListLock, TRUE);
  2370. dprintf(TEXT("User List Dump. Record Size: %4lu # Entries: %lu\n"), sizeof(USER_RECORD), UserListNumEntries);
  2371. UserRec = (PUSER_RECORD) LLSEnumerateGenericTableWithoutSplaying(&UserList, (VOID **) &RestartKey);
  2372. while (UserRec != NULL) {
  2373. //
  2374. // Dump info for found user-rec
  2375. //
  2376. if (UserRec->Mapping != NULL)
  2377. dprintf(TEXT("%4lu) Repl: %s LT: %2lu Svc: %2lu Flags: 0x%4lX Map: %s User: [%2lu] %s\n"),
  2378. ++i,
  2379. TimeToString((ULONG)(UserRec->LastReplicated)),
  2380. UserRec->LicenseListSize,
  2381. UserRec->ServiceTableSize,
  2382. UserRec->Flags,
  2383. UserRec->Mapping->Name,
  2384. UserRec->IDSize,
  2385. (LPTSTR) UserRec->UserID );
  2386. else
  2387. dprintf(TEXT("%4lu) Repl: %s LT: %2lu Svc: %2lu Flags: 0x%4lX User: [%2lu] %s\n"),
  2388. ++i,
  2389. TimeToString((ULONG)(UserRec->LastReplicated)),
  2390. UserRec->LicenseListSize,
  2391. UserRec->ServiceTableSize,
  2392. UserRec->Flags,
  2393. UserRec->IDSize,
  2394. (LPTSTR) UserRec->UserID );
  2395. // Get next record
  2396. UserRec = (PUSER_RECORD) LLSEnumerateGenericTableWithoutSplaying(&UserList, (VOID **) &RestartKey);
  2397. }
  2398. RtlReleaseResource(&UserListLock);
  2399. } // UserListDebugDump
  2400. /////////////////////////////////////////////////////////////////////////
  2401. VOID
  2402. UserListDebugInfoDump(
  2403. PVOID Data
  2404. )
  2405. /*++
  2406. Routine Description:
  2407. Arguments:
  2408. Return Value:
  2409. --*/
  2410. {
  2411. USER_RECORD UserRec;
  2412. PUSER_RECORD pUserRec;
  2413. PSVC_RECORD SvcTable = NULL;
  2414. ULONG i;
  2415. RtlAcquireResourceExclusive(&UserListLock, TRUE);
  2416. dprintf(TEXT("User List Info. Record Size: %4lu # Entries: %lu\n"), sizeof(USER_RECORD), UserListNumEntries);
  2417. //
  2418. // Only dump user if one was specified.
  2419. //
  2420. if (lstrlen((LPWSTR) Data) > 0) {
  2421. UserRec.UserID = Data;
  2422. RtlEnterCriticalSection(&GenTableLock);
  2423. pUserRec = (PUSER_RECORD) LLSLookupElementGenericTable(&UserList, &UserRec);
  2424. RtlLeaveCriticalSection(&GenTableLock);
  2425. if (pUserRec != NULL) {
  2426. //
  2427. // Dump info for found user-rec
  2428. //
  2429. if (pUserRec->Mapping != NULL)
  2430. dprintf(TEXT(" Repl: %s LT: %2lu Svc: %2lu Flags: 0x%4lX Map: %s User: [%2lu] %s\n"),
  2431. TimeToString((ULONG)(pUserRec->LastReplicated)),
  2432. pUserRec->LicenseListSize,
  2433. pUserRec->ServiceTableSize,
  2434. pUserRec->Flags,
  2435. pUserRec->Mapping->Name,
  2436. pUserRec->IDSize,
  2437. (LPTSTR) pUserRec->UserID );
  2438. else
  2439. dprintf(TEXT(" Repl: %s LT: %2lu Svc: %2lu Flags: 0x%4lX User: [%2lu] %s\n"),
  2440. TimeToString((ULONG)(pUserRec->LastReplicated)),
  2441. pUserRec->LicenseListSize,
  2442. pUserRec->ServiceTableSize,
  2443. pUserRec->Flags,
  2444. pUserRec->IDSize,
  2445. (LPTSTR) pUserRec->UserID );
  2446. //
  2447. // Now do the service table - but get critical section first.
  2448. //
  2449. RtlEnterCriticalSection(&pUserRec->ServiceTableLock);
  2450. SvcTable = pUserRec->Services;
  2451. if (pUserRec->ServiceTableSize != 0)
  2452. dprintf(TEXT("\nServiceTable\n"));
  2453. for (i = 0; i < pUserRec->ServiceTableSize; i++)
  2454. dprintf( TEXT(" AC: %4lu LA: %s Flags: 0x%4lX Svc: %s\n"),
  2455. SvcTable[i].AccessCount,
  2456. TimeToString(SvcTable[i].LastAccess),
  2457. SvcTable[i].Flags,
  2458. SvcTable[i].Service->Name );
  2459. if (pUserRec->LicenseListSize != 0)
  2460. dprintf(TEXT("\nLicenseTable\n"));
  2461. for (i = 0; i < pUserRec->LicenseListSize; i++)
  2462. dprintf( TEXT(" Flags: 0x%4lX Ref: %2lu LN: %2lu Svc: %s\n"),
  2463. pUserRec->LicenseList[i]->Flags,
  2464. pUserRec->LicenseList[i]->RefCount,
  2465. pUserRec->LicenseList[i]->LicensesNeeded,
  2466. pUserRec->LicenseList[i]->Service->Name );
  2467. RtlLeaveCriticalSection(&pUserRec->ServiceTableLock);
  2468. } else
  2469. dprintf(TEXT("User Not Found: %s\n"), (LPWSTR) Data);
  2470. }
  2471. RtlReleaseResource(&UserListLock);
  2472. } // UserListDebugInfoDump
  2473. /////////////////////////////////////////////////////////////////////////
  2474. VOID
  2475. UserListDebugFlush( )
  2476. /*++
  2477. Routine Description:
  2478. Arguments:
  2479. Return Value:
  2480. --*/
  2481. {
  2482. USER_RECORD UserRec;
  2483. //
  2484. // Searching so don't need exclusive access
  2485. //
  2486. RtlAcquireResourceExclusive(&UserListLock, TRUE);
  2487. RtlEnterCriticalSection(&GenTableLock);
  2488. LLSLookupElementGenericTable(&UserList, &UserRec);
  2489. RtlLeaveCriticalSection(&GenTableLock);
  2490. RtlReleaseResource(&UserListLock);
  2491. } // UserListDebugFlush
  2492. /////////////////////////////////////////////////////////////////////////
  2493. VOID
  2494. SidListDebugDump( )
  2495. /*++
  2496. Routine Description:
  2497. Arguments:
  2498. Return Value:
  2499. --*/
  2500. {
  2501. ULONG i = 0;
  2502. PUSER_RECORD UserRec = NULL;
  2503. UNICODE_STRING UString;
  2504. NTSTATUS NtStatus;
  2505. PVOID RestartKey = NULL;
  2506. RtlAcquireResourceShared(&SidListLock, TRUE);
  2507. dprintf(TEXT("SID List Dump. Record Size: %4lu # Entries: %lu\n"), sizeof(USER_RECORD), SidListNumEntries);
  2508. UserRec = (PUSER_RECORD) LLSEnumerateGenericTableWithoutSplaying(&SidList, (VOID **) &RestartKey);
  2509. while (UserRec != NULL) {
  2510. //
  2511. // Dump info for found user-rec
  2512. //
  2513. NtStatus = RtlConvertSidToUnicodeString(&UString, (PSID) UserRec->UserID, TRUE);
  2514. dprintf(TEXT("%4lu) User-Rec: 0x%lX Svc: %2lu User: [%2lu] %s\n"),
  2515. ++i,
  2516. UserRec->LastReplicated,
  2517. UserRec->ServiceTableSize,
  2518. UserRec->IDSize,
  2519. UString.Buffer );
  2520. RtlFreeUnicodeString(&UString);
  2521. // Get next record
  2522. UserRec = (PUSER_RECORD) LLSEnumerateGenericTableWithoutSplaying(&SidList, (VOID **) &RestartKey);
  2523. }
  2524. RtlReleaseResource(&SidListLock);
  2525. } // SidListDebugDump
  2526. /////////////////////////////////////////////////////////////////////////
  2527. VOID
  2528. SidListDebugInfoDump(
  2529. PVOID Data
  2530. )
  2531. /*++
  2532. Routine Description:
  2533. Arguments:
  2534. Return Value:
  2535. --*/
  2536. {
  2537. USER_RECORD UserRec;
  2538. PUSER_RECORD pUserRec;
  2539. PSVC_RECORD SvcTable = NULL;
  2540. ULONG i;
  2541. RtlAcquireResourceExclusive(&SidListLock, TRUE);
  2542. dprintf(TEXT("SID List Info. Record Size: %4lu # Entries: %lu\n"), sizeof(USER_RECORD), SidListNumEntries);
  2543. //
  2544. // Only dump user if one was specified.
  2545. //
  2546. if (lstrlen((LPWSTR) Data) > 0) {
  2547. UserRec.UserID = Data;
  2548. RtlEnterCriticalSection(&GenTableLock);
  2549. pUserRec = (PUSER_RECORD) LLSLookupElementGenericTable(&SidList, &UserRec);
  2550. RtlLeaveCriticalSection(&GenTableLock);
  2551. if (pUserRec != NULL) {
  2552. //
  2553. // Dump info for found user-rec
  2554. //
  2555. dprintf(TEXT(" User-Rec: 0x%lX Svc: %2lu User: [%2lu] %s\n"),
  2556. pUserRec->LastReplicated,
  2557. pUserRec->ServiceTableSize,
  2558. pUserRec->IDSize,
  2559. (LPTSTR) pUserRec->UserID );
  2560. // No Service Table for SID's
  2561. } else
  2562. dprintf(TEXT("SID Not Found: %s\n"), (LPWSTR) Data);
  2563. }
  2564. RtlReleaseResource(&SidListLock);
  2565. } // SidListDebugInfoDump
  2566. /////////////////////////////////////////////////////////////////////////
  2567. VOID
  2568. SidListDebugFlush( )
  2569. /*++
  2570. Routine Description:
  2571. Arguments:
  2572. Return Value:
  2573. --*/
  2574. {
  2575. USER_RECORD UserRec;
  2576. //
  2577. // Searching so don't need exclusive access
  2578. //
  2579. RtlAcquireResourceExclusive(&SidListLock, TRUE);
  2580. RtlReleaseResource(&SidListLock);
  2581. } // SidListDebugFlush
  2582. #endif