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.

1825 lines
47 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. registry.c
  5. Abstract:
  6. Registry reading routines for License Server. Can Scan the registry
  7. for all License Service entries, or for a specific service.
  8. Author:
  9. Arthur Hanson (arth) 07-Dec-1994
  10. Revision History:
  11. Jeff Parham (jeffparh) 05-Dec-1995
  12. o Removed unnecessary RegConnect() to local server.
  13. o Added secure service list. This list tracks the products that
  14. require "secure" license certificates for all licenses; i.e., the
  15. products that do not accept the 3.51 Honesty method of "enter the
  16. number of license you purchased."
  17. o Added routine to update the concurrent limit value in the registry
  18. to accurately reflect the connection limit of secure products.
  19. --*/
  20. #include <stdlib.h>
  21. #include <nt.h>
  22. #include <ntrtl.h>
  23. #include <nturtl.h>
  24. #include <windows.h>
  25. #include <rpc.h>
  26. #include <rpcndr.h>
  27. #include <dsgetdc.h>
  28. #include "llsapi.h"
  29. #include "debug.h"
  30. #include "llssrv.h"
  31. #include "registry.h"
  32. #include "ntlsapi.h"
  33. #include "mapping.h"
  34. #include "msvctbl.h"
  35. #include "svctbl.h"
  36. #include "purchase.h"
  37. #include "perseat.h"
  38. #include "server.h"
  39. #include "llsutil.h"
  40. #include <strsafe.h> //include last
  41. // #define API_TRACE 1
  42. #define NUM_MAPPING_ENTRIES 2
  43. const LPTSTR NameMappingTable2[] = {
  44. TEXT("Microsoft SQL Server"),
  45. TEXT("Microsoft SNA Server")
  46. }; // NameMappingTable2
  47. ULONG NumFilePrintEntries = 0;
  48. LPTSTR *FilePrintTable = NULL;
  49. #define KEY_NAME_SIZE 512
  50. HANDLE LLSRegistryEvent;
  51. ULONG LocalServiceListSize = 0;
  52. PLOCAL_SERVICE_RECORD *LocalServiceList = NULL;
  53. RTL_RESOURCE LocalServiceListLock;
  54. static ULONG SecureServiceListSize = 0;
  55. static LPTSTR * SecureServiceList = NULL;
  56. static ULONG SecureServiceBufferSize = 0; // in bytes!
  57. static TCHAR * SecureServiceBuffer = NULL;
  58. /////////////////////////////////////////////////////////////////////////
  59. VOID
  60. ConfigInfoRegistryInit(
  61. DWORD * pReplicationType,
  62. DWORD * pReplicationTime,
  63. DWORD * pLogLevel,
  64. BOOL * pPerServerCapacityWarning
  65. )
  66. {
  67. HKEY hKey2 = NULL;
  68. DWORD dwType, dwSize;
  69. static BOOL ReportedError = FALSE;
  70. static const TCHAR RegKeyText[] = TEXT("System\\CurrentControlSet\\Services\\LicenseService\\Parameters");
  71. LONG Status;
  72. DWORD ReplicationType, ReplicationTime;
  73. DWORD LogLevel;
  74. DWORD DisableCapacityWarning;
  75. ReplicationType = ReplicationTime = LogLevel = 0;
  76. //
  77. // Create registry key-name we are looking for
  78. //
  79. if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_READ, &hKey2)) == ERROR_SUCCESS)
  80. {
  81. dwSize = sizeof(ReplicationType);
  82. Status = RegQueryValueEx(hKey2, TEXT("ReplicationType"), NULL, &dwType, (LPBYTE) &ReplicationType, &dwSize);
  83. if (Status == ERROR_SUCCESS)
  84. {
  85. dwSize = sizeof(ReplicationTime);
  86. Status = RegQueryValueEx(hKey2, TEXT("ReplicationTime"), NULL, &dwType, (LPBYTE) &ReplicationTime, &dwSize);
  87. if (Status == ERROR_SUCCESS)
  88. {
  89. ASSERT(NULL != pReplicationType);
  90. ASSERT(NULL != pReplicationTime);
  91. *pReplicationType = ReplicationType;
  92. *pReplicationTime = ReplicationTime;
  93. }
  94. else
  95. {
  96. if (!ReportedError)
  97. {
  98. ReportedError = TRUE;
  99. #ifdef DEBUG
  100. dprintf(TEXT("LLS: (WARNING) No registry parm for ReplicationTime\n"));
  101. #endif
  102. }
  103. }
  104. }
  105. else
  106. {
  107. if (!ReportedError)
  108. {
  109. ReportedError = TRUE;
  110. #ifdef DEBUG
  111. dprintf(TEXT("LLS: (WARNING) No registry parm for ReplicationType\n"));
  112. #endif
  113. }
  114. }
  115. // LogLevel (REG_DWORD): determines how much info is dumped to the EventLog.
  116. // Higher values imply more logging. Default: 0.
  117. dwSize = sizeof( LogLevel );
  118. Status = RegQueryValueEx( hKey2, TEXT("LogLevel"), NULL, &dwType, (LPBYTE) &LogLevel, &dwSize);
  119. ASSERT(NULL != pLogLevel);
  120. if ( ERROR_SUCCESS == Status )
  121. *pLogLevel = LogLevel;
  122. else
  123. *pLogLevel = 0;
  124. //
  125. // Read the per server capacity warning value. A warning when the per
  126. // server license usage nears 90-95% of the total number of licenses.
  127. // A non-zero registry value disables the per server capacity warning
  128. // mechanism.
  129. //
  130. // It is not likely this value wll be present. Default to warn.
  131. //
  132. dwSize = sizeof( DisableCapacityWarning );
  133. Status = RegQueryValueEx( hKey2,
  134. TEXT("DisableCapacityWarning"),
  135. NULL,
  136. &dwType,
  137. (LPBYTE)&DisableCapacityWarning,
  138. &dwSize);
  139. if ( ERROR_SUCCESS == Status && DisableCapacityWarning ) {
  140. ASSERT(NULL != pPerServerCapacityWarning);
  141. *pPerServerCapacityWarning = FALSE;
  142. }
  143. else {
  144. *pPerServerCapacityWarning = TRUE;
  145. }
  146. // ProductData (REG_BINARY): an encrypted buffer of concatenated service names
  147. // that determine which services need to have secure certificates
  148. // for license entry
  149. Status = RegQueryValueEx( hKey2, TEXT("ProductData"), NULL, &dwType, NULL, &dwSize );
  150. if ( ERROR_SUCCESS == Status )
  151. {
  152. TCHAR * NewSecureServiceBuffer = NULL;
  153. LPTSTR * NewSecureServiceList = NULL;
  154. ULONG NewSecureServiceListSize = 0;
  155. ULONG NewSecureServiceBufferSize;
  156. NewSecureServiceBufferSize = dwSize;
  157. NewSecureServiceBuffer = LocalAlloc( LMEM_FIXED, NewSecureServiceBufferSize );
  158. if ( NULL != NewSecureServiceBuffer )
  159. {
  160. Status = RegQueryValueEx( hKey2, TEXT("ProductData"), NULL, &dwType, (LPBYTE) NewSecureServiceBuffer, &dwSize);
  161. if ( ERROR_SUCCESS == Status )
  162. {
  163. Status = DeBlock( NewSecureServiceBuffer, dwSize );
  164. if ( ( STATUS_SUCCESS == Status )
  165. && ( ( NULL == SecureServiceBuffer )
  166. || ( memcmp( NewSecureServiceBuffer, SecureServiceBuffer, dwSize ) ) ) )
  167. {
  168. // process changes in secure product list
  169. DWORD i;
  170. DWORD ProductNdx;
  171. NewSecureServiceListSize = 0;
  172. // count number of product names contained in the buffer
  173. for ( i=0; ( i < dwSize ) && ( NewSecureServiceBuffer[i] != TEXT( '\0' ) ); i++ )
  174. {
  175. // skip to beginning of next product name
  176. for ( ; ( i < dwSize ) && ( NewSecureServiceBuffer[i] != TEXT( '\0' ) ); i++ );
  177. i++;
  178. if ( i * sizeof( TCHAR) < dwSize )
  179. {
  180. // properly null-terminated product name
  181. NewSecureServiceListSize++;
  182. }
  183. }
  184. if ( 0 != NewSecureServiceListSize )
  185. {
  186. NewSecureServiceList = LocalAlloc( LMEM_FIXED, sizeof( LPTSTR ) * NewSecureServiceListSize );
  187. if ( NULL != NewSecureServiceList )
  188. {
  189. for ( i = ProductNdx = 0; ProductNdx < NewSecureServiceListSize; ProductNdx++ )
  190. {
  191. NewSecureServiceList[ ProductNdx ] = &NewSecureServiceBuffer[i];
  192. // skip to beginning of next product name
  193. for ( ; NewSecureServiceBuffer[i] != TEXT( '\0' ); i++ );
  194. i++;
  195. }
  196. // new secure product list read successfully; use it
  197. if ( NULL != SecureServiceBuffer )
  198. {
  199. LocalFree( SecureServiceBuffer );
  200. }
  201. if ( NULL != SecureServiceList )
  202. {
  203. LocalFree( SecureServiceList );
  204. }
  205. SecureServiceBuffer = NewSecureServiceBuffer;
  206. SecureServiceList = NewSecureServiceList;
  207. SecureServiceListSize = NewSecureServiceListSize;
  208. SecureServiceBufferSize = NewSecureServiceBufferSize;
  209. }
  210. }
  211. }
  212. }
  213. }
  214. // free buffers if we aren't using them anymore
  215. if ( ( NULL != NewSecureServiceList )
  216. && ( SecureServiceList != NewSecureServiceList ) )
  217. {
  218. LocalFree( NewSecureServiceList );
  219. }
  220. if ( ( NULL != NewSecureServiceBuffer )
  221. && ( SecureServiceBuffer != NewSecureServiceBuffer ) )
  222. {
  223. LocalFree( NewSecureServiceBuffer );
  224. }
  225. }
  226. RegCloseKey(hKey2);
  227. }
  228. } // ConfigInfoRegistryInit
  229. /////////////////////////////////////////////////////////////////////////
  230. NTSTATUS
  231. FilePrintTableInit(
  232. )
  233. /*++
  234. Routine Description:
  235. Builds up the FilePrint mapping table by enumerating the keys in the
  236. registry init'd by the various install programs.
  237. Arguments:
  238. Return Value:
  239. None.
  240. --*/
  241. {
  242. HKEY hKey2;
  243. static const TCHAR RegKeyText[] = TEXT("System\\CurrentControlSet\\Services\\LicenseService\\FilePrint");
  244. static TCHAR KeyText[KEY_NAME_SIZE], ClassText[KEY_NAME_SIZE];
  245. NTSTATUS Status;
  246. DWORD index = 0;
  247. DWORD KeySize, ClassSize, NumKeys, NumValue, MaxKey, MaxClass, MaxValue, MaxValueData, MaxSD;
  248. FILETIME LastWrite;
  249. LPTSTR *pFilePrintTableTmp;
  250. HRESULT hr;
  251. size_t cch;
  252. #if DBG
  253. if (TraceFlags & TRACE_FUNCTION_TRACE)
  254. dprintf(TEXT("LLS TRACE: FilePrintTableInit\n"));
  255. #endif
  256. //
  257. // Create registry key-name we are looking for
  258. //
  259. if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_READ, &hKey2)) == ERROR_SUCCESS) {
  260. //
  261. // Find out how many sub-keys there are to intialize our table size.
  262. // The table can still grow dynamically, this just makes having to
  263. // realloc it a rare occurance.
  264. //
  265. ClassSize = KEY_NAME_SIZE;
  266. Status = RegQueryInfoKey(hKey2, ClassText, &ClassSize, NULL,
  267. &NumKeys, &MaxKey, &MaxClass, &NumValue,
  268. &MaxValue, &MaxValueData, &MaxSD, &LastWrite);
  269. if (Status == ERROR_SUCCESS) {
  270. FilePrintTable = (LPTSTR *) LocalAlloc(LPTR, sizeof(LPTSTR) * NumKeys);
  271. while ((Status == ERROR_SUCCESS) && (FilePrintTable != NULL)) {
  272. //
  273. // Double check in-case we need to expand the table.
  274. //
  275. if (index > NumKeys) {
  276. pFilePrintTableTmp = (LPTSTR *) LocalReAlloc(FilePrintTable, sizeof(LPTSTR) * (NumKeys+1), LHND);
  277. if (pFilePrintTableTmp == NULL)
  278. {
  279. Status = ERROR_NOT_ENOUGH_MEMORY;
  280. break;
  281. } else
  282. {
  283. NumKeys++;
  284. FilePrintTable = pFilePrintTableTmp;
  285. }
  286. }
  287. //
  288. // Now read in the key name and add it to the table
  289. //
  290. KeySize = KEY_NAME_SIZE;
  291. Status = RegEnumKeyEx(hKey2, index, KeyText, &KeySize, NULL, NULL, NULL, &LastWrite);
  292. if (Status == ERROR_SUCCESS) {
  293. //
  294. // Allocate space in our table and copy the key
  295. //
  296. cch = KeySize + 1;
  297. FilePrintTable[index] = (LPTSTR) LocalAlloc(LPTR, cch * sizeof(TCHAR));
  298. if (FilePrintTable[index] != NULL) {
  299. hr = StringCchCopy(FilePrintTable[index], cch, KeyText);
  300. ASSERT(SUCCEEDED(hr));
  301. index++;
  302. } else
  303. Status = ERROR_NOT_ENOUGH_MEMORY;
  304. }
  305. }
  306. }
  307. #ifdef DEBUG
  308. else {
  309. dprintf(TEXT("LLS FilePrintTable Error: 0x%lx\n"), Status);
  310. }
  311. #endif
  312. RegCloseKey( hKey2 );
  313. }
  314. if (FilePrintTable != NULL)
  315. NumFilePrintEntries = index;
  316. else
  317. NumFilePrintEntries = 0;
  318. return Status;
  319. } // FilePrintTableInit
  320. /////////////////////////////////////////////////////////////////////////
  321. NTSTATUS
  322. RegistryMonitor (
  323. IN PVOID ThreadParameter
  324. )
  325. /*++
  326. Routine Description:
  327. Watches for any changes in the Licensing Keys, and if any updates our
  328. internal information.
  329. Arguments:
  330. ThreadParameter - Indicates how many active threads there currently
  331. are.
  332. Return Value:
  333. None.
  334. --*/
  335. {
  336. LONG Status = 0;
  337. HKEY hKey1 = NULL;
  338. HKEY hKey2 = NULL;
  339. NTSTATUS NtStatus = STATUS_SUCCESS;
  340. static const TCHAR RegKeyText1[] = TEXT("System\\CurrentControlSet\\Services\\LicenseService");
  341. static const TCHAR RegKeyText2[] = TEXT("System\\CurrentControlSet\\Services\\LicenseInfo");
  342. HANDLE Events[2];
  343. DWORD dwWhichEvent = 0; // Keeps track of which event was last triggered
  344. UNREFERENCED_PARAMETER(ThreadParameter);
  345. //
  346. // Open registry key-name we are looking for
  347. //
  348. if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText1, 0, KEY_NOTIFY, &hKey1)) != ERROR_SUCCESS) {
  349. #if DBG
  350. dprintf(TEXT("LLS RegistryMonitor - RegOpenKeyEx failed: 0x%lX\n"), Status);
  351. #endif
  352. return (NTSTATUS) Status;
  353. }
  354. if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText2, 0, KEY_NOTIFY, &hKey2)) != ERROR_SUCCESS) {
  355. #if DBG
  356. dprintf(TEXT("LLS RegistryMonitor - RegOpenKeyEx 2 failed: 0x%lX\n"), Status);
  357. #endif
  358. RegCloseKey(hKey1);
  359. return (NTSTATUS) Status;
  360. }
  361. if ((Status = NtCreateEvent(Events,EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE,NULL,SynchronizationEvent,FALSE)) != ERROR_SUCCESS)
  362. {
  363. #if DBG
  364. dprintf(TEXT("LLS RegistryMonitor - RegOpenKeyEx 2 failed: 0x%lX\n"), Status);
  365. #endif
  366. RegCloseKey(hKey1);
  367. RegCloseKey(hKey2);
  368. return (NTSTATUS) Status;
  369. }
  370. Events[1] = LLSRegistryEvent;
  371. //
  372. // Loop forever
  373. //
  374. for ( ; ; ) {
  375. if ((dwWhichEvent == 0) || (dwWhichEvent == 2))
  376. {
  377. Status = RegNotifyChangeKeyValue(hKey1, TRUE, REG_NOTIFY_CHANGE_LAST_SET, LLSRegistryEvent, TRUE);
  378. if (Status != ERROR_SUCCESS) {
  379. #if DBG
  380. dprintf(TEXT("LLS RegNotifyChangeKeyValue Failed: %lu\n"), Status);
  381. #endif
  382. }
  383. }
  384. if ((dwWhichEvent == 0) || (dwWhichEvent == 1))
  385. {
  386. Status = RegNotifyChangeKeyValue(hKey2, TRUE, REG_NOTIFY_CHANGE_LAST_SET, Events[0], TRUE);
  387. if (Status != ERROR_SUCCESS) {
  388. #if DBG
  389. dprintf(TEXT("LLS RegNotifyChangeKeyValue 2 Failed: %lu\n"), Status);
  390. #endif
  391. }
  392. }
  393. NtStatus = NtWaitForMultipleObjects( 2, Events, WaitAny, TRUE, NULL );
  394. switch (NtStatus)
  395. {
  396. case 0:
  397. dwWhichEvent = 1;
  398. break;
  399. case 1:
  400. dwWhichEvent = 2;
  401. break;
  402. default:
  403. dwWhichEvent = 0;
  404. break;
  405. }
  406. #if DELAY_INITIALIZATION
  407. EnsureInitialized();
  408. #endif
  409. //
  410. // Re-synch the lists
  411. //
  412. LocalServiceListUpdate();
  413. LocalServerServiceListUpdate();
  414. ServiceListResynch();
  415. ConfigInfoRegistryUpdate();
  416. LocalServiceListConcurrentLimitSet();
  417. if (dwWhichEvent == 0)
  418. {
  419. #if DBG
  420. dprintf(TEXT("LLS Registry Event Notification Failed: %lu\n"), NtStatus);
  421. #endif
  422. //
  423. // If we failed - sleep for 2 minutes before looping
  424. //
  425. Sleep(120000L);
  426. }
  427. }
  428. //return NtStatus; //unreachable line
  429. } // RegistryMonitor
  430. /////////////////////////////////////////////////////////////////////////
  431. VOID
  432. RegistryInit( )
  433. /*++
  434. Routine Description:
  435. Looks in registry for given service and sets values accordingly.
  436. Arguments:
  437. Return Value:
  438. None.
  439. --*/
  440. {
  441. NTSTATUS Status;
  442. DWORD Mode, ConcurrentLimit;
  443. Mode = 0;
  444. ConcurrentLimit = 0;
  445. //
  446. // Create a key to tell us about any changes in the registry
  447. //
  448. Status = NtCreateEvent(
  449. &LLSRegistryEvent,
  450. EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE,
  451. NULL,
  452. SynchronizationEvent,
  453. FALSE
  454. );
  455. ASSERT(NT_SUCCESS(Status));
  456. } // RegistryInit
  457. /////////////////////////////////////////////////////////////////////////
  458. VOID
  459. RegistryStartMonitor( )
  460. /*++
  461. Routine Description:
  462. Looks in registry for given service and sets values accordingly.
  463. Arguments:
  464. Return Value:
  465. None.
  466. --*/
  467. {
  468. HANDLE Thread;
  469. DWORD Ignore;
  470. //
  471. // Now dispatch a thread to watch for any registry changes
  472. //
  473. Thread = CreateThread(
  474. NULL,
  475. 0L,
  476. (LPTHREAD_START_ROUTINE) RegistryMonitor,
  477. 0L,
  478. 0L,
  479. &Ignore
  480. );
  481. if (Thread != NULL)
  482. CloseHandle(Thread);
  483. } // RegistryStartMonitor
  484. /////////////////////////////////////////////////////////////////////////
  485. VOID
  486. RegistryInitValues(
  487. LPTSTR ServiceName,
  488. BOOL *PerSeatLicensing,
  489. ULONG *SessionLimit
  490. )
  491. /*++
  492. Routine Description:
  493. Looks in registry for given service and sets values accordingly.
  494. Arguments:
  495. Service Name -
  496. PerSeatLicensing -
  497. SessionLimit -
  498. Return Value:
  499. None.
  500. --*/
  501. {
  502. static TCHAR RegKeyText[512];
  503. #ifndef SPECIAL_USER_LIMIT
  504. LONG Status;
  505. DWORD Mode, ConcurrentLimit;
  506. DWORD dwType, dwSize;
  507. HKEY hKey2 = NULL;
  508. HRESULT hr;
  509. size_t cb;
  510. #endif
  511. #if DBG
  512. if (TraceFlags & TRACE_FUNCTION_TRACE)
  513. dprintf(TEXT("LLS TRACE: RegistryInitValues\n"));
  514. #endif
  515. #ifdef SPECIAL_USER_LIMIT
  516. ASSERT(NULL != PerSeatLicensing &&
  517. NULL != SessionLimit);
  518. *PerSeatLicensing = FALSE;
  519. *SessionLimit = SPECIAL_USER_LIMIT;
  520. UNREFERENCED_PARAMETER(ServiceName);
  521. #else // #ifdef SPECIAL_USER_LIMIT
  522. Mode = 0;
  523. ConcurrentLimit = 0;
  524. //
  525. // Create registry key-name we are looking for
  526. //
  527. cb = sizeof(RegKeyText);
  528. hr = StringCbCopy(RegKeyText, cb, TEXT("System\\CurrentControlSet\\Services\\LicenseInfo\\"));
  529. ASSERT(SUCCEEDED(hr));
  530. hr = StringCbCat(RegKeyText, cb, ServiceName);
  531. ASSERT(SUCCEEDED(hr));
  532. if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_READ, &hKey2)) == ERROR_SUCCESS) {
  533. //
  534. // First Get Mode
  535. //
  536. dwSize = sizeof(Mode);
  537. Status = RegQueryValueEx(hKey2, TEXT("Mode"), NULL, &dwType, (LPBYTE) &Mode, &dwSize);
  538. #if DBG
  539. if ((TraceFlags & TRACE_REGISTRY) && (Status == ERROR_SUCCESS))
  540. dprintf(TEXT("Found Reg-Key for [%s] Mode: %ld\n"), ServiceName, Mode);
  541. #endif
  542. //
  543. // Now Concurrent Limit
  544. //
  545. dwSize = sizeof(ConcurrentLimit);
  546. Status = RegQueryValueEx(hKey2, TEXT("ConcurrentLimit"), NULL, &dwType, (LPBYTE) &ConcurrentLimit, &dwSize);
  547. #if DBG
  548. if ((TraceFlags & TRACE_REGISTRY) && (Status == ERROR_SUCCESS))
  549. dprintf(TEXT("Found Reg-Key for [%s] ConcurrentLimit: %ld\n"), ServiceName, ConcurrentLimit);
  550. #endif
  551. RegCloseKey(hKey2);
  552. }
  553. if (Mode == 0) {
  554. *PerSeatLicensing = TRUE;
  555. *SessionLimit = 0;
  556. } else {
  557. *PerSeatLicensing = FALSE;
  558. *SessionLimit = ConcurrentLimit;
  559. }
  560. #endif // #else // #ifdef SPECIAL_USER_LIMIT
  561. } // RegistryInitValues
  562. /////////////////////////////////////////////////////////////////////////
  563. VOID
  564. RegistryDisplayNameGet(
  565. LPTSTR ServiceName,
  566. LPTSTR DefaultName,
  567. LPTSTR *pDisplayName
  568. )
  569. /*++
  570. Routine Description:
  571. Arguments:
  572. Service Name -
  573. Return Value:
  574. None.
  575. --*/
  576. {
  577. HKEY hKey2 = NULL;
  578. DWORD dwType, dwSize;
  579. static TCHAR RegKeyText[512];
  580. static TCHAR DisplayName[512];
  581. LONG Status;
  582. HRESULT hr;
  583. size_t cb, cch;
  584. #if DBG
  585. if (TraceFlags & TRACE_FUNCTION_TRACE)
  586. dprintf(TEXT("LLS TRACE: RegistryDisplayNameGet\n"));
  587. #endif
  588. hr = StringCbCopy(DisplayName, sizeof(DisplayName), DefaultName);
  589. ASSERT(SUCCEEDED(hr));
  590. //
  591. // Create registry key-name we are looking for
  592. //
  593. cb = sizeof(RegKeyText);
  594. hr = StringCbCopy(RegKeyText, cb, TEXT("System\\CurrentControlSet\\Services\\LicenseInfo\\"));
  595. ASSERT(SUCCEEDED(hr));
  596. hr = StringCbCat(RegKeyText, cb, ServiceName);
  597. ASSERT(SUCCEEDED(hr));
  598. if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_READ, &hKey2)) == ERROR_SUCCESS) {
  599. dwSize = sizeof(DisplayName);
  600. Status = RegQueryValueEx(hKey2, TEXT("DisplayName"), NULL, &dwType, (LPBYTE) DisplayName, &dwSize);
  601. # if DBG
  602. if ((TraceFlags & TRACE_REGISTRY) && (Status == ERROR_SUCCESS))
  603. dprintf(TEXT("Found Reg-Key for [%s] DisplayName: %s\n"), ServiceName, DisplayName);
  604. # endif
  605. RegCloseKey(hKey2);
  606. }
  607. ASSERT(NULL != pDisplayName);
  608. cch = lstrlen(DisplayName) + 1;
  609. *pDisplayName = LocalAlloc(LPTR, cch * sizeof(TCHAR));
  610. if (*pDisplayName != NULL)
  611. {
  612. hr = StringCchCopy(*pDisplayName, cch, DisplayName);
  613. ASSERT(SUCCEEDED(hr));
  614. }
  615. } // RegistryDisplayNameGet
  616. /////////////////////////////////////////////////////////////////////////
  617. VOID
  618. RegistryFamilyDisplayNameGet(
  619. LPTSTR ServiceName,
  620. LPTSTR DefaultName,
  621. LPTSTR *pDisplayName
  622. )
  623. /*++
  624. Routine Description:
  625. Arguments:
  626. Service Name -
  627. Return Value:
  628. None.
  629. --*/
  630. {
  631. HKEY hKey2 = NULL;
  632. DWORD dwType, dwSize;
  633. static TCHAR RegKeyText[512];
  634. static TCHAR DisplayName[MAX_PATH + 1];
  635. LONG Status;
  636. HRESULT hr;
  637. size_t cb, cch;
  638. #if DBG
  639. if (TraceFlags & TRACE_FUNCTION_TRACE)
  640. dprintf(TEXT("LLS TRACE: RegistryFamilyDisplayNameGet\n"));
  641. #endif
  642. hr = StringCbCopy(DisplayName, sizeof(DisplayName), DefaultName);
  643. ASSERT(SUCCEEDED(hr));
  644. //
  645. // Create registry key-name we are looking for
  646. //
  647. cb = sizeof(RegKeyText);
  648. hr = StringCbCopy(RegKeyText, cb, TEXT("System\\CurrentControlSet\\Services\\LicenseInfo\\"));
  649. ASSERT(SUCCEEDED(hr));
  650. hr = StringCbCat(RegKeyText, cb, ServiceName);
  651. ASSERT(SUCCEEDED(hr));
  652. if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_READ, &hKey2)) == ERROR_SUCCESS) {
  653. dwSize = sizeof(DisplayName);
  654. Status = RegQueryValueEx(hKey2, TEXT("FamilyDisplayName"), NULL, &dwType, (LPBYTE) DisplayName, &dwSize);
  655. # if DBG
  656. if ((TraceFlags & TRACE_REGISTRY) && (Status == ERROR_SUCCESS))
  657. dprintf(TEXT("Found Reg-Key for [%s] FamilyDisplayName: %s\n"), ServiceName, DisplayName);
  658. # endif
  659. RegCloseKey(hKey2);
  660. }
  661. ASSERT(NULL != pDisplayName);
  662. cch = lstrlen(DisplayName) + 1;
  663. *pDisplayName = LocalAlloc(LPTR, cch * sizeof(TCHAR));
  664. if (*pDisplayName != NULL)
  665. {
  666. hr = StringCchCopy(*pDisplayName, cch, DisplayName);
  667. ASSERT(SUCCEEDED(hr));
  668. }
  669. } // RegistryFamilyDisplayNameGet
  670. /////////////////////////////////////////////////////////////////////////
  671. LPTSTR
  672. ServiceFindInTable(
  673. LPTSTR ServiceName,
  674. const LPTSTR Table[],
  675. ULONG TableSize,
  676. ULONG *TableIndex
  677. )
  678. /*++
  679. Routine Description:
  680. Does search of table to find matching service name.
  681. Arguments:
  682. Service Name -
  683. Table -
  684. TableSize -
  685. TableIndex -
  686. Return Value:
  687. Pointer to found service or NULL if not found.
  688. --*/
  689. {
  690. ULONG i = 0;
  691. BOOL Found = FALSE;
  692. #if DBG
  693. if (TraceFlags & TRACE_FUNCTION_TRACE)
  694. dprintf(TEXT("LLS TRACE: ServiceFindInTable\n"));
  695. #endif
  696. while ((i < TableSize) && (!Found)) {
  697. Found = !lstrcmpi(ServiceName, Table[i]);
  698. i++;
  699. }
  700. if (Found) {
  701. i--;
  702. *TableIndex = i;
  703. return Table[i];
  704. } else
  705. return NULL;
  706. } // ServiceFindInTable
  707. /////////////////////////////////////////////////////////////////////////
  708. VOID
  709. RegistryInitService(
  710. LPTSTR ServiceName,
  711. BOOL *PerSeatLicensing,
  712. ULONG *SessionLimit
  713. )
  714. /*++
  715. Routine Description:
  716. Gets init values for a given service from the registry. If not found
  717. then just returns default values.
  718. Arguments:
  719. ServiceName -
  720. PerSeatLicensing -
  721. SessionLimit -
  722. Return Value:
  723. --*/
  724. {
  725. //
  726. // These are the default values
  727. //
  728. ULONG TableEntry;
  729. LPTSTR SvcName = NULL;
  730. #if DBG
  731. if (TraceFlags & TRACE_FUNCTION_TRACE)
  732. dprintf(TEXT("LLS TRACE: RegistryInitService\n"));
  733. #endif
  734. ASSERT(NULL != PerSeatLicensing &&
  735. NULL != SessionLimit);
  736. *PerSeatLicensing = FALSE;
  737. *SessionLimit = 0;
  738. //
  739. // Check if it is a file/print service - if so don't worry about rest
  740. // of registry entries.
  741. //
  742. if (ServiceFindInTable(ServiceName, FilePrintTable, NumFilePrintEntries, &TableEntry)) {
  743. return;
  744. }
  745. //
  746. // Not FilePrint - see if we need to map the name.
  747. //
  748. SvcName = ServiceFindInTable(ServiceName, NameMappingTable2, NUM_MAPPING_ENTRIES, &TableEntry);
  749. // if it wasn't found, use original ServiceName
  750. if (SvcName == NULL)
  751. SvcName = ServiceName;
  752. RegistryInitValues(SvcName, PerSeatLicensing, SessionLimit);
  753. #if DBG
  754. if (TraceFlags & TRACE_REGISTRY)
  755. if (*PerSeatLicensing)
  756. dprintf(TEXT("LLS - Registry Init: PerSeat: Y Svc: %s\n"), SvcName);
  757. else
  758. dprintf(TEXT("LLS - Registry Init: PerSeat: N Svc: %s\n"), SvcName);
  759. #endif
  760. } // RegistryInitService
  761. /////////////////////////////////////////////////////////////////////////
  762. /////////////////////////////////////////////////////////////////////////
  763. /////////////////////////////////////////////////////////////////////////
  764. /////////////////////////////////////////////////////////////////////////
  765. NTSTATUS
  766. LocalServiceListInit()
  767. /*++
  768. Routine Description:
  769. Arguments:
  770. None.
  771. Return Value:
  772. None.
  773. --*/
  774. {
  775. NTSTATUS status = STATUS_SUCCESS;
  776. try
  777. {
  778. RtlInitializeResource(&LocalServiceListLock);
  779. } except(EXCEPTION_EXECUTE_HANDLER ) {
  780. status = GetExceptionCode();
  781. }
  782. if (!NT_SUCCESS(status))
  783. return status;
  784. //
  785. // Now scan the registry and add all the services
  786. //
  787. LocalServiceListUpdate();
  788. return STATUS_SUCCESS;
  789. } // LocalServiceListInit
  790. /////////////////////////////////////////////////////////////////////////
  791. int __cdecl LocalServiceListCompare(const void *arg1, const void *arg2) {
  792. PLOCAL_SERVICE_RECORD Svc1, Svc2;
  793. Svc1 = (PLOCAL_SERVICE_RECORD) *((PLOCAL_SERVICE_RECORD *) arg1);
  794. Svc2 = (PLOCAL_SERVICE_RECORD) *((PLOCAL_SERVICE_RECORD *) arg2);
  795. return lstrcmpi( Svc1->Name, Svc2->Name );
  796. } // LocalServiceListCompare
  797. /////////////////////////////////////////////////////////////////////////
  798. PLOCAL_SERVICE_RECORD
  799. LocalServiceListFind(
  800. LPTSTR Name
  801. )
  802. /*++
  803. Routine Description:
  804. Internal routine to actually do binary search on LocalServiceList, this
  805. does not do any locking as we expect the wrapper routine to do this.
  806. The search is a simple binary search.
  807. Arguments:
  808. ServiceName -
  809. Return Value:
  810. Pointer to found server table entry or NULL if not found.
  811. --*/
  812. {
  813. LONG begin = 0;
  814. LONG end = (LONG) LocalServiceListSize - 1;
  815. LONG cur;
  816. int match;
  817. PLOCAL_SERVICE_RECORD Service;
  818. #if DBG
  819. if (TraceFlags & TRACE_FUNCTION_TRACE)
  820. dprintf(TEXT("LLS TRACE: LocalServiceListFind\n"));
  821. #endif
  822. if ((LocalServiceListSize == 0) || (Name == NULL))
  823. return NULL;
  824. while (end >= begin) {
  825. // go halfway in-between
  826. cur = (begin + end) / 2;
  827. Service = LocalServiceList[cur];
  828. // compare the two result into match
  829. match = lstrcmpi(Name, Service->Name);
  830. if (match < 0)
  831. // move new begin
  832. end = cur - 1;
  833. else
  834. begin = cur + 1;
  835. if (match == 0)
  836. return Service;
  837. }
  838. return NULL;
  839. } // LocalServiceListFind
  840. /////////////////////////////////////////////////////////////////////////
  841. PLOCAL_SERVICE_RECORD
  842. LocalServiceListAdd(
  843. LPTSTR Name,
  844. LPTSTR DisplayName,
  845. LPTSTR FamilyDisplayName,
  846. DWORD ConcurrentLimit,
  847. DWORD FlipAllow,
  848. DWORD Mode,
  849. DWORD HighMark
  850. )
  851. /*++
  852. Routine Description:
  853. Arguments:
  854. ServiceName -
  855. Return Value:
  856. Pointer to added service table entry, or NULL if failed.
  857. --*/
  858. {
  859. LPTSTR NewName;
  860. PLOCAL_SERVICE_RECORD Service;
  861. PLOCAL_SERVICE_RECORD *pLocalServiceListTmp;
  862. HRESULT hr;
  863. size_t cch;
  864. #if DBG
  865. if (TraceFlags & TRACE_FUNCTION_TRACE)
  866. dprintf(TEXT("LLS TRACE: LocalServiceListAdd\n"));
  867. #endif
  868. if ((Name == NULL) || (*Name == TEXT('\0'))) {
  869. #if DBG
  870. dprintf(TEXT("Error LLS: LocalServiceListAdd Bad Parms\n"));
  871. #endif
  872. ASSERT(FALSE);
  873. return NULL;
  874. }
  875. //
  876. // Try to find the name
  877. //
  878. Service = LocalServiceListFind(Name);
  879. if (Service != NULL) {
  880. Service->ConcurrentLimit = ConcurrentLimit;
  881. Service->FlipAllow = FlipAllow;
  882. Service->Mode = Mode;
  883. return Service;
  884. }
  885. //
  886. // No record - so create a new one
  887. //
  888. if (LocalServiceList == NULL) {
  889. pLocalServiceListTmp = (PLOCAL_SERVICE_RECORD *) LocalAlloc(LPTR, sizeof(PLOCAL_SERVICE_RECORD));
  890. } else {
  891. pLocalServiceListTmp = (PLOCAL_SERVICE_RECORD *) LocalReAlloc(LocalServiceList, sizeof(PLOCAL_SERVICE_RECORD) * (LocalServiceListSize + 1), LHND);
  892. }
  893. //
  894. // Make sure we could allocate server table
  895. //
  896. if (pLocalServiceListTmp == NULL) {
  897. return NULL;
  898. } else {
  899. LocalServiceList = pLocalServiceListTmp;
  900. }
  901. //
  902. // Allocate space for Record.
  903. //
  904. Service = (PLOCAL_SERVICE_RECORD) LocalAlloc(LPTR, sizeof(LOCAL_SERVICE_RECORD));
  905. if (Service == NULL) {
  906. ASSERT(FALSE);
  907. return NULL;
  908. }
  909. LocalServiceList[LocalServiceListSize] = Service;
  910. //
  911. // Name
  912. //
  913. cch = lstrlen(Name) + 1;
  914. NewName = (LPTSTR) LocalAlloc(LPTR, cch * sizeof(TCHAR));
  915. if (NewName == NULL) {
  916. ASSERT(FALSE);
  917. LocalFree(Service);
  918. return NULL;
  919. }
  920. // now copy it over...
  921. Service->Name = NewName;
  922. hr = StringCchCopy(NewName, cch, Name);
  923. ASSERT(SUCCEEDED(hr));
  924. //
  925. // DisplayName
  926. //
  927. cch = lstrlen(DisplayName) + 1;
  928. NewName = (LPTSTR) LocalAlloc(LPTR, cch * sizeof(TCHAR));
  929. if (NewName == NULL) {
  930. ASSERT(FALSE);
  931. LocalFree(Service->Name);
  932. LocalFree(Service);
  933. return NULL;
  934. }
  935. // now copy it over...
  936. Service->DisplayName = NewName;
  937. hr = StringCchCopy(NewName, cch, DisplayName);
  938. ASSERT(SUCCEEDED(hr));
  939. //
  940. // FamilyDisplayName
  941. //
  942. cch = lstrlen(FamilyDisplayName) + 1;
  943. NewName = (LPTSTR) LocalAlloc(LPTR, cch * sizeof(TCHAR));
  944. if (NewName == NULL) {
  945. ASSERT(FALSE);
  946. LocalFree(Service->Name);
  947. LocalFree(Service->DisplayName);
  948. LocalFree(Service);
  949. return NULL;
  950. }
  951. // now copy it over...
  952. Service->FamilyDisplayName = NewName;
  953. hr = StringCchCopy(NewName, cch, FamilyDisplayName);
  954. ASSERT(SUCCEEDED(hr));
  955. //
  956. // Initialize other stuff
  957. //
  958. Service->ConcurrentLimit = ConcurrentLimit;
  959. Service->FlipAllow = FlipAllow;
  960. Service->Mode = Mode;
  961. Service->HighMark = HighMark;
  962. LocalServiceListSize++;
  963. // Have added the entry - now need to sort it in order of the service names
  964. qsort((void *) LocalServiceList, (size_t) LocalServiceListSize, sizeof(PLOCAL_SERVICE_RECORD), LocalServiceListCompare);
  965. return Service;
  966. } // LocalServiceListAdd
  967. /////////////////////////////////////////////////////////////////////////
  968. VOID
  969. LocalServiceListUpdate( )
  970. /*++
  971. Routine Description:
  972. Looks in registry for given service and sets values accordingly.
  973. Arguments:
  974. Return Value:
  975. None.
  976. --*/
  977. {
  978. HKEY hKey2 = NULL;
  979. HKEY hKey3 = NULL;
  980. static TCHAR KeyName[MAX_PATH + 1];
  981. static TCHAR DisplayName[MAX_PATH + 1];
  982. static TCHAR FamilyDisplayName[MAX_PATH + 1];
  983. LONG EnumStatus;
  984. NTSTATUS Status;
  985. DWORD iSubKey = 0;
  986. DWORD dwType, dwSize;
  987. DWORD FlipAllow = 0;
  988. DWORD Mode = 0;
  989. DWORD ConcurrentLimit = 0;
  990. DWORD HighMark = 0;
  991. HRESULT hr;
  992. #if DBG
  993. if (TraceFlags & TRACE_FUNCTION_TRACE)
  994. dprintf(TEXT("LLS TRACE: LocalServiceListUpdate\n"));
  995. #endif
  996. RtlAcquireResourceExclusive(&LocalServiceListLock, TRUE);
  997. EnumStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\LicenseInfo"), 0, KEY_READ, &hKey2);
  998. while (EnumStatus == ERROR_SUCCESS) {
  999. EnumStatus = RegEnumKey(hKey2, iSubKey, KeyName, MAX_PATH + 1);
  1000. iSubKey++;
  1001. if (EnumStatus == ERROR_SUCCESS) {
  1002. if ((Status = RegOpenKeyEx(hKey2, KeyName, 0, KEY_READ, &hKey3)) == ERROR_SUCCESS) {
  1003. dwSize = sizeof(DisplayName);
  1004. Status = RegQueryValueEx(hKey3, TEXT("DisplayName"), NULL, &dwType, (LPBYTE) DisplayName, &dwSize);
  1005. dwSize = sizeof(FamilyDisplayName);
  1006. if (Status == ERROR_SUCCESS) {
  1007. Status = RegQueryValueEx(hKey3, TEXT("FamilyDisplayName"), NULL, &dwType, (LPBYTE) FamilyDisplayName, &dwSize);
  1008. if (Status != ERROR_SUCCESS) {
  1009. hr = StringCbCopy(FamilyDisplayName, sizeof(FamilyDisplayName), DisplayName);
  1010. ASSERT(SUCCEEDED(hr));
  1011. Status = ERROR_SUCCESS;
  1012. }
  1013. }
  1014. dwSize = sizeof(Mode);
  1015. if (Status == ERROR_SUCCESS)
  1016. Status = RegQueryValueEx(hKey3, TEXT("Mode"), NULL, &dwType, (LPBYTE) &Mode, &dwSize);
  1017. dwSize = sizeof(FlipAllow);
  1018. if (Status == ERROR_SUCCESS)
  1019. Status = RegQueryValueEx(hKey3, TEXT("FlipAllow"), NULL, &dwType, (LPBYTE) &FlipAllow, &dwSize);
  1020. dwSize = sizeof(ConcurrentLimit);
  1021. if (Status == ERROR_SUCCESS)
  1022. if (Mode == 0)
  1023. ConcurrentLimit = 0;
  1024. else
  1025. Status = RegQueryValueEx(hKey3, TEXT("ConcurrentLimit"), NULL, &dwType, (LPBYTE) &ConcurrentLimit, &dwSize);
  1026. dwSize = sizeof(HighMark);
  1027. if (Status == ERROR_SUCCESS) {
  1028. Status = RegQueryValueEx(hKey3, TEXT("LocalKey"), NULL, &dwType, (LPBYTE) &HighMark, &dwSize);
  1029. if (Status != ERROR_SUCCESS) {
  1030. Status = ERROR_SUCCESS;
  1031. HighMark = 0;
  1032. }
  1033. }
  1034. //
  1035. // If we read in everything then add to our table
  1036. //
  1037. if (Status == ERROR_SUCCESS)
  1038. LocalServiceListAdd(KeyName, DisplayName, FamilyDisplayName, ConcurrentLimit, FlipAllow, Mode, HighMark);
  1039. RegCloseKey(hKey3);
  1040. }
  1041. }
  1042. }
  1043. RegCloseKey(hKey2);
  1044. RtlReleaseResource(&LocalServiceListLock);
  1045. } // LocalServiceListUpdate
  1046. /////////////////////////////////////////////////////////////////////////
  1047. VOID
  1048. LocalServiceListHighMarkSet( )
  1049. /*++
  1050. Routine Description:
  1051. Arguments:
  1052. Return Value:
  1053. None.
  1054. --*/
  1055. {
  1056. HKEY hKey2 = NULL;
  1057. static TCHAR RegKeyText[512];
  1058. LONG Status;
  1059. ULONG i, j;
  1060. PSERVICE_RECORD Service;
  1061. HRESULT hr;
  1062. size_t cb;
  1063. #if DBG
  1064. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1065. dprintf(TEXT("LLS TRACE: LocalServiceListHighMarkSet\n"));
  1066. #endif
  1067. RtlAcquireResourceExclusive(&LocalServiceListLock, TRUE);
  1068. for (i = 0; i < LocalServiceListSize; i++) {
  1069. RtlAcquireResourceShared(&ServiceListLock, TRUE);
  1070. j = 0;
  1071. Service = NULL;
  1072. while ( (j < ServiceListSize) && (Service == NULL) ) {
  1073. if (!lstrcmpi(LocalServiceList[i]->DisplayName, ServiceList[j]->DisplayName) )
  1074. Service = ServiceList[j];
  1075. j++;
  1076. }
  1077. RtlReleaseResource(&ServiceListLock);
  1078. if (Service != NULL) {
  1079. //
  1080. // Create registry key-name we are looking for
  1081. //
  1082. cb = sizeof(RegKeyText);
  1083. hr = StringCbCopy(RegKeyText, cb, TEXT("System\\CurrentControlSet\\Services\\LicenseInfo\\"));
  1084. ASSERT(SUCCEEDED(hr));
  1085. hr = StringCbCat(RegKeyText, cb, LocalServiceList[i]->Name);
  1086. ASSERT(SUCCEEDED(hr));
  1087. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_WRITE, &hKey2);
  1088. if (Status == ERROR_SUCCESS)
  1089. {
  1090. Status = RegSetValueEx(hKey2, TEXT("LocalKey"), 0, REG_DWORD, (LPBYTE) &Service->HighMark, sizeof(Service->HighMark));
  1091. RegCloseKey( hKey2 );
  1092. }
  1093. }
  1094. }
  1095. RtlReleaseResource(&LocalServiceListLock);
  1096. } // LocalServiceListHighMarkSet
  1097. ///////////////////////////////////////////////////////////////////////////////
  1098. VOID
  1099. LocalServiceListConcurrentLimitSet( )
  1100. /*++
  1101. Routine Description:
  1102. Write concurrent limit to the registry for all secure services.
  1103. Modified from LocalServiceListHighMarkSet() implementation.
  1104. Arguments:
  1105. None.
  1106. Return Value:
  1107. None.
  1108. --*/
  1109. {
  1110. HKEY hKey2 = NULL;
  1111. TCHAR RegKeyText[512];
  1112. LONG Status;
  1113. ULONG i;
  1114. HRESULT hr;
  1115. size_t cb;
  1116. #if DBG
  1117. if (TraceFlags & TRACE_FUNCTION_TRACE)
  1118. dprintf(TEXT("LLS TRACE: LocalServiceListConcurrentLimitSet\n"));
  1119. #endif
  1120. RtlAcquireResourceExclusive(&LocalServiceListLock, TRUE);
  1121. for (i = 0; i < LocalServiceListSize; i++)
  1122. {
  1123. //
  1124. // Create registry key-name we are looking for
  1125. //
  1126. cb = sizeof(RegKeyText);
  1127. hr = StringCbCopy(RegKeyText, cb, TEXT("System\\CurrentControlSet\\Services\\LicenseInfo\\"));
  1128. ASSERT(SUCCEEDED(hr));
  1129. hr = StringCbCat(RegKeyText, cb, LocalServiceList[i]->Name);
  1130. ASSERT(SUCCEEDED(hr));
  1131. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_READ, &hKey2);
  1132. if (Status == ERROR_SUCCESS)
  1133. {
  1134. DWORD dwConcurrentLimit;
  1135. DWORD cbConcurrentLimit = sizeof( dwConcurrentLimit );
  1136. DWORD dwType;
  1137. // don't write unless we have to (to avoid triggering the registry monitor thread)
  1138. Status = RegQueryValueEx(hKey2, TEXT("ConcurrentLimit"), NULL, &dwType, (LPBYTE) &dwConcurrentLimit, &cbConcurrentLimit );
  1139. if ( ServiceIsSecure( LocalServiceList[i]->DisplayName ) )
  1140. {
  1141. LocalServiceList[i]->ConcurrentLimit = LocalServiceList[i]->Mode ? ProductLicensesGet( LocalServiceList[i]->DisplayName, TRUE ) : 0;
  1142. // secure product
  1143. if ( ( ERROR_SUCCESS != Status )
  1144. || ( REG_DWORD != dwType )
  1145. || ( dwConcurrentLimit != LocalServiceList[i]->ConcurrentLimit ) )
  1146. {
  1147. RegCloseKey( hKey2 );
  1148. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegKeyText, 0, KEY_WRITE, &hKey2);
  1149. ASSERT( ERROR_SUCCESS == Status );
  1150. if ( ERROR_SUCCESS == Status )
  1151. {
  1152. Status = RegSetValueEx(hKey2, TEXT("ConcurrentLimit"), 0, REG_DWORD, (LPBYTE) &LocalServiceList[i]->ConcurrentLimit, sizeof( LocalServiceList[i]->ConcurrentLimit ) );
  1153. }
  1154. }
  1155. }
  1156. RegCloseKey( hKey2 );
  1157. }
  1158. }
  1159. RtlReleaseResource(&LocalServiceListLock);
  1160. } // LocalServiceListConcurrentLimitSet
  1161. ///////////////////////////////////////////////////////////////////////////////
  1162. BOOL ServiceIsSecure( LPTSTR ServiceName )
  1163. /*++
  1164. Routine Description:
  1165. Determine whether a given service disallows 3.51 Honesty-style
  1166. license purchases.
  1167. Arguments:
  1168. ServiceName (LPTSTR)
  1169. Service to check.
  1170. Return Value:
  1171. TRUE if service requires secure certificate,
  1172. FALSE if it accepts 3.51 Honesty-style license purchases.
  1173. --*/
  1174. {
  1175. BOOL IsSecure = FALSE;
  1176. if ( NULL != SecureServiceList )
  1177. {
  1178. DWORD i;
  1179. RtlEnterCriticalSection( &ConfigInfoLock );
  1180. for ( i=0; i < SecureServiceListSize; i++ )
  1181. {
  1182. if ( !lstrcmpi( SecureServiceList[i], ServiceName ) )
  1183. {
  1184. IsSecure = TRUE;
  1185. break;
  1186. }
  1187. }
  1188. RtlLeaveCriticalSection( &ConfigInfoLock );
  1189. }
  1190. return IsSecure;
  1191. }
  1192. ///////////////////////////////////////////////////////////////////////////////
  1193. NTSTATUS ServiceSecuritySet( LPTSTR ServiceName )
  1194. /*++
  1195. Routine Description:
  1196. Add a given service to the secure service list.
  1197. Arguments:
  1198. ServiceName (LPTSTR)
  1199. Service to add.
  1200. Return Value:
  1201. STATUS_SUCCESS or Win error or NTSTATUS error code.
  1202. --*/
  1203. {
  1204. NTSTATUS nt;
  1205. DWORD i;
  1206. BOOL bChangedValue = FALSE;
  1207. RtlEnterCriticalSection( &ConfigInfoLock );
  1208. for ( i=0; i < SecureServiceListSize; i++ )
  1209. {
  1210. if ( !lstrcmpi( SecureServiceList[i], ServiceName ) )
  1211. {
  1212. // product already registered as secure
  1213. break;
  1214. }
  1215. }
  1216. if ( i < SecureServiceListSize )
  1217. {
  1218. // product already registered as secure
  1219. nt = STATUS_SUCCESS;
  1220. }
  1221. else
  1222. {
  1223. TCHAR * NewSecureServiceBuffer;
  1224. ULONG NewSecureServiceBufferSize;
  1225. NewSecureServiceBufferSize = ( SecureServiceBufferSize ? SecureServiceBufferSize : sizeof( TCHAR ) ) + sizeof( TCHAR ) * ( 1 + lstrlen( ServiceName ) );
  1226. NewSecureServiceBuffer = LocalAlloc( LPTR, NewSecureServiceBufferSize );
  1227. if ( NULL == NewSecureServiceBuffer )
  1228. {
  1229. nt = STATUS_NO_MEMORY;
  1230. ASSERT( FALSE );
  1231. }
  1232. else
  1233. {
  1234. if ( NULL != SecureServiceBuffer )
  1235. {
  1236. // copy over current secure service strings
  1237. memcpy( NewSecureServiceBuffer, SecureServiceBuffer, SecureServiceBufferSize - sizeof( TCHAR ) );
  1238. // add new secure service (don't forget last string is followed by 2 nulls)
  1239. memcpy( (LPBYTE) NewSecureServiceBuffer + SecureServiceBufferSize - sizeof( TCHAR ), ServiceName, NewSecureServiceBufferSize - SecureServiceBufferSize - sizeof( TCHAR ) );
  1240. }
  1241. else
  1242. {
  1243. // add new secure service (don't forget last string is followed by 2 nulls)
  1244. memcpy( NewSecureServiceBuffer, ServiceName, NewSecureServiceBufferSize - sizeof( TCHAR ) );
  1245. }
  1246. ASSERT( 0 == *( (LPBYTE) NewSecureServiceBuffer + NewSecureServiceBufferSize - 2 * sizeof( TCHAR ) ) );
  1247. ASSERT( 0 == *( (LPBYTE) NewSecureServiceBuffer + NewSecureServiceBufferSize - sizeof( TCHAR ) ) );
  1248. // encrypt buffer
  1249. nt = EBlock( NewSecureServiceBuffer, NewSecureServiceBufferSize );
  1250. ASSERT( STATUS_SUCCESS == nt );
  1251. if ( STATUS_SUCCESS == nt )
  1252. {
  1253. HKEY hKeyParameters;
  1254. // save new list to registry
  1255. nt = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\LicenseService\\Parameters"), 0, KEY_WRITE, &hKeyParameters );
  1256. ASSERT( STATUS_SUCCESS == nt );
  1257. if ( STATUS_SUCCESS == nt )
  1258. {
  1259. nt = RegSetValueEx( hKeyParameters, TEXT( "ProductData" ), 0, REG_BINARY, (LPBYTE) NewSecureServiceBuffer, NewSecureServiceBufferSize );
  1260. ASSERT( STATUS_SUCCESS == nt );
  1261. if ( STATUS_SUCCESS == nt )
  1262. {
  1263. bChangedValue = TRUE;
  1264. }
  1265. }
  1266. RegCloseKey( hKeyParameters );
  1267. }
  1268. LocalFree( NewSecureServiceBuffer );
  1269. }
  1270. }
  1271. RtlLeaveCriticalSection( &ConfigInfoLock );
  1272. if ( ( STATUS_SUCCESS == nt ) && bChangedValue )
  1273. {
  1274. // key updated, now update internal copy
  1275. ConfigInfoRegistryUpdate();
  1276. }
  1277. return nt;
  1278. }
  1279. ///////////////////////////////////////////////////////////////////////////////
  1280. NTSTATUS ProductSecurityPack( LPDWORD pcchProductSecurityStrings, WCHAR ** ppchProductSecurityStrings )
  1281. /*++
  1282. Routine Description:
  1283. Pack the secure service list into a contiguous buffer for transmission.
  1284. NOTE: If the routine succeeds, the caller must later MIDL_user_free() the
  1285. buffer at *ppchProductSecurityStrings.
  1286. Arguments:
  1287. pcchProductSecurityStrings (LPDWORD)
  1288. On return, holds the size (in characters) of the buffer pointed to
  1289. by *ppchProductSecurityStrings.
  1290. ppchProductSecurityStrings (WCHAR **)
  1291. On return, holds the address of the buffer allocated to hold the names
  1292. of the secure products.
  1293. Return Value:
  1294. STATUS_SUCCESS or STATUS_NO_MEMORY.
  1295. --*/
  1296. {
  1297. NTSTATUS nt;
  1298. RtlEnterCriticalSection( &ConfigInfoLock );
  1299. ASSERT(NULL != ppchProductSecurityStrings);
  1300. *ppchProductSecurityStrings = MIDL_user_allocate( SecureServiceBufferSize );
  1301. if ( NULL == *ppchProductSecurityStrings )
  1302. {
  1303. nt = STATUS_NO_MEMORY;
  1304. ASSERT( FALSE );
  1305. }
  1306. else
  1307. {
  1308. memcpy( *ppchProductSecurityStrings, SecureServiceBuffer, SecureServiceBufferSize );
  1309. ASSERT(NULL != pcchProductSecurityStrings);
  1310. *pcchProductSecurityStrings = SecureServiceBufferSize / sizeof( TCHAR );
  1311. nt = STATUS_SUCCESS;
  1312. }
  1313. RtlLeaveCriticalSection( &ConfigInfoLock );
  1314. return nt;
  1315. }
  1316. ///////////////////////////////////////////////////////////////////////////////
  1317. NTSTATUS ProductSecurityUnpack( DWORD cchProductSecurityStrings, WCHAR * pchProductSecurityStrings )
  1318. /*++
  1319. Routine Description:
  1320. Unpack a secure service list packed by ProductSecurityPack(). The products
  1321. contained in the pack are added to the current secure product list.
  1322. Arguments:
  1323. cchProductSecurityStrings (DWORD)
  1324. The size (in characters) of the buffer pointed to by pchProductSecurityStrings.
  1325. pchProductSecurityStrings (WCHAR *)
  1326. The address of the buffer allocated to hold the names of the secure products.
  1327. Return Value:
  1328. STATUS_SUCCESS.
  1329. --*/
  1330. {
  1331. DWORD i;
  1332. for ( i=0;
  1333. ( i < cchProductSecurityStrings )
  1334. && ( TEXT('\0') != pchProductSecurityStrings[i] );
  1335. i += 1 + lstrlen( &pchProductSecurityStrings[i] ) )
  1336. {
  1337. ServiceSecuritySet( &pchProductSecurityStrings[i] );
  1338. }
  1339. return STATUS_SUCCESS;
  1340. }
  1341. #if DBG
  1342. ///////////////////////////////////////////////////////////////////////////////
  1343. void ProductSecurityListDebugDump()
  1344. /*++
  1345. Routine Description:
  1346. Dump contents of product security list to debug console.
  1347. Arguments:
  1348. None.
  1349. Return Value:
  1350. None.
  1351. --*/
  1352. {
  1353. if ( NULL == SecureServiceList )
  1354. {
  1355. dprintf( TEXT( "No secure products.\n" ) );
  1356. }
  1357. else
  1358. {
  1359. DWORD i;
  1360. RtlEnterCriticalSection( &ConfigInfoLock );
  1361. for ( i=0; i < SecureServiceListSize; i++ )
  1362. {
  1363. dprintf( TEXT( "(%3ld) %s\n" ), (long)i, SecureServiceList[i] );
  1364. }
  1365. RtlLeaveCriticalSection( &ConfigInfoLock );
  1366. }
  1367. }
  1368. #endif //DBG