Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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