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.

2570 lines
64 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. llssrv.c
  5. Abstract:
  6. Main routine to setup the exception handlers and initialize everything
  7. to listen to LPC and RPC port requests.
  8. Author:
  9. Arthur Hanson (arth) Dec 07, 1994
  10. Environment:
  11. Revision History:
  12. Jeff Parham (jeffparh) 05-Dec-1995
  13. o Added certificate database support.
  14. o Expanded file load time (the update limit sent to the service
  15. controller) to account for certificate database loading.
  16. o Reordered initialization such that the license purchase subsystem
  17. is initialized before the service subsystem. (The service
  18. subsystem now uses the license subsystem.)
  19. o Increased internal version number.
  20. --*/
  21. #include <nt.h>
  22. #include <ntlsa.h>
  23. #include <ntsam.h>
  24. #include <ntrtl.h>
  25. #include <nturtl.h>
  26. #include <windows.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <process.h>
  30. #include <tchar.h>
  31. #define COBJMACROS
  32. #include <objbase.h>
  33. #pragma warning (push)
  34. #pragma warning (disable : 4201) //iads.h(1003) : nonstandard extension used : nameless struct/union
  35. #include <iads.h>
  36. #pragma warning (pop)
  37. #include <adshlp.h>
  38. #include <adserr.h>
  39. #include <lm.h>
  40. #include <alertmsg.h>
  41. #include <winsock2.h>
  42. #include <dsgetdc.h>
  43. #include <ntdsapi.h>
  44. #include "llsapi.h"
  45. #include "debug.h"
  46. #include "llsutil.h"
  47. #include "llssrv.h"
  48. #include "service.h"
  49. #include "registry.h"
  50. #include "mapping.h"
  51. #include "msvctbl.h"
  52. #include "svctbl.h"
  53. #include "perseat.h"
  54. #include "purchase.h"
  55. #include "server.h"
  56. #include "repl.h"
  57. #include "scaven.h"
  58. #include "llsrpc_s.h"
  59. #include "certdb.h"
  60. #include <strsafe.h> //include last
  61. BOOL CompareMachineName(
  62. LPCWSTR pwszName1,
  63. LPCWSTR pwszName2);
  64. VOID DNSToFlatName(
  65. LPCWSTR pwszDNSName,
  66. DWORD ccBufferLen,
  67. LPWSTR pwszBuffer);
  68. NTSTATUS GetDCInfo(
  69. DWORD cbDomain,
  70. WCHAR *wszDomain,
  71. DOMAIN_CONTROLLER_INFO ** ppDCInfo);
  72. HRESULT GetSiteServer(
  73. LPCWSTR pwszDomain,
  74. LPCWSTR pwszSiteName,
  75. BOOL fIsDC,
  76. LPWSTR * ppwszSiteServer);
  77. HRESULT
  78. BecomeSiteServer(
  79. DS_NAME_RESULT **ppDsResult,
  80. IADs *pADs2,
  81. LPWSTR *ppwszDN,
  82. LPCWSTR pwszDomain);
  83. LPWSTR GetSiteServerFromRegistry(
  84. VOID);
  85. LPWSTR GetEnterpriseServerFromRegistry(
  86. VOID);
  87. HRESULT GetLicenseSettingsObject(
  88. LPCWSTR pwszSiteName,
  89. LPCWSTR pwszConfigContainer,
  90. IADs ** ppADs);
  91. HRESULT GetSiteObject(
  92. LPCWSTR pwszSiteName,
  93. LPCWSTR pwszConfigContainer,
  94. IADsContainer ** ppADsContainer);
  95. HRESULT CreateLicenseSettingsObject(
  96. LPCWSTR pwszSiteName,
  97. LPCWSTR pwszConfigContainer,
  98. IADs ** ppADs);
  99. BOOL IsDC(
  100. VOID);
  101. VOID LLSRpcInit();
  102. BOOLEAN LLSpLPCInitialize(
  103. VOID);
  104. VOID LoadAll();
  105. VOID SetSiteRegistrySettings(
  106. LPCWSTR pwszSiteServer);
  107. NTSTATUS FilePrintTableInit();
  108. #define INTERNAL_VERSION 0x0006
  109. #define DEFAULT_LICENSE_CHECK_TIME 24
  110. #define DEFAULT_REPLICATION_TIME 12 * 60 * 60
  111. CONFIG_RECORD ConfigInfo;
  112. RTL_CRITICAL_SECTION ConfigInfoLock;
  113. #if DBG
  114. DWORD TraceFlags = 0;
  115. #endif
  116. //
  117. // this event is signalled when the service should end
  118. //
  119. HANDLE hServerStopEvent = NULL;
  120. TCHAR MyDomain[MAX_COMPUTERNAME_LENGTH + 2];
  121. ULONG MyDomainSize;
  122. BOOL IsMaster = FALSE;
  123. //
  124. // Files
  125. //
  126. TCHAR MappingFileName[MAX_PATH + 1];
  127. TCHAR UserFileName[MAX_PATH + 1];
  128. TCHAR LicenseFileName[MAX_PATH + 1];
  129. TCHAR CertDbFileName[MAX_PATH + 1];
  130. extern SERVICE_STATUS_HANDLE sshStatusHandle;
  131. RTL_CRITICAL_SECTION g_csLock;
  132. volatile BOOL g_fInitializationComplete = FALSE;
  133. volatile BOOL g_fDoingInitialization = FALSE;
  134. //
  135. // SBS mods (bug# 505640), declarations for per server licensing problems hotfix
  136. //
  137. PPER_SERVER_USER_RECORD PerServerList = NULL;
  138. RTL_CRITICAL_SECTION PerServerListLock;
  139. BOOL SBSPerServerHotfix = FALSE;
  140. //
  141. // end SBS mods
  142. //
  143. HANDLE g_hThrottleConfig = NULL;
  144. HANDLE g_hThrottleConnect = NULL;
  145. BOOL g_fRunning = FALSE;
  146. extern RTL_CRITICAL_SECTION MappingFileLock;
  147. extern RTL_CRITICAL_SECTION UserFileLock;
  148. /////////////////////////////////////////////////////////////////////////
  149. NTSTATUS
  150. GetDCInfo(
  151. DWORD cbDomain,
  152. WCHAR *wszDomain,
  153. DOMAIN_CONTROLLER_INFO ** ppDCInfo
  154. )
  155. /*++
  156. Routine Description:
  157. Arguments:
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. DWORD Status;
  163. HRESULT hr;
  164. ASSERT(NULL != wszDomain);
  165. Status = DsGetDcNameW(NULL,
  166. NULL,
  167. NULL,
  168. NULL,
  169. DS_DIRECTORY_SERVICE_PREFERRED | DS_RETURN_FLAT_NAME | DS_BACKGROUND_ONLY,
  170. ppDCInfo);
  171. if (Status == STATUS_SUCCESS) {
  172. ASSERT(NULL != ppDCInfo);
  173. hr = StringCbCopy(wszDomain, cbDomain, (*ppDCInfo)->DomainName);
  174. ASSERT(SUCCEEDED(hr));
  175. }
  176. else {
  177. *wszDomain = L'\0';
  178. *ppDCInfo = NULL;
  179. }
  180. return(Status);
  181. } // GetDCInfo
  182. /////////////////////////////////////////////////////////////////////////
  183. DWORD
  184. LlsTimeGet(
  185. )
  186. /*++
  187. Routine Description:
  188. Arguments:
  189. Return Value:
  190. Seconds since midnight.
  191. --*/
  192. {
  193. DWORD Seconds;
  194. SYSTEMTIME SysTime;
  195. GetLocalTime(&SysTime);
  196. Seconds = (SysTime.wHour * 24 * 60) + (SysTime.wMinute * 60) + (SysTime.wSecond);
  197. return Seconds;
  198. } // LlsTimeGet
  199. /////////////////////////////////////////////////////////////////////////
  200. VOID
  201. ConfigInfoRegistryUpdate( )
  202. /*++
  203. Routine Description:
  204. Arguments:
  205. Return Value:
  206. --*/
  207. {
  208. DWORD ReplicationType, ReplicationTime;
  209. #if DBG
  210. if (TraceFlags & TRACE_FUNCTION_TRACE)
  211. dprintf(TEXT("LLS TRACE: ConfigInfoRegistryUpdate\n"));
  212. #endif
  213. #if DELAY_INITIALIZATION
  214. EnsureInitialized();
  215. #endif
  216. ConfigInfoUpdate(NULL,FALSE);
  217. RtlEnterCriticalSection(&ConfigInfoLock);
  218. //
  219. // Update values from Registry
  220. //
  221. ReplicationTime = ConfigInfo.ReplicationTime;
  222. ReplicationType = ConfigInfo.ReplicationType;
  223. ConfigInfoRegistryInit( &ConfigInfo.ReplicationType,
  224. &ConfigInfo.ReplicationTime,
  225. &ConfigInfo.LogLevel,
  226. &ConfigInfo.PerServerCapacityWarning );
  227. if ( (ConfigInfo.ReplicationTime == 0) && (LLS_REPLICATION_TYPE_TIME != ConfigInfo.ReplicationType) )
  228. ConfigInfo.ReplicationTime = DEFAULT_REPLICATION_TIME;
  229. //
  230. // Adjust replication time if it has changed
  231. //
  232. if ((ReplicationTime != ConfigInfo.ReplicationTime) || (ReplicationType != ConfigInfo.ReplicationType))
  233. ReplicationTimeSet();
  234. RtlLeaveCriticalSection(&ConfigInfoLock);
  235. } // ConfigInfoRegistryUpdate
  236. /////////////////////////////////////////////////////////////////////////
  237. VOID
  238. ConfigInfoUpdate(
  239. DOMAIN_CONTROLLER_INFO * pDCInfo,
  240. BOOL fForceUpdate
  241. )
  242. /*++
  243. Routine Description:
  244. Arguments:
  245. Return Value:
  246. --*/
  247. {
  248. BOOL fIsDC = FALSE;
  249. BOOL fSiteServerFromRegistry = FALSE;
  250. BOOL fInDomain = FALSE;
  251. LPWSTR pwszSiteName = NULL;
  252. LPWSTR pwszSiteServer = NULL;
  253. LPWSTR pwszPropagationTarget = NULL;
  254. DOMAIN_CONTROLLER_INFO * pDCInfoLocal = NULL;
  255. DWORD ReplicationType, ReplicationTime;
  256. TCHAR szDomain[MAX_COMPUTERNAME_LENGTH + 1] = { TEXT('\0') };
  257. DWORD dwWait;
  258. HRESULT hr;
  259. size_t cch;
  260. #if DBG
  261. if (TraceFlags & TRACE_FUNCTION_TRACE)
  262. dprintf(TEXT("LLS TRACE: ConfigInfoUpdate2\n"));
  263. #endif
  264. if (!fForceUpdate)
  265. {
  266. dwWait = WaitForSingleObject(g_hThrottleConfig, 0);
  267. if (dwWait == WAIT_TIMEOUT)
  268. {
  269. // We've already updated in the past 15 minutes; return immediately
  270. return;
  271. }
  272. }
  273. //
  274. // Get domain/DC information.
  275. //
  276. if (pDCInfo == NULL) {
  277. GetDCInfo(sizeof(szDomain),
  278. szDomain,
  279. &pDCInfoLocal);
  280. pDCInfo = pDCInfoLocal;
  281. }
  282. else {
  283. //
  284. // Copy the domain name.
  285. //
  286. if (pDCInfo->DomainName != NULL) {
  287. wcsncpy(szDomain, pDCInfo->DomainName, MAX_COMPUTERNAME_LENGTH);
  288. }
  289. }
  290. if (*szDomain) {
  291. fInDomain = TRUE;
  292. if (NO_ERROR != DsGetSiteName(NULL, &pwszSiteName))
  293. {
  294. pwszSiteName = NULL;
  295. }
  296. fIsDC = IsDC();
  297. if (fIsDC && (NULL != pwszSiteName)) {
  298. GetSiteServer(szDomain, pwszSiteName, fIsDC, &pwszSiteServer);
  299. }
  300. }
  301. if (!fIsDC) {
  302. //
  303. // Domain or Workgroup member
  304. //
  305. pwszSiteServer = GetSiteServerFromRegistry();
  306. fSiteServerFromRegistry = TRUE;
  307. }
  308. if ( fIsDC ) {
  309. //
  310. // This server is a DC. Propagate to the site server.
  311. //
  312. if (pwszSiteServer == NULL) {
  313. //
  314. // The attempt to obtain it from the DS failed, default to
  315. // the local registry.
  316. //
  317. pwszSiteServer = GetSiteServerFromRegistry();
  318. fSiteServerFromRegistry = TRUE;
  319. }
  320. pwszPropagationTarget = pwszSiteServer;
  321. }
  322. else if ( fInDomain ) {
  323. //
  324. // This server is a member server. Propagate to a DC, providing
  325. // it is in the same site as this server; else, propagate
  326. // directly to the site server.
  327. //
  328. if (pDCInfo != NULL && pwszSiteName != NULL &&
  329. pDCInfo->DcSiteName != NULL &&
  330. lstrcmpi(pwszSiteName, pDCInfo->DcSiteName) == 0) {
  331. //
  332. // DC and server are in same site. Propagate to DC.
  333. //
  334. // Create DC name copy so the info struct can be freed.
  335. //
  336. if (pDCInfo->DomainControllerName != NULL) {
  337. cch = lstrlen(pDCInfo->DomainControllerName) + 1;
  338. pwszPropagationTarget = LocalAlloc(
  339. LPTR,
  340. cch * sizeof(TCHAR));
  341. if (pwszPropagationTarget != NULL) {
  342. hr = StringCchCopy(pwszPropagationTarget,
  343. cch,
  344. pDCInfo->DomainControllerName);
  345. ASSERT(SUCCEEDED(hr));
  346. }
  347. else {
  348. #if DBG
  349. dprintf(TEXT("LLS: DC name allocation failure\n"));
  350. #endif
  351. goto CleanExit;
  352. }
  353. }
  354. }
  355. else {
  356. //
  357. // DC is in another site. Propagate to the site server.
  358. //
  359. if ((NULL == pwszSiteServer)
  360. && (NULL != pwszSiteName)) {
  361. //
  362. // No value found in registry, try Active Directory
  363. //
  364. fSiteServerFromRegistry = FALSE;
  365. GetSiteServer(szDomain, pwszSiteName, fIsDC, &pwszSiteServer);
  366. }
  367. pwszPropagationTarget = pwszSiteServer;
  368. }
  369. }
  370. else {
  371. //
  372. // Standalone server. Propagate directly to the enterprise
  373. // server
  374. //
  375. pwszPropagationTarget = GetEnterpriseServerFromRegistry();
  376. if (pwszPropagationTarget == NULL)
  377. {
  378. //
  379. // Don't have an enterprise server, try site server
  380. //
  381. pwszPropagationTarget = pwszSiteServer;
  382. }
  383. }
  384. //
  385. // Update ConfigInfo fields from information obtained above.
  386. //
  387. RtlEnterCriticalSection(&ConfigInfoLock);
  388. //
  389. // Check if the propagation target is actually this
  390. // machine. i.e., this is the site server.
  391. //
  392. if ((pwszPropagationTarget != NULL) && (*pwszPropagationTarget != 0)) {
  393. if (CompareMachineName(pwszPropagationTarget,
  394. ConfigInfo.ComputerName)) {
  395. //
  396. // This is the site server - don't propagate.
  397. //
  398. if (pwszPropagationTarget != pwszSiteServer) {
  399. LocalFree(pwszPropagationTarget);
  400. }
  401. pwszPropagationTarget = NULL; // For free below.
  402. ConfigInfo.IsMaster = TRUE;
  403. ConfigInfo.Replicate = FALSE;
  404. }
  405. }
  406. //
  407. // Update the SiteServer ConfigInfo field.
  408. //
  409. if (pwszSiteServer != NULL) {
  410. if (ConfigInfo.SiteServer != ConfigInfo.ReplicateTo) {
  411. LocalFree(ConfigInfo.SiteServer);
  412. }
  413. ConfigInfo.SiteServer = pwszSiteServer;
  414. pwszSiteServer = NULL; // For free below.
  415. //
  416. // Update the site related registry values.
  417. //
  418. if (!fSiteServerFromRegistry) {
  419. SetSiteRegistrySettings(ConfigInfo.SiteServer);
  420. }
  421. }
  422. //
  423. // Update the ReplicateTo ConfigInfo field.
  424. //
  425. if ((pwszPropagationTarget != NULL) && (*pwszPropagationTarget != 0)) {
  426. //
  427. // This server is propgagating to the site server or the DC.
  428. //
  429. ConfigInfo.IsMaster = FALSE;
  430. ConfigInfo.Replicate = TRUE;
  431. if ((ConfigInfo.ReplicateTo != NULL) && (ConfigInfo.ReplicateTo != ConfigInfo.SiteServer)) {
  432. LocalFree(ConfigInfo.ReplicateTo);
  433. }
  434. ConfigInfo.ReplicateTo = pwszPropagationTarget;
  435. pwszPropagationTarget = NULL; // For free below.
  436. }
  437. else if (!ConfigInfo.IsMaster) {
  438. //
  439. // Standalone server, and Site Server not specified in registry.
  440. // Do not replicate.
  441. //
  442. ConfigInfo.IsMaster = FALSE;
  443. ConfigInfo.Replicate = FALSE;
  444. }
  445. //
  446. // Update remaining ConfigInfo fields from registry.
  447. //
  448. // NB : Hardcode to *always* use the enterprise - new with NT 5.0.
  449. //
  450. ConfigInfo.UseEnterprise = 1;
  451. ReplicationTime = ConfigInfo.ReplicationTime;
  452. ReplicationType = ConfigInfo.ReplicationType;
  453. ConfigInfoRegistryInit( &ConfigInfo.ReplicationType,
  454. &ConfigInfo.ReplicationTime,
  455. &ConfigInfo.LogLevel,
  456. &ConfigInfo.PerServerCapacityWarning );
  457. //
  458. // Finally, adjust replication time if it has changed
  459. //
  460. if ((ReplicationTime != ConfigInfo.ReplicationTime)
  461. || (ReplicationType != ConfigInfo.ReplicationType)) {
  462. ReplicationTimeSet();
  463. }
  464. IsMaster = ConfigInfo.IsMaster;
  465. RtlLeaveCriticalSection(&ConfigInfoLock);
  466. CleanExit:
  467. if (pDCInfoLocal != NULL) {
  468. NetApiBufferFree(pDCInfoLocal); // Allocated from DsGetDcName
  469. }
  470. if (pwszSiteName != NULL) { // Allocated from DsGetSiteName
  471. NetApiBufferFree(pwszSiteName);
  472. }
  473. if (pwszSiteServer != NULL && pwszSiteServer == pwszPropagationTarget) {
  474. LocalFree(pwszSiteServer);
  475. pwszPropagationTarget = NULL;
  476. }
  477. if (pwszPropagationTarget != NULL) {
  478. LocalFree(pwszPropagationTarget);
  479. }
  480. }
  481. /////////////////////////////////////////////////////////////////////////
  482. BOOL
  483. IsDC(
  484. VOID
  485. )
  486. /*++
  487. Routine Description:
  488. Arguments:
  489. Return Value:
  490. --*/
  491. {
  492. NT_PRODUCT_TYPE NtType;
  493. //
  494. // If we aren't a DC, then count us as a member
  495. //
  496. NtType = NtProductLanManNt;
  497. RtlGetNtProductType(&NtType);
  498. if (NtType != NtProductLanManNt)
  499. return(FALSE);
  500. else {
  501. return(TRUE);
  502. }
  503. }
  504. /////////////////////////////////////////////////////////////////////////
  505. NTSTATUS
  506. ConfigInfoInit( )
  507. /*++
  508. Routine Description:
  509. Arguments:
  510. Return Value:
  511. --*/
  512. {
  513. DWORD Size;
  514. TCHAR DataPath[MAX_PATH + 1];
  515. NTSTATUS status;
  516. HRESULT hr;
  517. size_t cb;
  518. DWORD cch;
  519. //
  520. // First zero init the memory
  521. //
  522. memset(&ConfigInfo, 0, sizeof(ConfigInfo));
  523. ConfigInfo.ComputerName = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(TCHAR));
  524. ConfigInfo.ReplicateTo = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 3) * sizeof(TCHAR));
  525. ConfigInfo.EnterpriseServer = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 3) * sizeof(TCHAR));
  526. cch = MAX_PATH + 1;
  527. ConfigInfo.SystemDir = LocalAlloc(LPTR, cch * sizeof(TCHAR));
  528. if ((ConfigInfo.ComputerName == NULL) || (ConfigInfo.ReplicateTo == NULL) || (ConfigInfo.EnterpriseServer == NULL) || (ConfigInfo.SystemDir == NULL) ) {
  529. ASSERT(FALSE);
  530. }
  531. ConfigInfo.Version = INTERNAL_VERSION;
  532. GetLocalTime(&ConfigInfo.Started);
  533. //
  534. // LastReplicated is just for display, LlsReplTime is what is used to
  535. // Calculate it.
  536. GetLocalTime(&ConfigInfo.LastReplicated);
  537. ConfigInfo.LastReplicatedSeconds = DateSystemGet();
  538. if (ConfigInfo.SystemDir != NULL)
  539. {
  540. //swi, code review, no return check?
  541. GetSystemDirectory(ConfigInfo.SystemDir, cch);
  542. hr = StringCchCat(ConfigInfo.SystemDir, cch, TEXT("\\"));
  543. ASSERT(SUCCEEDED(hr));
  544. }
  545. ConfigInfo.IsMaster = FALSE;
  546. ConfigInfo.Replicate = FALSE;
  547. ConfigInfo.IsReplicating = FALSE;
  548. ConfigInfo.PerServerCapacityWarning = TRUE;
  549. ConfigInfo.ReplicationType = REPLICATE_DELTA;
  550. ConfigInfo.ReplicationTime = DEFAULT_REPLICATION_TIME;
  551. if (ConfigInfo.ComputerName != NULL)
  552. {
  553. Size = MAX_COMPUTERNAME_LENGTH + 1;
  554. GetComputerName(ConfigInfo.ComputerName, &Size);
  555. }
  556. status = RtlInitializeCriticalSection(&ConfigInfoLock);
  557. if (!NT_SUCCESS(status))
  558. return status;
  559. ConfigInfo.LogLevel = 0;
  560. if (ConfigInfo.SystemDir != NULL)
  561. {
  562. //
  563. // Create File paths
  564. //
  565. cb = sizeof(MappingFileName);
  566. hr = StringCbCopy(MappingFileName, cb, ConfigInfo.SystemDir);
  567. ASSERT(SUCCEEDED(hr));
  568. hr = StringCbCat(MappingFileName, cb, TEXT(LLS_FILE_SUBDIR));
  569. ASSERT(SUCCEEDED(hr));
  570. hr = StringCbCat(MappingFileName, cb, TEXT("\\"));
  571. ASSERT(SUCCEEDED(hr));
  572. hr = StringCbCat(MappingFileName, cb, TEXT(MAP_FILE_NAME));
  573. ASSERT(SUCCEEDED(hr));
  574. cb = sizeof(UserFileName);
  575. hr = StringCbCopy(UserFileName, cb, ConfigInfo.SystemDir);
  576. ASSERT(SUCCEEDED(hr));
  577. hr = StringCbCat(UserFileName, cb, TEXT(LLS_FILE_SUBDIR));
  578. ASSERT(SUCCEEDED(hr));
  579. hr = StringCbCat(UserFileName, cb, TEXT("\\"));
  580. ASSERT(SUCCEEDED(hr));
  581. hr = StringCbCat(UserFileName, cb, TEXT(USER_FILE_NAME));
  582. ASSERT(SUCCEEDED(hr));
  583. cb = sizeof(CertDbFileName);
  584. hr = StringCbCopy(CertDbFileName, cb, ConfigInfo.SystemDir);
  585. ASSERT(SUCCEEDED(hr));
  586. hr = StringCbCat(CertDbFileName, cb, TEXT(LLS_FILE_SUBDIR));
  587. ASSERT(SUCCEEDED(hr));
  588. hr = StringCbCat(CertDbFileName, cb, TEXT("\\"));
  589. ASSERT(SUCCEEDED(hr));
  590. hr = StringCbCat(CertDbFileName, cb, TEXT(CERT_DB_FILE_NAME));
  591. ASSERT(SUCCEEDED(hr));
  592. cb = sizeof(LicenseFileName);
  593. hr = StringCbCopy(LicenseFileName, cb, ConfigInfo.SystemDir);
  594. ASSERT(SUCCEEDED(hr));
  595. hr = StringCbCat(LicenseFileName, cb, TEXT(LICENSE_FILE_NAME));
  596. ASSERT(SUCCEEDED(hr));
  597. //
  598. // Make sure our directory is there.
  599. //
  600. cb = sizeof(DataPath);
  601. hr = StringCbCopy(DataPath, cb, ConfigInfo.SystemDir);
  602. ASSERT(SUCCEEDED(hr));
  603. hr = StringCbCat(DataPath, cb, TEXT(LLS_FILE_SUBDIR));
  604. ASSERT(SUCCEEDED(hr));
  605. CreateDirectory(DataPath, NULL);
  606. } else
  607. {
  608. MappingFileName[0] = 0;
  609. UserFileName[0] = 0;
  610. CertDbFileName[0] = 0;
  611. LicenseFileName[0] = 0;
  612. }
  613. return STATUS_SUCCESS;
  614. } // ConfigInfoInit
  615. /////////////////////////////////////////////////////////////////////////
  616. DWORD WINAPI
  617. LLSTopLevelExceptionHandler(
  618. struct _EXCEPTION_POINTERS *ExceptionInfo
  619. )
  620. /*++
  621. Routine Description:
  622. The Top Level exception filter for LLSMain.exe.
  623. This ensures the entire process will be cleaned up if any of
  624. the threads fail. Since LLSMain.exe is a distributed application,
  625. it is better to fail the entire process than allow random threads
  626. to continue executing.
  627. Arguments:
  628. ExceptionInfo - Identifies the exception that occurred.
  629. Return Values:
  630. EXCEPTION_EXECUTE_HANDLER - Terminate the process.
  631. EXCEPTION_CONTINUE_SEARCH - Continue processing as though this filter
  632. was never called.
  633. --*/
  634. {
  635. HANDLE hModule;
  636. //
  637. // Raise an alert
  638. //
  639. hModule = LoadLibraryA("netapi32");
  640. if ( hModule != NULL ) {
  641. NET_API_STATUS (NET_API_FUNCTION *NetAlertRaiseExFunction)
  642. (LPTSTR, LPVOID, DWORD, LPTSTR);
  643. NetAlertRaiseExFunction =
  644. (NET_API_STATUS (NET_API_FUNCTION *) (LPTSTR, LPVOID, DWORD, LPTSTR))
  645. GetProcAddress(hModule, "NetAlertRaiseEx");
  646. if ( NetAlertRaiseExFunction != NULL ) {
  647. NTSTATUS Status;
  648. UNICODE_STRING Strings;
  649. char message[ALERTSZ + sizeof(ADMIN_OTHER_INFO)];
  650. PADMIN_OTHER_INFO admin = (PADMIN_OTHER_INFO) message;
  651. //
  652. // Build the variable data
  653. //
  654. admin->alrtad_errcode = ALERT_UnhandledException;
  655. admin->alrtad_numstrings = 0;
  656. Strings.Buffer = (LPWSTR) ALERT_VAR_DATA(admin);
  657. Strings.Length = 0;
  658. Strings.MaximumLength = ALERTSZ;
  659. ASSERT(NULL != ExceptionInfo);
  660. Status = RtlIntegerToUnicodeString(
  661. (ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode,
  662. 16,
  663. &Strings );
  664. if ( NT_SUCCESS(Status) ) {
  665. if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
  666. Status = STATUS_BUFFER_TOO_SMALL;
  667. } else {
  668. admin->alrtad_numstrings++;
  669. *(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
  670. Strings.Length += sizeof(WCHAR);
  671. Status = RtlAppendUnicodeToString( &Strings, L"LLS" );
  672. }
  673. }
  674. if ( NT_SUCCESS(Status) ) {
  675. if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
  676. Status = STATUS_BUFFER_TOO_SMALL;
  677. } else {
  678. admin->alrtad_numstrings++;
  679. *(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
  680. Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1;
  681. Strings.MaximumLength -= Strings.Length + sizeof(WCHAR);
  682. Strings.Length = 0;
  683. Status = RtlIntPtrToUnicodeString(
  684. (ULONG_PTR)(ExceptionInfo->ExceptionRecord->ExceptionAddress),
  685. 16,
  686. &Strings );
  687. }
  688. }
  689. if ( NT_SUCCESS(Status) ) {
  690. if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) {
  691. Status = STATUS_BUFFER_TOO_SMALL;
  692. } else {
  693. admin->alrtad_numstrings++;
  694. *(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0';
  695. Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1;
  696. (VOID) (*NetAlertRaiseExFunction)(
  697. ALERT_ADMIN_EVENT,
  698. message,
  699. (DWORD)((PCHAR)Strings.Buffer -
  700. (PCHAR)message),
  701. L"LLS" );
  702. }
  703. }
  704. }
  705. (VOID) FreeLibrary( hModule );
  706. }
  707. //
  708. // Just continue processing the exception.
  709. //
  710. return EXCEPTION_CONTINUE_SEARCH;
  711. } // LLSTopLevelExceptionHandler
  712. DWORD
  713. ServiceStartDelayed(
  714. )
  715. /*++
  716. Routine Description:
  717. Do the stuff that used to be done at service startup time,
  718. but can wait until the first RPC.
  719. Arguments:
  720. None.
  721. Return Values:
  722. None.
  723. --*/
  724. {
  725. NTSTATUS dwErr = STATUS_SUCCESS;
  726. //
  727. // SBS mods (bug# 505640), locals for per server licensing hotfix
  728. //
  729. OSVERSIONINFOEX VersionInfo = {sizeof(OSVERSIONINFOEX)};
  730. //
  731. // end SBS mods
  732. //
  733. dwErr = RtlInitializeCriticalSection(&MappingFileLock);
  734. if (!NT_SUCCESS(dwErr))
  735. goto Cleanup;
  736. dwErr = RtlInitializeCriticalSection(&UserFileLock);
  737. if (!NT_SUCCESS(dwErr))
  738. goto Cleanup;
  739. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  740. //
  741. // Create the FilePrint table
  742. //
  743. dwErr = FilePrintTableInit();
  744. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  745. if (!NT_SUCCESS(dwErr))
  746. goto Cleanup;
  747. // Initialize the Service Table
  748. dwErr = LicenseListInit();
  749. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  750. if (!NT_SUCCESS(dwErr))
  751. goto Cleanup;
  752. dwErr = MasterServiceListInit();
  753. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  754. if (!NT_SUCCESS(dwErr))
  755. goto Cleanup;
  756. dwErr = LocalServiceListInit();
  757. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  758. if (!NT_SUCCESS(dwErr))
  759. goto Cleanup;
  760. dwErr = ServiceListInit();
  761. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  762. if (!NT_SUCCESS(dwErr))
  763. goto Cleanup;
  764. dwErr = MappingListInit();
  765. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  766. if (!NT_SUCCESS(dwErr))
  767. goto Cleanup;
  768. // Initialize the Per-Seat Table
  769. dwErr = UserListInit();
  770. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  771. if (!NT_SUCCESS(dwErr))
  772. goto Cleanup;
  773. // Initialize the Service Table
  774. dwErr = ServerListInit();
  775. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  776. if (!NT_SUCCESS(dwErr))
  777. goto Cleanup;
  778. // Initialize the Certificate Database
  779. dwErr = CertDbInit();
  780. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  781. if (!NT_SUCCESS(dwErr))
  782. goto Cleanup;
  783. // Load data files
  784. LoadAll();
  785. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  786. //
  787. // SBS mods (bug# 505640) - initialization for per server licensing problem hotfix
  788. //
  789. // ensure that our QFE only runs on SBS.
  790. if (GetVersionEx((LPOSVERSIONINFO)&VersionInfo) &&
  791. (VersionInfo.wSuiteMask & (VER_SUITE_SMALLBUSINESS_RESTRICTED | VER_SUITE_SMALLBUSINESS))) {
  792. SBSPerServerHotfix = TRUE;
  793. RtlInitializeCriticalSection(&PerServerListLock);
  794. // This next is probably unneccessary, but certainly won't hurt anything.
  795. ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
  796. }
  797. //
  798. // end SBS mods
  799. //
  800. Cleanup:
  801. return dwErr;
  802. }
  803. DWORD
  804. EnsureInitialized (
  805. VOID
  806. )
  807. {
  808. DWORD dwErr;
  809. // Most common case is we're already initialized. Perform a quick
  810. // check for this.
  811. //
  812. if (g_fInitializationComplete)
  813. {
  814. return NOERROR;
  815. }
  816. dwErr = NOERROR;
  817. // Make no assumptions about how many threads may be trying to
  818. // initialize us at the same time.
  819. //
  820. RtlEnterCriticalSection (&g_csLock);
  821. // Need to re-check after acquiring the lock because another thread
  822. // may have just finished initializing and released the lock allowing
  823. // us to get it.
  824. //
  825. if ((!g_fInitializationComplete) && (!g_fDoingInitialization))
  826. {
  827. // set this now so this thread can't call ServiceStartDelayed twice
  828. g_fDoingInitialization = TRUE;
  829. dwErr = ServiceStartDelayed();
  830. g_fInitializationComplete = TRUE;
  831. }
  832. RtlLeaveCriticalSection (&g_csLock);
  833. return dwErr;
  834. }
  835. /////////////////////////////////////////////////////////////////////////
  836. VOID
  837. ServiceStart (
  838. DWORD dwArgc,
  839. LPTSTR *lpszArgv
  840. )
  841. /*++
  842. Routine Description:
  843. The code that starts everything, is really the main().
  844. Arguments:
  845. None. *** argc and argv unused ***
  846. Return Values:
  847. None.
  848. --*/
  849. {
  850. DWORD dwWait;
  851. NTSTATUS Status = STATUS_SUCCESS;
  852. KPRIORITY BasePriority;
  853. HANDLE hThread = NULL;
  854. BOOL fCoInitialized = FALSE;
  855. LARGE_INTEGER liWait;
  856. BOOL fRet;
  857. UNREFERENCED_PARAMETER(dwArgc);
  858. UNREFERENCED_PARAMETER(lpszArgv);
  859. ///////////////////////////////////////////////////
  860. //
  861. // Service initialization
  862. //
  863. //
  864. // Report the status to the service control manager.
  865. //
  866. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  867. goto Cleanup;
  868. //
  869. // Define a top-level exception handler for the entire process.
  870. //
  871. (VOID) SetErrorMode( SEM_FAILCRITICALERRORS );
  872. //
  873. // Report the status to the service control manager.
  874. //
  875. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  876. goto Cleanup;
  877. #pragma warning (push)
  878. #pragma warning (disable : 4057) //'LPTOP_LEVEL_EXCEPTION_FILTER' differs in indirection to slightly different base types from 'DWORD (__stdcall *)(_EXCEPTION_POINTERS *)'
  879. (VOID) SetUnhandledExceptionFilter( &LLSTopLevelExceptionHandler );
  880. #pragma warning (pop)
  881. //
  882. // Run the LLS in the foreground.
  883. //
  884. // Several processes which depend on the LLS (like the lanman server)
  885. // run in the foreground. If we don't run in the foreground, they'll
  886. // starve waiting for us.
  887. //
  888. BasePriority = FOREGROUND_BASE_PRIORITY;
  889. Status = NtSetInformationProcess(
  890. NtCurrentProcess(),
  891. ProcessBasePriority,
  892. &BasePriority,
  893. sizeof(BasePriority)
  894. );
  895. // BUGBUG: ignore error for now; may be caused by running as NetworkService
  896. #if 0
  897. if (!NT_SUCCESS(Status))
  898. {
  899. goto Cleanup;
  900. }
  901. #endif
  902. //
  903. // Report the status to the service control manager.
  904. //
  905. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  906. goto Cleanup;
  907. //
  908. // Create an event to throttle ConfigInfoUpdate
  909. //
  910. g_hThrottleConfig
  911. = CreateWaitableTimer(NULL, // SecurityAttributes,
  912. FALSE, // bManualReset
  913. NULL // lpName
  914. );
  915. if (NULL == g_hThrottleConfig)
  916. {
  917. Status = GetLastError();
  918. goto Cleanup;
  919. }
  920. liWait.QuadPart = (LONGLONG) (-1); // Start immediately
  921. fRet = SetWaitableTimer(g_hThrottleConfig,
  922. &liWait,
  923. 1000*60*15, // lPeriod, 15 minutes
  924. NULL, // pfnCompletionRoutine
  925. NULL, // lpArgToCompletionRoutine
  926. FALSE // fResume (from suspended)
  927. );
  928. if (!fRet)
  929. {
  930. Status = GetLastError();
  931. goto Cleanup;
  932. }
  933. //
  934. // Create an event to throttle Per Seat purchase replication
  935. //
  936. g_hThrottleConnect
  937. = CreateWaitableTimer(NULL, // SecurityAttributes,
  938. FALSE, // bManualReset
  939. NULL // lpName
  940. );
  941. if (NULL == g_hThrottleConnect)
  942. {
  943. Status = GetLastError();
  944. goto Cleanup;
  945. }
  946. liWait.QuadPart = (LONGLONG) (-1); // Start immediately
  947. fRet = SetWaitableTimer(g_hThrottleConnect,
  948. &liWait,
  949. 1000*60*15, // lPeriod, 15 minutes
  950. NULL, // pfnCompletionRoutine
  951. NULL, // lpArgToCompletionRoutine
  952. FALSE // fResume (from suspended)
  953. );
  954. if (!fRet)
  955. {
  956. Status = GetLastError();
  957. goto Cleanup;
  958. }
  959. //
  960. // Start separate thread to contact the DS
  961. //
  962. hThread = CreateThread(NULL,
  963. 0,
  964. (LPTHREAD_START_ROUTINE) ConfigInfoInit,
  965. NULL,
  966. 0,
  967. NULL);
  968. Status = RtlInitializeCriticalSection(&g_csLock);
  969. if (!NT_SUCCESS(Status))
  970. {
  971. goto Cleanup;
  972. }
  973. //
  974. // Report the status to the service control manager.
  975. //
  976. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  977. goto Cleanup;
  978. //
  979. // Create the event object. The control handler function signals
  980. // this event when it receives the "stop" control code.
  981. //
  982. hServerStopEvent = CreateEvent(
  983. NULL, // no security attributes
  984. TRUE, // manual reset event
  985. FALSE, // not-signalled
  986. NULL); // no name
  987. if ( hServerStopEvent == NULL)
  988. goto Cleanup;
  989. //
  990. // Report the status to the service control manager.
  991. //
  992. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  993. goto Cleanup;
  994. //
  995. // Report the status to the service control manager.
  996. //
  997. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  998. goto Cleanup;
  999. // Initialize Replication...
  1000. ReplicationInit();
  1001. //
  1002. // Report the status to the service control manager.
  1003. //
  1004. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  1005. goto Cleanup;
  1006. // Initialize the Registry values...
  1007. RegistryInit();
  1008. //
  1009. // Report the status to the service control manager.
  1010. //
  1011. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  1012. goto Cleanup;
  1013. // Initialize scavenger thread...
  1014. ScavengerInit();
  1015. //
  1016. // Report the status to the service control manager.
  1017. //
  1018. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  1019. goto Cleanup;
  1020. //
  1021. // wait for ConfigInfoInit to complete before accepting clients
  1022. //
  1023. while (hThread != NULL)
  1024. {
  1025. dwWait = WaitForSingleObject(hThread,NSERVICEWAITHINT/2);
  1026. //
  1027. // Report the status to the service control manager.
  1028. //
  1029. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  1030. goto Cleanup;
  1031. if (dwWait == WAIT_OBJECT_0)
  1032. {
  1033. GetExitCodeThread(hThread, (LPDWORD)(&Status));
  1034. // Check if critsec creation failed
  1035. if (!NT_SUCCESS(Status))
  1036. goto Cleanup;
  1037. CloseHandle(hThread);
  1038. hThread = NULL;
  1039. break;
  1040. }
  1041. }
  1042. // Initialize RegistryMonitor thread...
  1043. RegistryStartMonitor();
  1044. //
  1045. // Report the status to the service control manager.
  1046. //
  1047. if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
  1048. goto Cleanup;
  1049. // Initialize COM
  1050. if (!FAILED(CoInitialize(NULL)))
  1051. {
  1052. fCoInitialized = TRUE;
  1053. }
  1054. // Do all the stuff that used to be delayed
  1055. EnsureInitialized();
  1056. // Initialize RPC Stuff... (start accepting clients)
  1057. LLSRpcInit();
  1058. //
  1059. // End of initialization
  1060. //
  1061. ////////////////////////////////////////////////////////
  1062. //
  1063. // Tell SCM we are up and running!
  1064. //
  1065. if (!ReportStatusToSCMgr( SERVICE_RUNNING, NO_ERROR, 0))
  1066. goto Cleanup;
  1067. g_fRunning = TRUE;
  1068. ////////////////////////////////////////////////////////
  1069. //
  1070. // Service is now running, perform work until shutdown
  1071. //
  1072. dwWait = WaitForSingleObject(hServerStopEvent, INFINITE);
  1073. Cleanup:
  1074. if (fCoInitialized)
  1075. CoUninitialize();
  1076. if (hThread != NULL)
  1077. CloseHandle(hThread);
  1078. if (hServerStopEvent)
  1079. CloseHandle(hServerStopEvent);
  1080. if (sshStatusHandle)
  1081. ReportStatusToSCMgr( SERVICE_STOPPED, NO_ERROR, 0);
  1082. } // ServiceStart
  1083. /////////////////////////////////////////////////////////////////////////
  1084. VOID ServiceStop()
  1085. /*++
  1086. Routine Description:
  1087. Stops the service.
  1088. If a ServiceStop procedure is going to take longer than 3 seconds to
  1089. execute, it should spawn a thread to execute the stop code, and return.
  1090. Otherwise, the ServiceControlManager will believe that the service has
  1091. stopped responding.
  1092. Arguments:
  1093. None.
  1094. Return Values:
  1095. None.
  1096. --*/
  1097. {
  1098. if ( hServerStopEvent )
  1099. SetEvent(hServerStopEvent);
  1100. } // ServiceStop
  1101. #define FIND_DNSNAME_SEPARATOR(pwsz) { \
  1102. while (*pwsz && *pwsz != TEXT('.')) { \
  1103. pwsz++; \
  1104. } \
  1105. }
  1106. /////////////////////////////////////////////////////////////////////////
  1107. VOID
  1108. DNSToFlatName(
  1109. LPCWSTR pwszDNSName,
  1110. DWORD ccBufferLen,
  1111. LPWSTR pwszBuffer
  1112. )
  1113. /*++
  1114. Routine Description:
  1115. Arguments:
  1116. pwszDNSName
  1117. ccBufferLen
  1118. pwszBuffer
  1119. Return Value:
  1120. --*/
  1121. {
  1122. LPWSTR pwszFlatName = (LPWSTR)pwszDNSName;
  1123. SIZE_T ccFlatNameLen;
  1124. ASSERT(pwszDNSName != NULL);
  1125. FIND_DNSNAME_SEPARATOR(pwszFlatName);
  1126. ccFlatNameLen = (DWORD)(pwszFlatName - pwszDNSName);
  1127. if (ccFlatNameLen && ccFlatNameLen < ccBufferLen) {
  1128. lstrcpyn(pwszBuffer, pwszDNSName, (int)ccFlatNameLen + 1);
  1129. pwszBuffer[ccFlatNameLen] = TEXT('\0');
  1130. }
  1131. else {
  1132. *pwszBuffer = TEXT('\0');
  1133. }
  1134. }
  1135. /////////////////////////////////////////////////////////////////////////
  1136. BOOL
  1137. CompareMachineName(
  1138. LPCWSTR pwszName1,
  1139. LPCWSTR pwszName2
  1140. )
  1141. /*++
  1142. Routine Description:
  1143. Arguments:
  1144. pwszName1
  1145. pwszName2
  1146. Return Value:
  1147. TRUE -- The names match.
  1148. FALSE -- Otherwise.
  1149. --*/
  1150. {
  1151. TCHAR szFlatName[MAX_COMPUTERNAME_LENGTH + 3];
  1152. LPWSTR pwszTmp1 = (LPWSTR)pwszName1;
  1153. LPWSTR pwszTmp2 = (LPWSTR)pwszName2;
  1154. if (pwszName1 == NULL || pwszName2 == NULL) {
  1155. return FALSE;
  1156. }
  1157. //
  1158. // Identify if both/either name are DNS names by checking for the
  1159. // existence of a '.' separator.
  1160. //
  1161. FIND_DNSNAME_SEPARATOR(pwszTmp1);
  1162. FIND_DNSNAME_SEPARATOR(pwszTmp2);
  1163. if ((*pwszTmp1 && *pwszTmp2) || (!*pwszTmp1 && !*pwszTmp2)) {
  1164. //
  1165. // Non-differing name types. Both are either DNS or flat.
  1166. //
  1167. return (lstrcmpi(pwszName1, pwszName2) == 0);
  1168. }
  1169. else if (*pwszTmp1) {
  1170. //
  1171. // Name 1 is DNS, name 2 is flat.
  1172. // Convert DNS to flat, then compare.
  1173. //
  1174. DNSToFlatName(pwszName1,
  1175. MAX_COMPUTERNAME_LENGTH + 3,
  1176. szFlatName);
  1177. return (lstrcmpi(szFlatName, pwszName2) == 0);
  1178. }
  1179. else {
  1180. //
  1181. // Name 2 is DNS, name 1 is flat.
  1182. // Convert DNS to flat, then compare.
  1183. //
  1184. DNSToFlatName(pwszName2,
  1185. MAX_COMPUTERNAME_LENGTH + 3,
  1186. szFlatName);
  1187. return (lstrcmpi(szFlatName, pwszName1) == 0);
  1188. }
  1189. }
  1190. #define REG_LS_PARAMETERS \
  1191. TEXT("System\\CurrentControlSet\\Services\\LicenseService\\Parameters")
  1192. #define REG_LS_SITESERVER \
  1193. TEXT("SiteServer")
  1194. #define REG_LS_ENTERPRISESERVER \
  1195. TEXT("EnterpriseServer")
  1196. #define REG_LS_USEENTERPRISE \
  1197. TEXT("UseEnterprise")
  1198. /////////////////////////////////////////////////////////////////////////
  1199. LPWSTR
  1200. GetSiteServerFromRegistry(
  1201. VOID
  1202. )
  1203. /*++
  1204. Routine Description:
  1205. Arguments:
  1206. None.
  1207. Return Value:
  1208. --*/
  1209. {
  1210. HKEY hKey = NULL;
  1211. DWORD dwType, dwSize;
  1212. LPWSTR pwszSiteServer = NULL;
  1213. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1214. REG_LS_PARAMETERS,
  1215. 0,
  1216. KEY_READ,
  1217. &hKey) == ERROR_SUCCESS) {
  1218. //
  1219. // Allocate SiteServer on the heap since it could be quite large.
  1220. //
  1221. dwSize = 0;
  1222. if (RegQueryValueEx(hKey,
  1223. REG_LS_SITESERVER,
  1224. NULL,
  1225. &dwType,
  1226. (LPBYTE)NULL,
  1227. &dwSize) == ERROR_SUCCESS)
  1228. {
  1229. // Bug# 685884
  1230. // dwSize is always 2 sizeof(WCHAR)(for unicode null character) even if the key is empty.
  1231. // Allocate only if dwSize > 2
  1232. if(dwSize > sizeof(WCHAR))
  1233. {
  1234. pwszSiteServer = LocalAlloc(LPTR, dwSize);
  1235. if (pwszSiteServer != NULL) {
  1236. if (RegQueryValueEx(hKey,
  1237. REG_LS_SITESERVER,
  1238. NULL,
  1239. &dwType,
  1240. (LPBYTE)pwszSiteServer,
  1241. &dwSize) != ERROR_SUCCESS) {
  1242. LocalFree(pwszSiteServer);
  1243. pwszSiteServer = NULL;
  1244. }
  1245. }
  1246. }
  1247. }
  1248. RegCloseKey(hKey);
  1249. }
  1250. return pwszSiteServer;
  1251. }
  1252. /////////////////////////////////////////////////////////////////////////
  1253. LPWSTR
  1254. GetEnterpriseServerFromRegistry(
  1255. VOID
  1256. )
  1257. /*++
  1258. Routine Description:
  1259. Arguments:
  1260. None.
  1261. Return Value:
  1262. --*/
  1263. {
  1264. HKEY hKey = NULL;
  1265. DWORD dwType, dwSize;
  1266. LPWSTR pwszEnterpriseServer = NULL;
  1267. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1268. REG_LS_PARAMETERS,
  1269. 0,
  1270. KEY_READ,
  1271. &hKey) == ERROR_SUCCESS) {
  1272. //
  1273. // Allocate EnterpriseServer on the heap since it could be quite large.
  1274. //
  1275. dwSize = 0;
  1276. if (RegQueryValueEx(hKey,
  1277. REG_LS_ENTERPRISESERVER,
  1278. NULL,
  1279. &dwType,
  1280. (LPBYTE)NULL,
  1281. &dwSize) == ERROR_SUCCESS)
  1282. {
  1283. pwszEnterpriseServer = LocalAlloc(LPTR, dwSize);
  1284. if (pwszEnterpriseServer != NULL) {
  1285. if (RegQueryValueEx(hKey,
  1286. REG_LS_ENTERPRISESERVER,
  1287. NULL,
  1288. &dwType,
  1289. (LPBYTE)pwszEnterpriseServer,
  1290. &dwSize) != ERROR_SUCCESS) {
  1291. LocalFree(pwszEnterpriseServer);
  1292. pwszEnterpriseServer = NULL;
  1293. }
  1294. }
  1295. }
  1296. RegCloseKey(hKey);
  1297. }
  1298. return pwszEnterpriseServer;
  1299. }
  1300. /////////////////////////////////////////////////////////////////////////
  1301. VOID
  1302. SetSiteRegistrySettings(
  1303. LPCWSTR pwszSiteServer
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. Arguments:
  1308. pwszSiteServer
  1309. Return Value:
  1310. --*/
  1311. {
  1312. HKEY hKey;
  1313. DWORD dwSize;
  1314. DWORD dwType = REG_SZ;
  1315. ASSERT(pwszSiteServer != NULL);
  1316. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1317. REG_LS_PARAMETERS,
  1318. 0,
  1319. KEY_WRITE,
  1320. &hKey) == ERROR_SUCCESS) {
  1321. //
  1322. // Write the SiteServer value.
  1323. //
  1324. dwSize = (lstrlen(pwszSiteServer) + 1) * sizeof(TCHAR);
  1325. RegSetValueEx(hKey,
  1326. REG_LS_SITESERVER,
  1327. 0,
  1328. dwType,
  1329. (LPBYTE)pwszSiteServer,
  1330. dwSize);
  1331. RegCloseKey(hKey);
  1332. }
  1333. }
  1334. //
  1335. // Pre-fill the ADSI cache with only the attribute we want, then get it
  1336. // Only use if exactly one attribute is needed
  1337. //
  1338. HRESULT
  1339. GetWithGetInfoEx(
  1340. IADs *pADs,
  1341. LPWSTR wszAttribute,
  1342. VARIANT *pvar
  1343. )
  1344. {
  1345. HRESULT hr;
  1346. ASSERT(NULL != wszAttribute);
  1347. hr = ADsBuildVarArrayStr( &wszAttribute, 1, pvar );
  1348. if( SUCCEEDED( hr ) )
  1349. {
  1350. hr = IADs_GetInfoEx( pADs, *pvar, 0L );
  1351. VariantClear( pvar );
  1352. if (SUCCEEDED(hr))
  1353. {
  1354. hr = IADs_Get( pADs, wszAttribute, pvar );
  1355. }
  1356. }
  1357. return hr;
  1358. }
  1359. //
  1360. // Pre-fill the ADSI cache with only the attributes we want, then get them
  1361. // Only use if exactly two attributes are needed
  1362. //
  1363. HRESULT
  1364. GetWithGetInfoEx2(
  1365. IADs *pADs,
  1366. LPWSTR wszAttribute1,
  1367. LPWSTR wszAttribute2,
  1368. VARIANT *pvar1,
  1369. VARIANT *pvar2,
  1370. HRESULT * phr2
  1371. )
  1372. {
  1373. HRESULT hr;
  1374. #pragma warning (push)
  1375. #pragma warning (disable : 4204) // following init violates W4, nonstandard extension used : non-constant aggregate initializer
  1376. LPWSTR rgwszAttributes[] = {wszAttribute1,wszAttribute2};
  1377. #pragma warning (pop)
  1378. hr = ADsBuildVarArrayStr( rgwszAttributes, 2, pvar1 );
  1379. if( SUCCEEDED( hr ) )
  1380. {
  1381. hr = IADs_GetInfoEx( pADs, *pvar1, 0L );
  1382. VariantClear( pvar1 );
  1383. if (SUCCEEDED(hr))
  1384. {
  1385. hr = IADs_Get( pADs, wszAttribute1, pvar1 );
  1386. if (SUCCEEDED(hr))
  1387. {
  1388. *phr2 = IADs_Get( pADs, wszAttribute2, pvar2 );
  1389. }
  1390. }
  1391. }
  1392. return hr;
  1393. }
  1394. #define CWSTR_SIZE(x) (sizeof(x) - (sizeof(WCHAR) * 2))
  1395. #define DWSTR_SIZE(x) ((wcslen(x) + 1) * sizeof(WCHAR))
  1396. #define ROOT_DSE_PATH L"LDAP://RootDSE"
  1397. #define CONFIG_CNTNR L"ConfigurationNamingContext"
  1398. #define SITE_SERVER L"siteServer"
  1399. #define DNS_MACHINE_NAME L"dNSHostName"
  1400. #define IS_DELETED L"isDeleted"
  1401. /////////////////////////////////////////////////////////////////////////
  1402. HRESULT
  1403. GetSiteServer(
  1404. LPCWSTR pwszDomain,
  1405. LPCWSTR pwszSiteName,
  1406. BOOL fIsDC,
  1407. LPWSTR * ppwszSiteServer
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. Arguments:
  1412. pwszSiteName
  1413. fIsDC
  1414. ppwszSiteServer
  1415. Return Value:
  1416. --*/
  1417. {
  1418. LPWSTR pwszDN = NULL;
  1419. LPWSTR pwszConfigContainer;
  1420. LPWSTR pwszBindPath;
  1421. IADs * pADs = NULL;
  1422. IADs * pADs2 = NULL;
  1423. IADs * pADs3 = NULL;
  1424. DS_NAME_RESULT * pDsResult = NULL;
  1425. VARIANT var;
  1426. VARIANT var2;
  1427. HRESULT hr, hr2;
  1428. DWORD dwRet = 0;
  1429. BOOL fAlreadyTookSiteServer = FALSE;
  1430. BOOL fCoInitialized = FALSE;
  1431. size_t cb, cch;
  1432. ASSERT(pwszSiteName != NULL);
  1433. ASSERT(ppwszSiteServer != NULL);
  1434. *ppwszSiteServer = NULL;
  1435. VariantInit(&var);
  1436. VariantInit(&var2);
  1437. hr = CoInitialize(NULL);
  1438. if (FAILED(hr)) {
  1439. ERR(hr);
  1440. goto CleanExit;
  1441. }
  1442. fCoInitialized = TRUE;
  1443. //
  1444. // Obtain the path to the configuration container.
  1445. //
  1446. hr = ADsGetObject(ROOT_DSE_PATH, &IID_IADs, (void **)&pADs);
  1447. if (FAILED(hr)) {
  1448. ERR(hr);
  1449. goto CleanExit;
  1450. }
  1451. hr = IADs_Get(pADs, CONFIG_CNTNR, &var);
  1452. if (FAILED(hr)) {
  1453. ERR(hr);
  1454. goto CleanExit;
  1455. }
  1456. if (V_VT(&var) != VT_BSTR) {
  1457. ASSERT(V_VT(&var) == VT_BSTR);
  1458. dwRet = ERROR_INVALID_DATA;
  1459. ERR(dwRet);
  1460. goto CleanExit;
  1461. }
  1462. pwszConfigContainer = var.bstrVal; // For sake of readability.
  1463. //
  1464. // Bind to the license settings object.
  1465. //
  1466. hr = GetLicenseSettingsObject(pwszSiteName,
  1467. pwszConfigContainer,
  1468. &pADs2);
  1469. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT)) {
  1470. //
  1471. // The license settings object doesn't exist. Create it.
  1472. //
  1473. hr = CreateLicenseSettingsObject(pwszSiteName,
  1474. pwszConfigContainer,
  1475. &pADs2);
  1476. }
  1477. if (FAILED(hr)) {
  1478. //
  1479. // Failed to bind or create the license settings object.
  1480. //
  1481. goto CleanExit;
  1482. }
  1483. ASSERT(pADs2 != NULL);
  1484. //
  1485. // Consult the site server property on the license settings object.
  1486. // It's a DN to the machine object of the site server.
  1487. //
  1488. VariantClear(&var);
  1489. hr = GetWithGetInfoEx(pADs2, SITE_SERVER, &var);
  1490. //
  1491. // If the site server property has not been set and this server
  1492. // is a DC, designate this server as the site server.
  1493. //
  1494. if (hr == E_ADS_PROPERTY_NOT_FOUND && fIsDC) {
  1495. dwRet = BecomeSiteServer(&pDsResult,pADs2,&pwszDN,pwszDomain);
  1496. if (dwRet)
  1497. goto CleanExit;
  1498. }
  1499. else if (SUCCEEDED(hr)) {
  1500. if (V_VT(&var) != VT_BSTR) {
  1501. ASSERT(V_VT(&var) == VT_BSTR);
  1502. dwRet = ERROR_INVALID_DATA;
  1503. ERR(dwRet);
  1504. goto CleanExit;
  1505. }
  1506. pwszDN = V_BSTR(&var);
  1507. }
  1508. else {
  1509. goto CleanExit;
  1510. }
  1511. TryNewSiteServer:
  1512. //
  1513. // Bind to the computer object referenced by the Site-Server property.
  1514. //
  1515. if (pwszDN == NULL)
  1516. {
  1517. hr = E_FAIL;
  1518. ERR(hr);
  1519. goto CleanExit;
  1520. }
  1521. // LDAP:// + pwszDN + 1
  1522. cch = wcslen(pwszDN) + 8;
  1523. pwszBindPath = LocalAlloc(LPTR,
  1524. cch * sizeof(WCHAR));
  1525. if (pwszBindPath == NULL) {
  1526. hr = E_OUTOFMEMORY;
  1527. ERR(hr);
  1528. goto CleanExit;
  1529. }
  1530. hr = StringCchPrintf(pwszBindPath, cch, L"LDAP://%ws", pwszDN);
  1531. ASSERT(SUCCEEDED(hr));
  1532. hr = ADsOpenObject(pwszBindPath,
  1533. NULL,
  1534. NULL,
  1535. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND | ADS_SERVER_BIND,
  1536. &IID_IADs,
  1537. (void **)&pADs3);
  1538. LocalFree(pwszBindPath);
  1539. if (FAILED(hr)) {
  1540. if (fIsDC && !fAlreadyTookSiteServer)
  1541. {
  1542. //
  1543. // Existing SiteServer is gone, claim it
  1544. //
  1545. if (pDsResult != NULL) {
  1546. DsFreeNameResult(pDsResult);
  1547. }
  1548. dwRet = BecomeSiteServer(&pDsResult,pADs2,&pwszDN,pwszDomain);
  1549. if (dwRet)
  1550. {
  1551. goto CleanExit;
  1552. }
  1553. else
  1554. {
  1555. fAlreadyTookSiteServer = TRUE;
  1556. if (pADs3 != NULL) {
  1557. IADs_Release(pADs3);
  1558. }
  1559. goto TryNewSiteServer;
  1560. }
  1561. } else
  1562. {
  1563. ERR(hr);
  1564. goto CleanExit;
  1565. }
  1566. }
  1567. //
  1568. // Fetch the Machine-DNS-Name property.
  1569. //
  1570. VariantClear(&var);
  1571. hr = GetWithGetInfoEx2(pADs3, DNS_MACHINE_NAME, IS_DELETED, &var, &var2, &hr2);
  1572. if (FAILED(hr)) {
  1573. ERR(hr);
  1574. goto CleanExit;
  1575. }
  1576. if (SUCCEEDED(hr2))
  1577. {
  1578. hr = VariantChangeType(&var2,&var2,0,VT_BOOL);
  1579. if (FAILED(hr)) {
  1580. ERR(hr);
  1581. goto CleanExit;
  1582. }
  1583. if (V_BOOL(&var2))
  1584. {
  1585. // object has been deleted - pretend it isn't set
  1586. hr = E_ADS_PROPERTY_NOT_SET;
  1587. if (fIsDC && !fAlreadyTookSiteServer)
  1588. {
  1589. //
  1590. // Existing SiteServer is gone, claim it
  1591. //
  1592. if (pDsResult != NULL) {
  1593. DsFreeNameResult(pDsResult);
  1594. }
  1595. dwRet = BecomeSiteServer(&pDsResult,pADs2,&pwszDN,pwszDomain);
  1596. if (dwRet)
  1597. {
  1598. goto CleanExit;
  1599. }
  1600. else
  1601. {
  1602. fAlreadyTookSiteServer = TRUE;
  1603. if (pADs3 != NULL) {
  1604. IADs_Release(pADs3);
  1605. }
  1606. goto TryNewSiteServer;
  1607. }
  1608. } else
  1609. {
  1610. ERR(hr);
  1611. goto CleanExit;
  1612. }
  1613. }
  1614. }
  1615. //
  1616. // Allocate a return copy of the DNS-Machine-Name.
  1617. //
  1618. cb = SysStringByteLen(V_BSTR(&var)) + sizeof(WCHAR);
  1619. *ppwszSiteServer = (LPWSTR)LocalAlloc(LPTR, cb);
  1620. if (*ppwszSiteServer != NULL) {
  1621. hr = StringCbCopy(*ppwszSiteServer, cb, V_BSTR(&var));
  1622. ASSERT(SUCCEEDED(hr));
  1623. }
  1624. else {
  1625. hr = E_OUTOFMEMORY;
  1626. ERR(hr);
  1627. }
  1628. CleanExit:
  1629. // Do not free pwszDN, pwszConfigContainer or pwszBindPath.
  1630. if (pADs != NULL) {
  1631. IADs_Release(pADs);
  1632. }
  1633. if (pADs2 != NULL) {
  1634. IADs_Release(pADs2);
  1635. }
  1636. if (pADs3 != NULL) {
  1637. IADs_Release(pADs3);
  1638. }
  1639. if (pDsResult != NULL) {
  1640. DsFreeNameResult(pDsResult);
  1641. }
  1642. if (dwRet) {
  1643. // If dwRet has no facility, then make into HRESULT
  1644. if (dwRet != ERROR_SUCCESS && HRESULT_CODE(dwRet) == dwRet)
  1645. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet);
  1646. }
  1647. VariantClear(&var);
  1648. VariantClear(&var2);
  1649. if (fCoInitialized) {
  1650. CoUninitialize();
  1651. }
  1652. return hr;
  1653. }
  1654. HRESULT
  1655. BecomeSiteServer(
  1656. DS_NAME_RESULT **ppDsResult,
  1657. IADs *pADs2,
  1658. LPWSTR *ppwszDN,
  1659. LPCWSTR pwszDomain
  1660. )
  1661. {
  1662. HANDLE hDS;
  1663. WCHAR wszName[MAX_PATH + 1];
  1664. LPWSTR rgpwszNames[2];
  1665. DWORD dwRet = 0;
  1666. VARIANT var;
  1667. DS_NAME_RESULT * pDsResult = NULL;
  1668. LPWSTR pwszDN = NULL;
  1669. HRESULT hr = S_OK;
  1670. size_t cb;
  1671. ASSERT(ppDsResult != NULL);
  1672. ASSERT(ppwszDN != NULL);
  1673. VariantInit(&var);
  1674. //
  1675. // Bind to the DS (get a handle for use with DsCrackNames).
  1676. //
  1677. if (ConfigInfo.ComputerName == NULL) {
  1678. hr = E_UNEXPECTED;
  1679. goto CleanExit;
  1680. }
  1681. if (DsBind(NULL, (WCHAR *)pwszDomain, &hDS) == ERROR_SUCCESS) {
  1682. //
  1683. // Request the DS-DN of this server's computer object.
  1684. // Offer the domain\server$ name of this server.
  1685. //
  1686. cb = sizeof(wszName);
  1687. hr = StringCbCopy(wszName, cb, pwszDomain);
  1688. if (S_OK != hr)
  1689. {
  1690. goto CleanExit;
  1691. }
  1692. hr = StringCbCat(wszName, cb, L"\\");
  1693. if (S_OK != hr)
  1694. {
  1695. goto CleanExit;
  1696. }
  1697. hr = StringCbCat(wszName, cb, ConfigInfo.ComputerName);
  1698. if (S_OK != hr)
  1699. {
  1700. goto CleanExit;
  1701. }
  1702. hr = StringCbCat(wszName, cb, L"$");
  1703. if (S_OK != hr)
  1704. {
  1705. goto CleanExit;
  1706. }
  1707. rgpwszNames[0] = wszName;
  1708. rgpwszNames[1] = NULL;
  1709. if (DsCrackNames(hDS,
  1710. DS_NAME_NO_FLAGS,
  1711. DS_UNKNOWN_NAME,
  1712. DS_FQDN_1779_NAME,
  1713. 1,
  1714. &rgpwszNames[0],
  1715. &pDsResult) == ERROR_SUCCESS) {
  1716. if (pDsResult->rItems[0].status != DS_NAME_NO_ERROR) {
  1717. if (pDsResult->rItems[0].status == DS_NAME_ERROR_RESOLVING) {
  1718. dwRet = ERROR_PATH_NOT_FOUND;
  1719. ERR(dwRet);
  1720. }
  1721. else {
  1722. ERR(pDsResult->rItems[0].status);
  1723. hr = E_FAIL;
  1724. }
  1725. goto CleanExit;
  1726. }
  1727. if (pDsResult->rItems[0].pName == NULL)
  1728. {
  1729. hr = E_FAIL;
  1730. goto CleanExit;
  1731. }
  1732. //
  1733. // Update the site server property on the license
  1734. // settings object.
  1735. //
  1736. VariantInit(&var);
  1737. V_VT(&var) = VT_BSTR;
  1738. V_BSTR(&var) = pwszDN = pDsResult->rItems[0].pName;
  1739. hr = IADs_Put(pADs2, SITE_SERVER, var);
  1740. V_VT(&var) = VT_EMPTY; // For VariantClear below
  1741. if (SUCCEEDED(hr)) {
  1742. hr = IADs_SetInfo(pADs2);
  1743. if (FAILED(hr)) {
  1744. ERR(hr);
  1745. }
  1746. }
  1747. else {
  1748. ERR(hr);
  1749. }
  1750. }
  1751. else {
  1752. dwRet = GetLastError();
  1753. ERR(dwRet);
  1754. }
  1755. DsUnBind(&hDS);
  1756. }
  1757. else {
  1758. dwRet = GetLastError();
  1759. ERR(dwRet);
  1760. }
  1761. CleanExit:
  1762. *ppDsResult = pDsResult;
  1763. *ppwszDN = pwszDN;
  1764. if (!SUCCEEDED(hr) && SUCCEEDED(dwRet))
  1765. dwRet = hr;
  1766. return dwRet;
  1767. }
  1768. #define SITE_FORMAT L"LDAP://CN=%ws,CN=%ws,%ws"
  1769. #define SITES L"sites"
  1770. #define SITE_FORMAT_SIZE CWSTR_SIZE(SITE_FORMAT)
  1771. #define SITES_SIZE CWSTR_SIZE(SITES)
  1772. HRESULT
  1773. GetSiteObject(LPCWSTR pwszSiteName,
  1774. LPCWSTR pwszConfigContainer,
  1775. IADsContainer ** ppADsContainer)
  1776. {
  1777. LPWSTR pwszSite;
  1778. HRESULT hr;
  1779. size_t cb;
  1780. ASSERT(NULL != ppADsContainer);
  1781. *ppADsContainer = NULL;
  1782. //
  1783. // Build the X.500 path to the Site object.
  1784. //
  1785. cb = SITE_FORMAT_SIZE
  1786. + DWSTR_SIZE(pwszSiteName)
  1787. + SITES_SIZE
  1788. + DWSTR_SIZE(pwszConfigContainer)
  1789. + sizeof(WCHAR);
  1790. pwszSite = (LPWSTR)LocalAlloc(LPTR, cb);
  1791. if (pwszSite == NULL) {
  1792. hr = E_OUTOFMEMORY;
  1793. ERR(hr);
  1794. goto Exit;
  1795. }
  1796. hr = StringCbPrintf(pwszSite, cb,
  1797. SITE_FORMAT,
  1798. pwszSiteName,
  1799. SITES,
  1800. pwszConfigContainer);
  1801. ASSERT(SUCCEEDED(hr));
  1802. hr = ADsGetObject(pwszSite,
  1803. &IID_IADsContainer,
  1804. (void **)ppADsContainer);
  1805. LocalFree(pwszSite);
  1806. if (FAILED(hr)) {
  1807. ERR(hr);
  1808. }
  1809. Exit:
  1810. return hr;
  1811. }
  1812. #define LICENSE_SETTINGS L"Licensing Site Settings"
  1813. #define LICENSE_SETTINGS_FORMAT L"LDAP://CN=%ws,CN=%ws,CN=%ws,%ws"
  1814. #define LICENSE_SETTINGS_SIZE CWSTR_SIZE(LICENSE_SETTINGS)
  1815. #define LICENSE_SETTINGS_FORMAT_SIZE CWSTR_SIZE(LICENSE_SETTINGS_FORMAT)
  1816. HRESULT
  1817. GetLicenseSettingsObject(LPCWSTR pwszSiteName,
  1818. LPCWSTR pwszConfigContainer,
  1819. IADs ** ppADs)
  1820. {
  1821. LPWSTR pwszLicenseSettings;
  1822. HRESULT hr;
  1823. size_t cb;
  1824. ASSERT(NULL != ppADs);
  1825. *ppADs = NULL;
  1826. //
  1827. // Build the X.500 path to the LicenseSettings object.
  1828. //
  1829. cb = LICENSE_SETTINGS_FORMAT_SIZE
  1830. + LICENSE_SETTINGS_SIZE
  1831. + DWSTR_SIZE(pwszSiteName)
  1832. + SITES_SIZE
  1833. + DWSTR_SIZE(pwszConfigContainer)
  1834. + sizeof(WCHAR);
  1835. pwszLicenseSettings = (LPWSTR)LocalAlloc(LPTR, cb);
  1836. if (pwszLicenseSettings == NULL) {
  1837. hr = E_OUTOFMEMORY;
  1838. ERR(hr);
  1839. goto Exit;
  1840. }
  1841. hr = StringCbPrintf(pwszLicenseSettings, cb,
  1842. LICENSE_SETTINGS_FORMAT,
  1843. LICENSE_SETTINGS,
  1844. pwszSiteName,
  1845. SITES,
  1846. pwszConfigContainer);
  1847. ASSERT(SUCCEEDED(hr));
  1848. hr = ADsOpenObject(pwszLicenseSettings,
  1849. NULL,
  1850. NULL,
  1851. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
  1852. &IID_IADs,
  1853. (void **)ppADs);
  1854. LocalFree(pwszLicenseSettings);
  1855. if (FAILED(hr)) {
  1856. ERR(hr);
  1857. }
  1858. Exit:
  1859. return hr;
  1860. }
  1861. HRESULT
  1862. CreateLicenseSettingsObject(LPCWSTR pwszSiteName,
  1863. LPCWSTR pwszConfigContainer,
  1864. IADs ** ppADs)
  1865. {
  1866. IADsContainer * pADsContainer;
  1867. IDispatch * pDisp;
  1868. HRESULT hr;
  1869. ASSERT(NULL != ppADs);
  1870. *ppADs = NULL;
  1871. //
  1872. // Obtain the site container object.
  1873. //
  1874. hr = GetSiteObject(pwszSiteName,
  1875. pwszConfigContainer,
  1876. &pADsContainer);
  1877. if (SUCCEEDED(hr)) {
  1878. //
  1879. // Create the license settings leaf object.
  1880. //
  1881. hr = IADsContainer_Create(pADsContainer,
  1882. LICENSE_SETTINGS,
  1883. LICENSE_SETTINGS,
  1884. &pDisp);
  1885. if (SUCCEEDED(hr)) {
  1886. //
  1887. // Return an IADs to the new license settings object.
  1888. //
  1889. hr = IDispatch_QueryInterface(pDisp,
  1890. &IID_IADs,
  1891. (void **)ppADs);
  1892. if (SUCCEEDED(hr)) {
  1893. //
  1894. // Persist the change via SetInfo.
  1895. //
  1896. hr = IADs_SetInfo(*ppADs);
  1897. if (FAILED(hr)) {
  1898. ERR(hr);
  1899. IADs_Release(*ppADs);
  1900. *ppADs = NULL;
  1901. }
  1902. }
  1903. else {
  1904. ERR(hr);
  1905. }
  1906. IDispatch_Release(pDisp);
  1907. }
  1908. else {
  1909. ERR(hr);
  1910. }
  1911. IADsContainer_Release(pADsContainer);
  1912. }
  1913. else {
  1914. ERR(hr);
  1915. }
  1916. return hr;
  1917. }
  1918. #if DBG
  1919. /////////////////////////////////////////////////////////////////////////
  1920. VOID
  1921. ConfigInfoDebugDump( )
  1922. /*++
  1923. Routine Description:
  1924. Arguments:
  1925. Return Value:
  1926. --*/
  1927. {
  1928. ConfigInfoUpdate(NULL,TRUE);
  1929. RtlEnterCriticalSection(&ConfigInfoLock);
  1930. dprintf(TEXT("License Logging Service - Version: 0x%lX\n"), ConfigInfo.Version);
  1931. dprintf(TEXT(" Started: %u-%u-%u @ %u:%u:%u\n"),
  1932. (UINT) ConfigInfo.Started.wDay,
  1933. (UINT) ConfigInfo.Started.wMonth,
  1934. (UINT) ConfigInfo.Started.wYear,
  1935. (UINT) ConfigInfo.Started.wHour,
  1936. (UINT) ConfigInfo.Started.wMinute,
  1937. (UINT) ConfigInfo.Started.wSecond );
  1938. dprintf(TEXT(" Replication\n"));
  1939. dprintf(TEXT(" +--------------+\n"));
  1940. if (ConfigInfo.IsMaster)
  1941. dprintf(TEXT(" Master Server\n"));
  1942. else
  1943. dprintf(TEXT(" NOT Master Server\n"));
  1944. if (ConfigInfo.Replicate)
  1945. dprintf(TEXT(" Replicates\n"));
  1946. else
  1947. dprintf(TEXT(" Does not Replicate\n"));
  1948. if (ConfigInfo.IsReplicating)
  1949. dprintf(TEXT(" Currently Replicating\n"));
  1950. else
  1951. dprintf(TEXT(" NOT Currently Replicating\n"));
  1952. dprintf(TEXT(" Replicates To: %s\n"), ConfigInfo.ReplicateTo);
  1953. dprintf(TEXT(" Enterprise Server: %s\n"), ConfigInfo.EnterpriseServer);
  1954. if (ConfigInfo.ReplicationType == REPLICATE_DELTA)
  1955. dprintf(TEXT(" Replicate Every: %lu Seconds\n"), ConfigInfo.ReplicationTime );
  1956. else
  1957. dprintf(TEXT(" Replicate @: %lu\n"), ConfigInfo.ReplicationTime );
  1958. dprintf(TEXT("\n Last Replicated: %u-%u-%u @ %u:%u:%u\n\n"),
  1959. (UINT) ConfigInfo.LastReplicated.wDay,
  1960. (UINT) ConfigInfo.LastReplicated.wMonth,
  1961. (UINT) ConfigInfo.LastReplicated.wYear,
  1962. (UINT) ConfigInfo.LastReplicated.wHour,
  1963. (UINT) ConfigInfo.LastReplicated.wMinute,
  1964. (UINT) ConfigInfo.LastReplicated.wSecond );
  1965. dprintf(TEXT(" Number Servers Currently Replicating: %lu\n"), ConfigInfo.NumReplicating);
  1966. dprintf(TEXT(" Current Backoff Time Delta: %lu\n"), ConfigInfo.BackoffTime);
  1967. dprintf(TEXT(" Current Replication Speed: %lu\n"), ConfigInfo.ReplicationSpeed);
  1968. RtlLeaveCriticalSection(&ConfigInfoLock);
  1969. } // ConfigInfoDebugDump
  1970. #endif