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

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