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.

3520 lines
96 KiB

  1. /*++
  2. Copyright (c) 1994-7 Microsoft Corporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. This is the main routine for the BINL server service.
  7. Where possible, debugged code has been obtained from the
  8. DHCP server since BINL processes similarly formatted
  9. requests.
  10. Author:
  11. Colin Watson (colinw) 14-Apr-1997
  12. Environment:
  13. User Mode - Win32
  14. Revision History:
  15. --*/
  16. #include <binl.h>
  17. #pragma hdrstop
  18. #define GLOBAL_DATA_ALLOCATE // allocate global data defined in global.h
  19. #include <global.h>
  20. #define BINL_PNP_DELAY_SECONDS 10
  21. #define BINL_LSA_SERVER_NAME_POLICY PolicyNotifyDnsDomainInformation
  22. //
  23. // module variables
  24. //
  25. PSECURITY_DESCRIPTOR s_SecurityDescriptor = NULL;
  26. struct l_timeval BinlLdapSearchTimeout;
  27. ULARGE_INTEGER BinlSifFileScavengerTime;
  28. #if defined(REGISTRY_ROGUE)
  29. BOOL RogueDetection = FALSE;
  30. #endif
  31. VOID
  32. FreeClient(
  33. PCLIENT_STATE client
  34. );
  35. DWORD
  36. UpdateStatus(
  37. VOID
  38. )
  39. /*++
  40. Routine Description:
  41. This function updates the binl service status with the Service
  42. Controller.
  43. Arguments:
  44. None.
  45. Return Value:
  46. Return code from SetServiceStatus.
  47. --*/
  48. {
  49. DWORD Error = ERROR_SUCCESS;
  50. #if DBG
  51. if (BinlGlobalRunningAsProcess) {
  52. return(Error);
  53. }
  54. #endif
  55. if ( BinlGlobalServiceStatusHandle != 0 ) {
  56. if (!SetServiceStatus(
  57. BinlGlobalServiceStatusHandle,
  58. &BinlGlobalServiceStatus)) {
  59. Error = GetLastError();
  60. BinlPrintDbg((DEBUG_ERRORS, "SetServiceStatus failed, %ld.\n", Error ));
  61. }
  62. }
  63. return(Error);
  64. }
  65. //
  66. // BinlReadParameters( )
  67. //
  68. DWORD
  69. BinlReadParameters( )
  70. {
  71. DWORD dwDSErr;
  72. DWORD dwErr;
  73. HKEY KeyHandle;
  74. UINT uResult;
  75. PWCHAR LanguageString;
  76. PWCHAR OrgnameString;
  77. PWCHAR TimezoneString;
  78. TIME_ZONE_INFORMATION TimeZoneInformation;
  79. HKEY KeyHandle2 = NULL;
  80. DWORD Index;
  81. //
  82. // Get any registry overrides
  83. //
  84. dwErr = RegOpenKeyEx(
  85. HKEY_LOCAL_MACHINE,
  86. BINL_PARAMETERS_KEY,
  87. 0,
  88. KEY_QUERY_VALUE,
  89. &KeyHandle );
  90. if ( dwErr != ERROR_SUCCESS ) {
  91. KeyHandle = NULL;
  92. }
  93. BinlRegGetValue( KeyHandle, BINL_DEFAULT_CONTAINER , REG_SZ, (LPBYTE *)&BinlGlobalDefaultContainer );
  94. BinlRegGetValue( KeyHandle, BINL_DEFAULT_DOMAIN, REG_SZ, (LPBYTE *)&DefaultDomain );
  95. BinlRegGetValue( KeyHandle, BINL_DEFAULT_DS, REG_SZ, (LPBYTE *)&BinlGlobalDefaultDS );
  96. BinlRegGetValue( KeyHandle, BINL_DEFAULT_GC, REG_SZ, (LPBYTE *)&BinlGlobalDefaultGC );
  97. AllowNewClients = ReadDWord( KeyHandle, BINL_ALLOW_NEW_CLIENTS, AllowNewClients );
  98. #if defined(REGISTRY_ROGUE)
  99. RogueDetection = ReadDWord( KeyHandle, L"RogueDetection", RogueDetection );
  100. #endif
  101. BinlClientTimeout = ReadDWord( KeyHandle, BINL_CLIENT_TIMEOUT, 900 );
  102. BinlPrint((DEBUG_OPTIONS, "Client Timeout = %u seconds\n", BinlClientTimeout ));
  103. g_Port = ReadDWord( KeyHandle, BINL_PORT_NAME, BINL_DEFAULT_PORT );
  104. BinlPrint((DEBUG_OPTIONS, "Port Number = %u\n", g_Port ));
  105. //
  106. // BinlGlobalScavengerSleep and BinlUpdateFromDSTimeout are specified in
  107. // the registry in seconds, but are maintained internally in milliseconds.
  108. //
  109. BinlGlobalScavengerSleep = ReadDWord( KeyHandle, BINL_SCAVENGER_SLEEP, 60 ); // seconds
  110. BinlGlobalScavengerSleep *= 1000; // convert to milliseconds
  111. BinlPrint((DEBUG_OPTIONS, "Scavenger Timeout = %u milliseconds\n", BinlGlobalScavengerSleep ));
  112. Index = ReadDWord( KeyHandle, BINL_SCAVENGER_SIFFILE, 24 ); // hours
  113. if (Index == 0 ) {
  114. Index = 24;
  115. }
  116. //
  117. // BinlSifFileScavengerTime is read from the registry in seconds, but is
  118. // maintained internally as a filetime, which has a resolution of 100 ns
  119. // intervals (100 ns == 10^7)
  120. //
  121. BinlSifFileScavengerTime.QuadPart = (ULONGLONG)(Index * 60) * 60 * 1000 * 10000;
  122. BinlPrint((DEBUG_OPTIONS, "SIF File Scavenger Timeout = %d hours\n", Index ));
  123. BinlUpdateFromDSTimeout = ReadDWord( KeyHandle, BINL_UPDATE_PARAMETER_POLL, 4 * 60 * 60 ); // seconds
  124. BinlUpdateFromDSTimeout *= 1000; // convert to milliseconds
  125. BinlPrint((DEBUG_OPTIONS, "Update from DS Timeout = %u milliseconds\n", BinlUpdateFromDSTimeout ));
  126. //
  127. // Setup the variables which control how many ldap errors we log at most
  128. // during a given time period and what the time period is.
  129. //
  130. BinlGlobalMaxLdapErrorsLogged = ReadDWord( KeyHandle, BINL_DS_ERROR_COUNT_PARAMETER, 10 );
  131. BinlGlobalLdapErrorScavenger = ReadDWord( KeyHandle, BINL_DS_ERROR_SLEEP, 10 * 60 ); // seconds, default to 10 minutes
  132. BinlGlobalLdapErrorScavenger *= 1000; // convert to milliseconds
  133. BinlPrint((DEBUG_OPTIONS, "DS Error log timeout = %u milliseconds\n", BinlGlobalLdapErrorScavenger ));
  134. //
  135. // get the min time to wait before we respond to a new client
  136. //
  137. // It defaults to 7 because it will then ignore the first two packets
  138. // and respond starting at the third. After testing, we may change
  139. // this to 3.
  140. //
  141. BinlMinDelayResponseForNewClients = (DWORD) ReadDWord( KeyHandle,
  142. BINL_MIN_RESPONSE_TIME,
  143. 0 );
  144. BinlPrint((DEBUG_OPTIONS, "New Client Timeout Minimum = %u seconds\n", BinlMinDelayResponseForNewClients ));
  145. //
  146. // Get the max time we'll wait for an ldap request
  147. //
  148. BinlLdapSearchTimeout.tv_usec = 0;
  149. BinlLdapSearchTimeout.tv_sec = (DWORD) ReadDWord( KeyHandle,
  150. BINL_LDAP_SEARCH_TIMEOUT,
  151. BINL_LDAP_SEARCH_TIMEOUT_SECONDS );
  152. BinlPrint((DEBUG_OPTIONS, "LDAP Search Timeout = %u seconds\n", BinlLdapSearchTimeout.tv_sec ));
  153. //
  154. // We need to give the DS some time to find the entries. If the user
  155. // specified 0 timeout, default to some decent minimum.
  156. //
  157. if (BinlLdapSearchTimeout.tv_sec == 0) {
  158. BinlLdapSearchTimeout.tv_usec = BINL_LDAP_SEARCH_MIN_TIMEOUT_MSECS;
  159. }
  160. BinlCacheExpireMilliseconds = (ULONG) ReadDWord( KeyHandle, BINL_CACHE_EXPIRE, BINL_CACHE_EXPIRE_DEFAULT);
  161. BinlPrint(( DEBUG_OPTIONS, "Cache Entry Expire Time = %u milliseconds\n", BinlCacheExpireMilliseconds ));
  162. BinlGlobalCacheCountLimit = (ULONG) ReadDWord( KeyHandle, BINL_CACHE_MAX_COUNT, BINL_CACHE_COUNT_LIMIT_DEFAULT);
  163. BinlPrint(( DEBUG_OPTIONS, "Maximum Cache Count = %u entries\n", BinlGlobalCacheCountLimit ));
  164. #if DBG
  165. //
  166. // Test for repeat ACKs - 0 = disabled
  167. //
  168. BinlRepeatSleep = (DWORD) ReadDWord( KeyHandle, BINL_REPEAT_RESPONSE, 0 );
  169. #endif
  170. //
  171. // Turn on/off LDAP_OPT_REFERRALS
  172. //
  173. BinlLdapOptReferrals = (DWORD) ReadDWord( KeyHandle, BINL_LDAP_OPT_REFERRALS, (ULONG) ((ULONG_PTR)LDAP_OPT_OFF) );
  174. //
  175. // Determine whether to assign new client accounts to the creating server.
  176. //
  177. AssignNewClientsToServer = (DWORD) ReadDWord( KeyHandle, BINL_ASSIGN_NEW_CLIENTS_TO_SERVER, AssignNewClientsToServer );
  178. BinlPrint(( DEBUG_OPTIONS, "Assign new clients to this server = %u\n", AssignNewClientsToServer ));
  179. BinlGlobalUseNTLMV2 = (DWORD) ReadDWord( KeyHandle, BINL_NTLMV2_AUTHENTICATE, BINL_NTLMV2_AUTHENTICATE_DEFAULT );
  180. BinlRegGetValue( KeyHandle, BINL_NTLMV2_AUTHENTICATE, REG_SZ, (LPBYTE *)&BinlGlobalDefaultGC );
  181. if (KeyHandle) {
  182. RegCloseKey(KeyHandle);
  183. }
  184. //
  185. // Determine the default language.
  186. //
  187. LanguageString = NULL;
  188. uResult = GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, NULL, 0);
  189. if (uResult != 0) {
  190. LanguageString = BinlAllocateMemory(uResult * sizeof(WCHAR) );
  191. if (LanguageString != NULL) {
  192. uResult = GetLocaleInfo(
  193. LOCALE_SYSTEM_DEFAULT,
  194. LOCALE_SENGLANGUAGE,
  195. LanguageString,
  196. uResult );
  197. if (uResult == 0) {
  198. BinlFreeMemory( LanguageString );
  199. LanguageString = NULL;
  200. }
  201. }
  202. }
  203. //
  204. // Determine the default organization to put in .sif files.
  205. //
  206. OrgnameString = NULL;
  207. dwErr = RegOpenKeyEx(
  208. HKEY_LOCAL_MACHINE,
  209. L"Software\\Microsoft\\Windows NT\\CurrentVersion",
  210. 0,
  211. KEY_QUERY_VALUE,
  212. &KeyHandle );
  213. if ( dwErr == ERROR_SUCCESS ) {
  214. dwErr = BinlRegGetValue(
  215. KeyHandle,
  216. L"RegisteredOrganization",
  217. REG_SZ,
  218. (LPBYTE *)&OrgnameString );
  219. if ( dwErr != ERROR_SUCCESS ) {
  220. ASSERT( OrgnameString == NULL );
  221. }
  222. RegCloseKey(KeyHandle);
  223. }
  224. //
  225. // Determine the default timezone to put in .sif files.
  226. //
  227. TimezoneString = NULL;
  228. if (GetTimeZoneInformation(&TimeZoneInformation) != TIME_ZONE_ID_INVALID) {
  229. //
  230. // We need to find the value of
  231. // "Software\\Microsoft\\Windows NT\\CurrentVersion\Time Zones\
  232. // {TimeZoneInformation.StandardName}\Index.
  233. //
  234. dwErr = RegOpenKeyEx(
  235. HKEY_LOCAL_MACHINE,
  236. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
  237. 0,
  238. KEY_READ,
  239. &KeyHandle );
  240. if (dwErr == ERROR_SUCCESS) {
  241. dwErr = RegOpenKeyEx(
  242. KeyHandle,
  243. TimeZoneInformation.StandardName,
  244. 0,
  245. KEY_QUERY_VALUE,
  246. &KeyHandle2);
  247. //
  248. // In Far East NT, the TimeZoneInformation.StandardName gets a
  249. // localized string of the English time zone name, but the subkey
  250. // name remains in English. For example, if the time zone is
  251. // "Pacific Standard Time", TimeZoneInformation.StandardName will
  252. // be the localized string for this English string, but the subkey
  253. // name will still be "Pacific Standard Time".
  254. //
  255. // So if we pass this Localized string to RegOpenKeyEx(), we may
  256. // get error value (0x00000002).
  257. //
  258. // The above code works fine in US Build, but for FE build, we
  259. // have to add a code block to get the correct Key.
  260. //
  261. if ( dwErr != ERROR_SUCCESS ) {
  262. //
  263. // This is for FE builds. Normally, in US Build, code will
  264. // not go to here.
  265. //
  266. WCHAR pszSubKeyName[MAX_PATH];
  267. WCHAR pszAlternateName[MAX_PATH];
  268. DWORD cbName;
  269. LONG lRetValue;
  270. DWORD dwIndex;
  271. dwIndex = 0;
  272. //
  273. // The alternate name is the name returned by
  274. // GetTimeZoneInformation with "Standard Time"
  275. // added at the end -- NT4 upgraded machines
  276. // may return the old names.
  277. //
  278. wcscpy(pszAlternateName, TimeZoneInformation.StandardName);
  279. wcscat(pszAlternateName, L" Standard Time");
  280. cbName = MAX_PATH;
  281. lRetValue = RegEnumKeyEx(
  282. KeyHandle,
  283. dwIndex,
  284. pszSubKeyName,
  285. &cbName,
  286. NULL,
  287. NULL,
  288. NULL,
  289. NULL );
  290. KeyHandle2 = NULL;
  291. while ( lRetValue != ERROR_NO_MORE_ITEMS ) {
  292. if ( KeyHandle2 != NULL ) {
  293. RegCloseKey( KeyHandle2 );
  294. KeyHandle2 = NULL;
  295. }
  296. dwErr = RegOpenKeyEx(
  297. KeyHandle,
  298. pszSubKeyName,
  299. 0,
  300. KEY_QUERY_VALUE,
  301. &KeyHandle2);
  302. if ( dwErr == ERROR_SUCCESS ) {
  303. WCHAR StdName[MAX_PATH];
  304. DWORD cb;
  305. cb = MAX_PATH;
  306. StdName[0] = L'\0';
  307. dwErr = RegQueryValueEx(KeyHandle2,
  308. TEXT("Std"),
  309. NULL,
  310. NULL,
  311. (PBYTE)StdName,
  312. &cb);
  313. if (dwErr == ERROR_SUCCESS &&
  314. (!wcscmp(StdName,TimeZoneInformation.StandardName) ||
  315. !wcscmp(StdName,pszAlternateName)) ){
  316. // got the right key.
  317. break;
  318. }
  319. }
  320. dwIndex ++;
  321. cbName = MAX_PATH;
  322. lRetValue = RegEnumKeyEx(
  323. KeyHandle,
  324. dwIndex,
  325. pszSubKeyName,
  326. &cbName,
  327. NULL,
  328. NULL,
  329. NULL,
  330. NULL);
  331. } // while
  332. if ( lRetValue == ERROR_NO_MORE_ITEMS ) {
  333. dwErr = ERROR_NO_MORE_ITEMS;
  334. }
  335. }
  336. if (dwErr == ERROR_SUCCESS) {
  337. BinlRegGetValue( KeyHandle2,
  338. L"Index",
  339. REG_DWORD,
  340. (LPBYTE *)&Index );
  341. TimezoneString = BinlAllocateMemory(24); // enough for a big number
  342. if (TimezoneString != NULL) {
  343. wsprintf(TimezoneString, L"%d", Index);
  344. }
  345. }
  346. if ( KeyHandle2 != NULL ) {
  347. RegCloseKey( KeyHandle2 );
  348. KeyHandle2 = NULL;
  349. }
  350. RegCloseKey(KeyHandle);
  351. }
  352. }
  353. EnterCriticalSection(&gcsParameters);
  354. if ( LanguageString != NULL ) {
  355. if ( BinlGlobalDefaultLanguage != NULL ) {
  356. BinlFreeMemory( BinlGlobalDefaultLanguage );
  357. }
  358. BinlGlobalDefaultLanguage = LanguageString;
  359. }
  360. if ( OrgnameString != NULL ) {
  361. if ( BinlGlobalDefaultOrgname != NULL ) {
  362. BinlFreeMemory( BinlGlobalDefaultOrgname );
  363. }
  364. BinlGlobalDefaultOrgname = OrgnameString;
  365. }
  366. if ( TimezoneString != NULL ) {
  367. if (BinlGlobalDefaultTimezone != NULL) {
  368. BinlFreeMemory( BinlGlobalDefaultTimezone );
  369. }
  370. BinlGlobalDefaultTimezone = TimezoneString;
  371. }
  372. LeaveCriticalSection(&gcsParameters);
  373. //
  374. // dwDSErr is the status code that we will return. We don't care whether
  375. // the registry reads work -- we assume that they always will. We do care
  376. // whether we were able to contact the DS.
  377. //
  378. //
  379. // We do the DS query after we've read the parameters so that we setup
  380. // the ldap timeouts, chase referrals, etc parameters correctly before
  381. // we try to do the search.
  382. //
  383. dwDSErr = GetBinlServerParameters( FALSE );
  384. if ( dwDSErr != ERROR_SUCCESS ) {
  385. BinlPrint(( DEBUG_ERRORS, "!!Error 0x%08x - there was an error getting the settings from the DS.\n", dwDSErr ));
  386. }
  387. //
  388. // Return the status of the DS access.
  389. //
  390. return(dwDSErr);
  391. }
  392. DWORD
  393. GetSCPName(
  394. PWSTR *ScpName
  395. )
  396. {
  397. DWORD dwError;
  398. PWSTR psz;
  399. WCHAR MachineDN[ MAX_PATH ];
  400. WCHAR IntellimirrorSCP[ 64 ] = L"-Remote-Installation-Services";
  401. DWORD dwPathLength;
  402. //
  403. // Figure out the machine DN
  404. //
  405. wcscpy( MachineDN, BinlGlobalOurFQDNName );
  406. psz = MachineDN;
  407. while ( *psz && *psz != L',' )
  408. psz++;
  409. if ( *psz == L',' ) {
  410. *psz = TEXT('\0'); // terminate
  411. } else {
  412. wcscpy( MachineDN, L"UNKNOWN" );
  413. }
  414. //
  415. // Make space
  416. //
  417. dwPathLength = (wcslen( MachineDN ) + // CN=SERVER
  418. wcslen( IntellimirrorSCP ) + // CN=SERVER-IntelliMirror-Service
  419. 1 + // CN=SERVER-IntelliMirror-Service,
  420. wcslen( BinlGlobalOurFQDNName ) + // CN=SERVER-IntelliMirror-Service,CN=SERVE
  421. 1 ) // CN=SERVER-IntelliMirror-Service,CN=SERVE
  422. * sizeof(WCHAR);
  423. *ScpName = (LPWSTR) BinlAllocateMemory( dwPathLength );
  424. if ( !*ScpName ) {
  425. dwError = ERROR_NOT_ENOUGH_MEMORY;
  426. goto exit;
  427. }
  428. //
  429. // Create string
  430. //
  431. wsprintf( *ScpName, L"%s%s,%s", MachineDN, IntellimirrorSCP, BinlGlobalOurFQDNName );
  432. dwError = ERROR_SUCCESS;
  433. exit:
  434. return(dwError);
  435. }
  436. DWORD
  437. CreateSCPIfNeeded(
  438. PBOOL CreatedTheSCP
  439. )
  440. /*++
  441. Routine Description:
  442. Creates the SCP for BINL if necessary.
  443. It does this by checking the local registry for a flag (ScpCreated) which
  444. indicates whether the SCP needs to be created. This flag may created by
  445. RISETUP or by BINL. If the SCP needs to be created, then the registry is
  446. queried for the SCP data. If the data isn't present, then we assume that
  447. RISETUP hasn't been run yet, and we do not try to create the SCP. If SCP
  448. creation is successful, the "ScpCreated" registry flag is set.
  449. KB. This is all done because the system context that BINL runs in should
  450. have permission to create the SCP underneath the MAO. The user running
  451. RISETUP may not have sufficient permissions to be able to create the SCP.
  452. Arguments:
  453. CreatedTheSCP - set to TRUE if we actually create the SCP.
  454. Return Value:
  455. ERROR_SUCCESS indicates success. A WIN32 error code if SCP creation fails.
  456. --*/
  457. {
  458. DWORD dwErr;
  459. HKEY KeyHandle;
  460. DWORD Created = 0;
  461. DWORD i;
  462. PWSTR ScpName;
  463. PWSTR ScpDataKeys[] = {
  464. BINL_SCP_NEWCLIENTS,
  465. BINL_SCP_LIMITCLIENTS,
  466. BINL_SCP_CURRENTCLIENTCOUNT,
  467. BINL_SCP_MAXCLIENTS,
  468. BINL_SCP_ANSWER_REQUESTS,
  469. BINL_SCP_ANSWER_VALID,
  470. BINL_SCP_NEWMACHINENAMEPOLICY,
  471. BINL_SCP_NEWMACHINEOU,
  472. BINL_SCP_NETBOOTSERVER };
  473. #define SCPDATACOUNT (sizeof(ScpDataKeys) / sizeof(PWSTR))
  474. #define MACHINEOU_INDEX 7
  475. #define NETBOOTSERVER_INDEX 8
  476. PWSTR ScpDataValues[SCPDATACOUNT];
  477. PLDAP LdapHandle = NULL;
  478. PLDAPMessage LdapMessage;
  479. PLDAPMessage CurrentEntry;
  480. LDAPMod mods[1+SCPDATACOUNT];
  481. PLDAPMod pmods[2+SCPDATACOUNT];
  482. LPWSTR attr_values[SCPDATACOUNT+1][2];
  483. *CreatedTheSCP = FALSE;
  484. //
  485. // Try to get the ScpCreated flag
  486. //
  487. dwErr = RegOpenKeyEx(
  488. HKEY_LOCAL_MACHINE,
  489. BINL_PARAMETERS_KEY,
  490. 0,
  491. KEY_QUERY_VALUE | KEY_SET_VALUE,
  492. &KeyHandle );
  493. if ( dwErr != ERROR_SUCCESS ) {
  494. dwErr = ERROR_SUCCESS;
  495. BinlPrintDbg(( DEBUG_INIT, "SCP Created key not in registry, won't try to create SCP.\n" ));
  496. goto e0;
  497. }
  498. dwErr = BinlRegGetValue(
  499. KeyHandle,
  500. BINL_SCP_CREATED ,
  501. REG_DWORD,
  502. (LPBYTE *)&Created );
  503. if (dwErr == ERROR_SUCCESS && Created != 0) {
  504. //
  505. // we think the SCP has already been created...we're done.
  506. //
  507. BinlPrintDbg(( DEBUG_INIT, "SCP Created flag set to 1, we won't try to create SCP.\n" ));
  508. dwErr = ERROR_SUCCESS;
  509. goto e1;
  510. }
  511. //
  512. // The SCP hasn't been created. See if all of the required parameters for
  513. // creating the SCP are in the registry.
  514. //
  515. RtlZeroMemory( ScpDataValues, sizeof(ScpDataValues) );
  516. for (i = 0; i < SCPDATACOUNT ; i++) {
  517. dwErr = BinlRegGetValue(
  518. KeyHandle,
  519. ScpDataKeys[i],
  520. REG_SZ,
  521. (LPBYTE *)&ScpDataValues[i] );
  522. if (dwErr != ERROR_SUCCESS) {
  523. //
  524. // one of the required parameters isn't present. this means that
  525. // RISETUP wasn't run yet.
  526. //
  527. BinlPrintDbg((
  528. DEBUG_INIT, "Can't retrieve SCP value %s [ec = 0x%08x, we won't try to create SCP.\n",
  529. ScpDataKeys[i],
  530. dwErr ));
  531. dwErr = ERROR_SUCCESS;
  532. goto e2;
  533. }
  534. }
  535. //
  536. // great, we have all of the data. Now do some touchup on the pieces that
  537. // may have changed
  538. //
  539. if (wcscmp(ScpDataValues[MACHINEOU_INDEX],BinlGlobalOurFQDNName)) {
  540. BinlFreeMemory( ScpDataValues[MACHINEOU_INDEX] );
  541. ScpDataValues[MACHINEOU_INDEX] = BinlAllocateMemory((wcslen(BinlGlobalOurFQDNName)+1)*sizeof(WCHAR));
  542. if (!ScpDataValues[MACHINEOU_INDEX]) {
  543. BinlPrintDbg(( DEBUG_INIT, "Can't allocate memory for SCP, we can't create SCP.\n" ));
  544. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  545. goto e2;
  546. }
  547. wcscpy(ScpDataValues[MACHINEOU_INDEX],BinlGlobalOurFQDNName);
  548. }
  549. if (wcscmp(ScpDataValues[NETBOOTSERVER_INDEX],BinlGlobalOurFQDNName)) {
  550. BinlFreeMemory( ScpDataValues[NETBOOTSERVER_INDEX] );
  551. ScpDataValues[NETBOOTSERVER_INDEX] = BinlAllocateMemory((wcslen(BinlGlobalOurFQDNName)+1)*sizeof(WCHAR));
  552. if (!ScpDataValues[NETBOOTSERVER_INDEX]) {
  553. BinlPrintDbg(( DEBUG_INIT, "Can't allocate memory for SCP, we can't create SCP.\n" ));
  554. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  555. goto e2;
  556. }
  557. wcscpy(ScpDataValues[NETBOOTSERVER_INDEX],BinlGlobalOurFQDNName);
  558. }
  559. //
  560. // generate the SCP name
  561. //
  562. dwErr = GetSCPName(&ScpName);
  563. if (dwErr != ERROR_SUCCESS) {
  564. BinlPrintDbg(( DEBUG_INIT, "Can't get the SCP name, ec=0x08x, we can't create SCP.\n",dwErr ));
  565. goto e2;
  566. }
  567. //
  568. // create the SCP -- set the timeout to something reasonable since the timeout isn't initialized
  569. // from the registry yet at this point
  570. //
  571. BinlLdapSearchTimeout.tv_sec = BINL_LDAP_SEARCH_TIMEOUT_SECONDS;
  572. BinlLdapSearchTimeout.tv_usec = 0;
  573. dwErr = InitializeConnection( FALSE, &LdapHandle, NULL );
  574. if ( dwErr != ERROR_SUCCESS ) {
  575. BinlPrintDbg(( DEBUG_INIT, "Can't InitializeConnection, ec=0x08x, we can't create SCP.\n",dwErr ));
  576. goto e2;
  577. }
  578. //
  579. // setup all of the attributes for the object.
  580. //
  581. mods[0].mod_op = LDAP_MOD_ADD;
  582. mods[0].mod_type = L"objectClass";
  583. mods[0].mod_values = attr_values[0];
  584. attr_values[0][0] = L"IntellimirrorSCP";
  585. attr_values[0][1] = NULL;
  586. pmods[0] = &mods[0];
  587. pmods[SCPDATACOUNT+1] = NULL;
  588. for( i = 0; i < SCPDATACOUNT ; i++ ) {
  589. mods[i+1].mod_op = LDAP_MOD_ADD;
  590. mods[i+1].mod_type = ScpDataKeys[i];
  591. mods[i+1].mod_values = attr_values[i+1];
  592. attr_values[i+1][0] = ScpDataValues[i];
  593. attr_values[i+1][1] = NULL;
  594. pmods[i+1] = &mods[i+1];
  595. }
  596. dwErr = ldap_add_s( LdapHandle, ScpName, pmods );
  597. if ( dwErr != LDAP_SUCCESS ) {
  598. if (dwErr == LDAP_ALREADY_EXISTS ) {
  599. //
  600. // if the SCP already exists, don't overwrite any data. Set our flag in
  601. // the registry so we don't try to do this next time we start.
  602. //
  603. dwErr = ERROR_SUCCESS;
  604. goto SetSCPCreatedFlag;
  605. } else {
  606. BinlPrintDbg(( DEBUG_INIT, "ldap_add_s failed, ec=0x08x, we can't create SCP.\n",dwErr ));
  607. goto e3;
  608. }
  609. }
  610. *CreatedTheSCP = TRUE;
  611. SetSCPCreatedFlag:
  612. //
  613. // we're done. set the flag so we don't try to do this in the future.
  614. //
  615. Created = 1;
  616. RegSetValueEx( KeyHandle, BINL_SCP_CREATED, 0, REG_DWORD, (LPBYTE)&Created, sizeof(DWORD) );
  617. e3:
  618. if ( dwErr != LDAP_SUCCESS ) {
  619. //
  620. // just delete the object if this failed
  621. //
  622. ldap_delete( LdapHandle, ScpName );
  623. }
  624. ldap_unbind( LdapHandle );
  625. e2:
  626. for (i = 0; i < SCPDATACOUNT ; i++) {
  627. if (ScpDataValues[i]) {
  628. BinlFreeMemory( ScpDataValues[i]);
  629. }
  630. }
  631. e1:
  632. RegCloseKey(KeyHandle);
  633. e0:
  634. return(dwErr);
  635. }
  636. DWORD
  637. InitializeData(
  638. VOID
  639. )
  640. {
  641. DWORD Length;
  642. DWORD dwErr;
  643. int i;
  644. DWORD ValueSize;
  645. //
  646. // We can operate on all NICs with all IP addresses with a single socket.
  647. // If we want control to limit BINL to particular NICs or IP addresses then
  648. // we will need multiple sockets and use the bindings in the registry.
  649. //
  650. BinlGlobalNumberOfNets = 2;
  651. BinlGlobalEndpointList =
  652. BinlAllocateMemory( sizeof(ENDPOINT) * BinlGlobalNumberOfNets );
  653. if( BinlGlobalEndpointList == NULL ) {
  654. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  655. goto Error;
  656. }
  657. BinlGlobalEndpointList[0].Socket = 0;
  658. BinlGlobalEndpointList[1].Socket = 0;
  659. BinlGlobalIgnoreBroadcastFlag = FALSE;
  660. BinlGlobalLdapErrorCount = 0;
  661. InitializeCriticalSection(&g_ProcessMessageCritSect);
  662. InitializeListHead(&BinlGlobalActiveRecvList);
  663. InitializeListHead(&BinlGlobalFreeRecvList);
  664. InitializeCriticalSection(&BinlGlobalRecvListCritSect);
  665. g_cMaxProcessingThreads = BINL_MAX_PROCESSING_THREADS;
  666. g_cProcessMessageThreads = 0;
  667. InitializeListHead(&BinlCacheList);
  668. InitializeCriticalSection( &BinlCacheListLock );
  669. //
  670. // initialize (free) receive message queue.
  671. //
  672. for( i = 0; i < BINL_RECV_QUEUE_LENGTH; i++ )
  673. {
  674. PBINL_REQUEST_CONTEXT pRequestContext =
  675. BinlAllocateMemory( sizeof(BINL_REQUEST_CONTEXT) );
  676. if( !pRequestContext )
  677. {
  678. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  679. goto Error;
  680. }
  681. //
  682. // allocate memory for the receive buffer, plus one byte
  683. // so we can ensure there is a NULL after the message.
  684. //
  685. pRequestContext->ReceiveBuffer =
  686. BinlAllocateMemory( DHCP_RECV_MESSAGE_SIZE + 1 );
  687. if( !pRequestContext->ReceiveBuffer )
  688. {
  689. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  690. goto Error;
  691. }
  692. //
  693. // add this entry to free list.
  694. //
  695. LOCK_RECV_LIST();
  696. InsertTailList( &BinlGlobalFreeRecvList,
  697. &pRequestContext->ListEntry );
  698. UNLOCK_RECV_LIST();
  699. }
  700. //
  701. // create an event to notifiy the message processing thread about the
  702. // arrival of a new message.
  703. //
  704. BinlGlobalRecvEvent = CreateEvent(
  705. NULL, // no security descriptor
  706. FALSE, // AUTOMATIC reset
  707. FALSE, // initial state: not signalled
  708. NULL); // no name
  709. if ( !BinlGlobalRecvEvent) {
  710. dwErr = GetLastError();
  711. goto Error;
  712. }
  713. BinlCloseCacheEvent = CreateEvent(
  714. NULL, // no security descriptor
  715. TRUE, // MANUAL reset
  716. FALSE, // initial state: not signalled
  717. NULL); // no name
  718. if ( !BinlCloseCacheEvent) {
  719. dwErr = GetLastError();
  720. goto Error;
  721. }
  722. //
  723. // initialize our notify event handle to LSA for server name change operations
  724. //
  725. BinlGlobalLsaDnsNameNotifyEvent =
  726. CreateEvent(
  727. NULL, // no security descriptor
  728. FALSE, // auto reset
  729. FALSE, // initial state: not signalled
  730. NULL); // no name
  731. if ( BinlGlobalLsaDnsNameNotifyEvent == NULL ) {
  732. dwErr = GetLastError();
  733. BinlPrintDbg((DEBUG_INIT, "Can't create LSA notify event, "
  734. "%ld.\n", dwErr));
  735. goto Error;
  736. }
  737. dwErr = LsaRegisterPolicyChangeNotification( BINL_LSA_SERVER_NAME_POLICY,
  738. BinlGlobalLsaDnsNameNotifyEvent
  739. );
  740. if (dwErr == ERROR_SUCCESS) {
  741. BinlGlobalHaveOutstandingLsaNotify = TRUE;
  742. } else {
  743. //
  744. // we won't fail for now as in 99.99% of the cases the machine name
  745. // won't be changing therefore this is not critical.
  746. //
  747. BinlPrintDbg((DEBUG_INIT, "Can't start LSA notify, 0x%08x.\n", dwErr));
  748. }
  749. dwErr = GetOurServerInfo();
  750. if (dwErr != ERROR_SUCCESS) {
  751. goto Error;
  752. }
  753. dwErr = GetIpAddressInfo( 0 );
  754. if (dwErr != ERROR_SUCCESS) {
  755. goto Error;
  756. }
  757. Cleanup:
  758. return(dwErr);
  759. Error:
  760. BinlPrintDbg(( DEBUG_ERRORS, "!!Error 0x%08x - Could not initialize BINL service.\n", dwErr ));
  761. BinlServerEventLog(
  762. EVENT_SERVER_INIT_DATA_FAILED,
  763. EVENTLOG_ERROR_TYPE,
  764. dwErr );
  765. goto Cleanup;
  766. }
  767. DWORD
  768. ReadDWord(
  769. HKEY KeyHandle,
  770. LPTSTR lpValueName,
  771. DWORD DefaultValue
  772. )
  773. /*++
  774. Routine Description:
  775. Read a DWORD value from the registry. If there is a problem then
  776. return the default value.
  777. --*/
  778. {
  779. DWORD Value;
  780. DWORD ValueSize = sizeof(Value);
  781. DWORD ValueType;
  782. if ((KeyHandle) &&
  783. (RegQueryValueEx(
  784. KeyHandle,
  785. lpValueName,
  786. 0,
  787. &ValueType,
  788. (PUCHAR)&Value,
  789. &ValueSize ) == ERROR_SUCCESS )) {
  790. return Value;
  791. } else {
  792. return DefaultValue;
  793. }
  794. }
  795. DWORD
  796. BinlRegGetValue(
  797. HKEY KeyHandle,
  798. LPWSTR ValueName,
  799. DWORD ValueType,
  800. LPBYTE * BufferPtr
  801. )
  802. /*++
  803. Routine Description:
  804. This function retrieves the value of the specified value field. This
  805. function allocates memory for variable length field such as REG_SZ.
  806. For REG_DWORD data type, it copies the field value directly into
  807. BufferPtr. Currently it can handle only the following fields :
  808. REG_DWORD,
  809. REG_SZ,
  810. REG_BINARY
  811. Arguments:
  812. KeyHandle : handle of the key whose value field is retrieved.
  813. ValueName : name of the value field.
  814. ValueType : Expected type of the value field.
  815. BufferPtr : Pointer to DWORD location where a DWORD datatype value
  816. is returned or a buffer pointer for REG_SZ or REG_BINARY
  817. datatype value is returned.
  818. If "ValueName" is not found, then "BufferPtr" will not be
  819. touched.
  820. Return Value:
  821. Registry Errors.
  822. --*/
  823. {
  824. DWORD dwErr;
  825. DWORD LocalValueType;
  826. DWORD ValueSize;
  827. LPBYTE DataBuffer;
  828. LPBYTE AllotedBuffer = NULL;
  829. LPDHCP_BINARY_DATA BinaryData = NULL;
  830. //
  831. // Query DataType and BufferSize.
  832. //
  833. if ( !KeyHandle ) {
  834. dwErr = ERROR_INVALID_HANDLE;
  835. goto Error;
  836. }
  837. dwErr = RegQueryValueEx(
  838. KeyHandle,
  839. ValueName,
  840. 0,
  841. &LocalValueType,
  842. NULL,
  843. &ValueSize );
  844. if ( dwErr != ERROR_SUCCESS ) {
  845. goto Error;
  846. }
  847. if ( LocalValueType != ValueType ) {
  848. dwErr = ERROR_INVALID_PARAMETER;
  849. goto Error;
  850. }
  851. switch( ValueType ) {
  852. case REG_DWORD:
  853. BinlAssert( ValueSize == sizeof(DWORD) );
  854. DataBuffer = (LPBYTE)BufferPtr;
  855. break;
  856. case REG_SZ:
  857. case REG_MULTI_SZ:
  858. case REG_EXPAND_SZ:
  859. case REG_BINARY:
  860. if( ValueSize == 0 ) {
  861. goto Cleanup; // no key
  862. }
  863. AllotedBuffer = DataBuffer = BinlAllocateMemory( ValueSize );
  864. if( DataBuffer == NULL ) {
  865. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  866. goto Error;
  867. }
  868. break;
  869. default:
  870. BinlPrint(( DEBUG_REGISTRY, "Unexpected ValueType in"
  871. "BinlRegGetValue function, %ld\n", ValueType ));
  872. dwErr= ERROR_INVALID_PARAMETER;
  873. goto Error;
  874. }
  875. //
  876. // retrieve data.
  877. //
  878. dwErr = RegQueryValueEx(
  879. KeyHandle,
  880. ValueName,
  881. 0,
  882. &LocalValueType,
  883. DataBuffer,
  884. &ValueSize );
  885. if( dwErr != ERROR_SUCCESS ) {
  886. goto Error;
  887. }
  888. switch( ValueType ) {
  889. case REG_SZ:
  890. case REG_MULTI_SZ:
  891. case REG_EXPAND_SZ:
  892. BinlAssert( ValueSize != 0 );
  893. *BufferPtr = DataBuffer;
  894. break;
  895. case REG_BINARY:
  896. BinaryData = BinlAllocateMemory(sizeof(DHCP_BINARY_DATA));
  897. if( BinaryData == NULL ) {
  898. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  899. goto Error;
  900. }
  901. BinaryData->DataLength = ValueSize;
  902. BinaryData->Data = DataBuffer;
  903. *BufferPtr = (LPBYTE)BinaryData;
  904. default:
  905. break;
  906. }
  907. Cleanup:
  908. return(dwErr);
  909. Error:
  910. if ( BinaryData )
  911. BinlFreeMemory( BinaryData );
  912. if ( AllotedBuffer )
  913. BinlFreeMemory( AllotedBuffer );
  914. goto Cleanup;
  915. }
  916. VOID
  917. ServiceControlHandler(
  918. IN DWORD Opcode
  919. )
  920. /*++
  921. Routine Description:
  922. This is the service control handler of the binl service.
  923. Arguments:
  924. Opcode - Supplies a value which specifies the action for the
  925. service to perform.
  926. Return Value:
  927. None.
  928. --*/
  929. {
  930. DWORD Error;
  931. //
  932. // Use critical section to stop DHCP telling us it is starting or stopping
  933. // while we change state ourselves.
  934. //
  935. EnterCriticalSection(&gcsDHCPBINL);
  936. switch (Opcode) {
  937. case SERVICE_CONTROL_STOP:
  938. case SERVICE_CONTROL_SHUTDOWN:
  939. BinlCurrentState = BINL_STOPPED;
  940. if (BinlGlobalServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) {
  941. if( Opcode == SERVICE_CONTROL_SHUTDOWN ) {
  942. //
  943. // set this flag, so that service shut down will be
  944. // faster.
  945. //
  946. BinlGlobalSystemShuttingDown = TRUE;
  947. }
  948. BinlPrintDbg(( DEBUG_MISC, "Service is stop pending.\n"));
  949. BinlGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  950. BinlGlobalServiceStatus.dwCheckPoint = 1;
  951. //
  952. // Send the status response.
  953. //
  954. UpdateStatus();
  955. if (! SetEvent(BinlGlobalProcessTerminationEvent)) {
  956. //
  957. // Problem with setting event to terminate binl
  958. // service.
  959. //
  960. BinlPrintDbg(( DEBUG_ERRORS, "BINL Server: Error "
  961. "setting DoneEvent %lu\n",
  962. GetLastError()));
  963. BinlAssert(FALSE);
  964. }
  965. LeaveCriticalSection(&gcsDHCPBINL);
  966. return;
  967. }
  968. break;
  969. case SERVICE_CONTROL_PAUSE:
  970. BinlGlobalServiceStatus.dwCurrentState = SERVICE_PAUSED;
  971. BinlPrint(( DEBUG_MISC, "Service is paused.\n"));
  972. break;
  973. case SERVICE_CONTROL_CONTINUE:
  974. BinlCurrentState = BINL_STARTED;
  975. BinlGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
  976. BinlPrint(( DEBUG_MISC, "Service is Continued.\n"));
  977. break;
  978. case SERVICE_CONTROL_INTERROGATE:
  979. BinlPrint(( DEBUG_MISC, "Service is interrogated.\n"));
  980. break;
  981. case BINL_SERVICE_REREAD_SETTINGS: // custom message
  982. BinlPrint(( DEBUG_MISC, "Service received paramchange message.\n"));
  983. Error = BinlReadParameters( );
  984. //
  985. // Cause the service to poll frequently for a while and then return to
  986. // normal polling. If we managed to read the DS above, then we don't
  987. // need to succeed again, but if we failed above, then we want to keep
  988. // trying until we succeed at least once.
  989. //
  990. BinlHyperUpdateCount = BINL_HYPERMODE_RETRY_COUNT;
  991. BinlHyperUpdateSatisfied = (BOOL)(Error == ERROR_SUCCESS);
  992. break;
  993. default:
  994. BinlPrintDbg(( DEBUG_MISC, "Service received unknown control.\n"));
  995. break;
  996. }
  997. //
  998. // Send the status response.
  999. //
  1000. UpdateStatus();
  1001. LeaveCriticalSection(&gcsDHCPBINL);
  1002. }
  1003. DWORD
  1004. BinlInitializeEndpoint(
  1005. PENDPOINT pEndpoint,
  1006. PDHCP_IP_ADDRESS pIpAddress,
  1007. DWORD Port
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. This function initializes an endpoint by creating and binding a
  1012. socket to the local address.
  1013. Arguments:
  1014. pEndpoint - Receives a pointer to the newly created socket
  1015. pIpAddress - The IP address to initialize to INADDR_ANY if NULL.
  1016. Port - The port to bind to.
  1017. Return Value:
  1018. The status of the operation.
  1019. --*/
  1020. {
  1021. DWORD Error;
  1022. SOCKET Sock;
  1023. DWORD OptValue;
  1024. #define SOCKET_RECEIVE_BUFFER_SIZE 1024 * 64 // 64K max.
  1025. struct sockaddr_in SocketName;
  1026. pEndpoint->Port = Port;
  1027. //
  1028. // Create a socket
  1029. //
  1030. Sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
  1031. if ( Sock == INVALID_SOCKET ) {
  1032. Error = WSAGetLastError();
  1033. goto Cleanup;
  1034. }
  1035. //
  1036. // Make the socket share-able
  1037. //
  1038. OptValue = TRUE;
  1039. Error = setsockopt(
  1040. Sock,
  1041. SOL_SOCKET,
  1042. SO_REUSEADDR,
  1043. (LPBYTE)&OptValue,
  1044. sizeof(OptValue) );
  1045. if ( Error != ERROR_SUCCESS ) {
  1046. Error = WSAGetLastError();
  1047. goto Cleanup;
  1048. }
  1049. OptValue = TRUE;
  1050. Error = setsockopt(
  1051. Sock,
  1052. SOL_SOCKET,
  1053. SO_BROADCAST,
  1054. (LPBYTE)&OptValue,
  1055. sizeof(OptValue) );
  1056. if ( Error != ERROR_SUCCESS ) {
  1057. Error = WSAGetLastError();
  1058. goto Cleanup;
  1059. }
  1060. OptValue = SOCKET_RECEIVE_BUFFER_SIZE;
  1061. Error = setsockopt(
  1062. Sock,
  1063. SOL_SOCKET,
  1064. SO_RCVBUF,
  1065. (LPBYTE)&OptValue,
  1066. sizeof(OptValue) );
  1067. if ( Error != ERROR_SUCCESS ) {
  1068. Error = WSAGetLastError();
  1069. goto Cleanup;
  1070. }
  1071. SocketName.sin_family = PF_INET;
  1072. SocketName.sin_port = htons( (unsigned short)Port );
  1073. if (pIpAddress) {
  1074. SocketName.sin_addr.s_addr = *pIpAddress;
  1075. } else {
  1076. SocketName.sin_addr.s_addr = INADDR_ANY;
  1077. }
  1078. RtlZeroMemory( SocketName.sin_zero, 8);
  1079. //
  1080. // Bind this socket to the server port
  1081. //
  1082. Error = bind(
  1083. Sock,
  1084. (struct sockaddr FAR *)&SocketName,
  1085. sizeof( SocketName )
  1086. );
  1087. if ( Error != ERROR_SUCCESS ) {
  1088. Error = WSAGetLastError();
  1089. goto Cleanup;
  1090. }
  1091. pEndpoint->Socket = Sock;
  1092. //
  1093. // if this is 4011, then we setup for the pnp notification.
  1094. //
  1095. if ((Port == g_Port) &&
  1096. (BinlGlobalPnpEvent != NULL) &&
  1097. (BinlPnpSocket == INVALID_SOCKET)) {
  1098. BinlPnpSocket = Sock;
  1099. Error = BinlSetupPnpWait( );
  1100. if (Error != 0) {
  1101. BinlPrintDbg(( DEBUG_ERRORS, "BinlInitializeEndpoint could not set pnp event, %ld.\n", Error ));
  1102. }
  1103. }
  1104. if (!pIpAddress) {
  1105. PHOSTENT Host = gethostbyname(NULL); // winsock2 allows us to do this.
  1106. if (Host) {
  1107. pEndpoint->IpAddress = *(PDHCP_IP_ADDRESS)Host->h_addr;
  1108. } else {
  1109. Error = WSAGetLastError();
  1110. BinlPrintDbg(( DEBUG_ERRORS, "BinlInitializeEndpoint could not get ip addr, %ld.\n", Error ));
  1111. pEndpoint->IpAddress = 0;
  1112. }
  1113. } else {
  1114. pEndpoint->IpAddress = *pIpAddress;
  1115. }
  1116. Error = ERROR_SUCCESS;
  1117. Cleanup:
  1118. if( Error != ERROR_SUCCESS ) {
  1119. //
  1120. // if we aren't successful, close the socket if it is opened.
  1121. //
  1122. if( Sock != INVALID_SOCKET ) {
  1123. closesocket( Sock );
  1124. }
  1125. BinlPrintDbg(( DEBUG_ERRORS,
  1126. "BinlInitializeEndpoint failed, %ld.\n", Error ));
  1127. }
  1128. return( Error );
  1129. }
  1130. DWORD
  1131. WaitForDsStartup(
  1132. VOID
  1133. )
  1134. {
  1135. const DWORD dwMaxWaitForDS = 5*60*1000;
  1136. HANDLE hDsStartupCompletedEvent = NULL;
  1137. DWORD i;
  1138. DWORD err = ERROR_DS_UNAVAILABLE;
  1139. DWORD waitStatus;
  1140. DWORD waitTime = BinlGlobalServiceStatus.dwWaitHint;
  1141. NT_PRODUCT_TYPE productType;
  1142. //
  1143. // Find out if we're on a DC. If we're not, there's no need to wait for
  1144. // the DS.
  1145. //
  1146. // RtlGetNtProductType shouldn't fail. If it does, just assume we're
  1147. // not on a DC.
  1148. //
  1149. if (!RtlGetNtProductType(&productType) || (productType != NtProductLanManNt)) {
  1150. return NO_ERROR;
  1151. }
  1152. //
  1153. // Wait up to five minutes for DS to finish startup, if it hasn't done so
  1154. // already.
  1155. //
  1156. for (i = 0; i < dwMaxWaitForDS; i += waitTime) {
  1157. if (hDsStartupCompletedEvent == NULL) {
  1158. hDsStartupCompletedEvent = OpenEvent(SYNCHRONIZE,
  1159. FALSE,
  1160. DS_SYNCED_EVENT_NAME_W);
  1161. }
  1162. if (hDsStartupCompletedEvent == NULL) {
  1163. //
  1164. // DS hasn't even gotten around to creating this event. This
  1165. // probably means the DS isn't *going* to be started, but let's
  1166. // not jump to conclusions.
  1167. //
  1168. BinlPrint((DEBUG_INIT, "DS startup has not begun; sleeping...\n"));
  1169. Sleep(waitTime);
  1170. } else {
  1171. //
  1172. // DS startup has begun.
  1173. //
  1174. waitStatus = WaitForSingleObject(hDsStartupCompletedEvent, waitTime);
  1175. if (waitStatus == WAIT_OBJECT_0) {
  1176. //
  1177. // DS startup completed (or failed).
  1178. //
  1179. BinlPrint((DEBUG_INIT, "DS startup completed.\n"));
  1180. err = NO_ERROR;
  1181. break;
  1182. } else if (WAIT_TIMEOUT == waitStatus) {
  1183. //
  1184. // DS startup still in progress.
  1185. //
  1186. BinlPrint((DEBUG_INIT, "DS is starting...\n"));
  1187. } else {
  1188. //
  1189. // Wait failure. Ignore the error.
  1190. //
  1191. BinlPrint((DEBUG_INIT, "Failed to wait on DS event handle;"
  1192. " waitStatus = %d, GLE = %d.\n", waitStatus, GetLastError()));
  1193. }
  1194. }
  1195. UpdateStatus();
  1196. }
  1197. if (hDsStartupCompletedEvent != NULL) {
  1198. CloseHandle(hDsStartupCompletedEvent);
  1199. }
  1200. return err;
  1201. }
  1202. DWORD
  1203. Initialize(
  1204. VOID
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. This function initialize the binl service global data structures and
  1209. starts up the service.
  1210. Arguments:
  1211. None.
  1212. Return Value:
  1213. The initialization status.
  1214. 0 - Success.
  1215. Positive - A windows error occurred.
  1216. Negative - A service specific error occured.
  1217. --*/
  1218. {
  1219. DWORD threadId;
  1220. DWORD Error;
  1221. WSADATA wsaData;
  1222. //
  1223. // Initialize all the status fields so that subsequent calls to
  1224. // SetServiceStatus need to only update fields that changed.
  1225. //
  1226. BinlGlobalServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  1227. BinlGlobalServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  1228. BinlGlobalServiceStatus.dwControlsAccepted = 0;
  1229. BinlGlobalServiceStatus.dwCheckPoint = 1;
  1230. BinlGlobalServiceStatus.dwWaitHint = 60000; // 60 secs.
  1231. BinlGlobalServiceStatus.dwWin32ExitCode = ERROR_SUCCESS;
  1232. BinlGlobalServiceStatus.dwServiceSpecificExitCode = 0;
  1233. //
  1234. // Initialize binl to receive service requests by registering the
  1235. // control handler.
  1236. //
  1237. #if DBG
  1238. if (!BinlGlobalRunningAsProcess) {
  1239. #endif
  1240. BinlGlobalServiceStatusHandle = RegisterServiceCtrlHandler(
  1241. BINL_SERVER,
  1242. ServiceControlHandler );
  1243. if ( BinlGlobalServiceStatusHandle == 0 ) {
  1244. Error = GetLastError();
  1245. BinlPrintDbg((DEBUG_INIT, "RegisterServiceCtrlHandlerW failed, "
  1246. "%ld.\n", Error));
  1247. BinlServerEventLog(
  1248. EVENT_SERVER_FAILED_REGISTER_SC,
  1249. EVENTLOG_ERROR_TYPE,
  1250. Error );
  1251. return(Error);
  1252. }
  1253. #if DBG
  1254. } // if (!BinlGlobalRunningAsProcess)
  1255. #endif
  1256. //
  1257. // Tell Service Controller that we are start pending.
  1258. //
  1259. UpdateStatus();
  1260. //
  1261. // Create the process termination event.
  1262. //
  1263. BinlGlobalProcessTerminationEvent =
  1264. CreateEvent(
  1265. NULL, // no security descriptor
  1266. TRUE, // MANUAL reset
  1267. FALSE, // initial state: not signalled
  1268. NULL); // no name
  1269. if ( BinlGlobalProcessTerminationEvent == NULL ) {
  1270. Error = GetLastError();
  1271. BinlPrintDbg((DEBUG_INIT, "Can't create ProcessTerminationEvent, "
  1272. "%ld.\n", Error));
  1273. return(Error);
  1274. }
  1275. BinlGlobalPnpEvent =
  1276. CreateEvent(
  1277. NULL, // no security descriptor
  1278. FALSE, // auto reset
  1279. FALSE, // initial state: not signalled
  1280. NULL); // no name
  1281. if ( BinlGlobalPnpEvent == NULL ) {
  1282. Error = GetLastError();
  1283. BinlPrintDbg((DEBUG_INIT, "Can't create PNP event, "
  1284. "%ld.\n", Error));
  1285. return(Error);
  1286. }
  1287. //
  1288. // create the ProcessMessage termination event
  1289. //
  1290. g_hevtProcessMessageComplete = CreateEvent(
  1291. NULL,
  1292. FALSE,
  1293. FALSE,
  1294. NULL
  1295. );
  1296. if ( !g_hevtProcessMessageComplete )
  1297. {
  1298. Error = GetLastError();
  1299. BinlPrintDbg( (DEBUG_INIT,
  1300. "Initialize(...) CreateEvent returned error %x\n",
  1301. Error )
  1302. );
  1303. return Error;
  1304. }
  1305. BinlPrint(( DEBUG_INIT, "Initializing .. \n", 0 ));
  1306. //
  1307. // Wait for the DS to start up.
  1308. //
  1309. Error = WaitForDsStartup();
  1310. if ( Error != ERROR_SUCCESS ) {
  1311. BinlPrintDbg(( DEBUG_INIT, "Wait for DS failed, %ld.\n", Error ));
  1312. BinlServerEventLog(
  1313. EVENT_SERVER_DS_WAIT_FAILED,
  1314. EVENTLOG_ERROR_TYPE,
  1315. Error );
  1316. return(Error);
  1317. }
  1318. Error = WSAStartup( WS_VERSION_REQUIRED, &wsaData);
  1319. if ( Error != ERROR_SUCCESS ) {
  1320. BinlPrintDbg(( DEBUG_INIT, "WSAStartup failed, %ld.\n", Error ));
  1321. BinlServerEventLog(
  1322. EVENT_SERVER_INIT_WINSOCK_FAILED,
  1323. EVENTLOG_ERROR_TYPE,
  1324. Error );
  1325. return(Error);
  1326. }
  1327. Error = InitializeData();
  1328. if ( Error != ERROR_SUCCESS ) {
  1329. BinlPrintDbg(( DEBUG_INIT, "Data initialization failed, %ld.\n",
  1330. Error ));
  1331. BinlServerEventLog(
  1332. EVENT_SERVER_INIT_DATA_FAILED,
  1333. EVENTLOG_ERROR_TYPE,
  1334. Error );
  1335. return(Error);
  1336. }
  1337. //
  1338. // if the SCP hasn't been created yet, then try to create it now.
  1339. // We do this before trying the read the SCP from the DS
  1340. // -- failure to read the SCP will mean that BINL won't startup properly
  1341. //
  1342. Error = CreateSCPIfNeeded(&BinlParametersRead);
  1343. if (Error != ERROR_SUCCESS ) {
  1344. BinlPrintDbg(( DEBUG_INIT, "Create SCP failed, %ld.\n", Error ));
  1345. BinlServerEventLog(
  1346. ERROR_BINL_SCP_CREATION_FAILED,
  1347. EVENTLOG_ERROR_TYPE,
  1348. Error );
  1349. }
  1350. if (BinlParametersRead) {
  1351. //
  1352. // this means that we created the SCP. When we try to read the SCP
  1353. // from the DS, it will probably fail the first time.
  1354. //
  1355. BinlPrint(( DEBUG_INIT, "BINLSVC created the SCP.\n" ));
  1356. }
  1357. BinlParametersRead = FALSE;
  1358. Error = BinlReadParameters( );
  1359. if ( Error != ERROR_SUCCESS ) {
  1360. BinlPrintDbg(( DEBUG_INIT, "Read parameters failed, %ld.\n",
  1361. Error ));
  1362. //
  1363. // Tell the scavenger to be hyper about reading parameters. Also, log
  1364. // an event indicating that we're in hyper mode and not truly
  1365. // initialized yet.
  1366. //
  1367. // In spite of this failure, we DO NOT fail to initialize BINLSVC.
  1368. // We assume that we'll eventually be able to read our parameters.
  1369. //
  1370. BinlHyperUpdateCount = 1;
  1371. BinlHyperUpdateSatisfied = FALSE;
  1372. BinlServerEventLog(
  1373. EVENT_SERVER_INIT_PARAMETERS_FAILED,
  1374. EVENTLOG_WARNING_TYPE,
  1375. Error );
  1376. } else {
  1377. BinlParametersRead = TRUE;
  1378. }
  1379. BinlPrintDbg(( DEBUG_INIT, "Data initialization succeeded.\n", 0 ));
  1380. // Get the DHCP UDP socket
  1381. Error = MaybeInitializeEndpoint( &BinlGlobalEndpointList[0],
  1382. NULL,
  1383. DHCP_SERVR_PORT);
  1384. if ( Error != ERROR_SUCCESS ) {
  1385. return WSAGetLastError();
  1386. };
  1387. if (g_Port) {
  1388. // Get the BINL UDP socket
  1389. Error = BinlInitializeEndpoint( &BinlGlobalEndpointList[1],
  1390. NULL,
  1391. g_Port);
  1392. if ( Error != ERROR_SUCCESS ) {
  1393. return WSAGetLastError();
  1394. };
  1395. }
  1396. //
  1397. // Initialize the OSChooser server.
  1398. //
  1399. Error = OscInitialize();
  1400. if ( Error != ERROR_SUCCESS ) {
  1401. BinlPrint(( DEBUG_INIT, "OSChooser initialization failed, %ld.\n",
  1402. Error ));
  1403. return Error;
  1404. };
  1405. //
  1406. // send heart beat to the service controller.
  1407. //
  1408. //
  1409. BinlGlobalServiceStatus.dwCheckPoint++;
  1410. UpdateStatus();
  1411. //
  1412. // Start a thread to queue the incoming BINL messages
  1413. //
  1414. BinlGlobalMessageHandle = CreateThread(
  1415. NULL,
  1416. 0,
  1417. (LPTHREAD_START_ROUTINE)BinlMessageLoop,
  1418. NULL,
  1419. 0,
  1420. &threadId );
  1421. if ( BinlGlobalMessageHandle == NULL ) {
  1422. Error = GetLastError();
  1423. BinlPrint((DEBUG_INIT, "Can't create Message Thread, %ld.\n", Error));
  1424. return(Error);
  1425. }
  1426. //
  1427. // Start a thread to process BINL messages
  1428. //
  1429. BinlGlobalProcessorHandle = CreateThread(
  1430. NULL,
  1431. 0,
  1432. (LPTHREAD_START_ROUTINE)BinlProcessingLoop,
  1433. NULL,
  1434. 0,
  1435. &threadId );
  1436. if ( BinlGlobalProcessorHandle == NULL ) {
  1437. Error = GetLastError();
  1438. BinlPrint((DEBUG_INIT, "Can't create ProcessThread, %ld.\n", Error));
  1439. return(Error);
  1440. }
  1441. Error = NetInfStartHandler();
  1442. if ( Error != ERROR_SUCCESS ) {
  1443. BinlPrint((DEBUG_INIT, "Can't start INF Handler thread, %ld.\n", Error));
  1444. return(Error);
  1445. }
  1446. BinlGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
  1447. BinlGlobalServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  1448. SERVICE_ACCEPT_SHUTDOWN |
  1449. SERVICE_ACCEPT_PAUSE_CONTINUE;
  1450. UpdateStatus();
  1451. BinlCurrentState = BINL_STARTED;
  1452. #if defined(REGISTRY_ROGUE)
  1453. //
  1454. // for now, temporarily set the rogue logic disabled. it can be
  1455. // enabled in the registry
  1456. //
  1457. if (RogueDetection) {
  1458. #endif
  1459. //
  1460. // initialize the rogue thread if DHCP server isn't running.
  1461. //
  1462. BinlRogueLoggedState = FALSE;
  1463. Error = MaybeStartRogueThread();
  1464. if ( Error != ERROR_SUCCESS ) {
  1465. BinlPrint((DEBUG_INIT, "Can't start rogue logic, %ld.\n", Error));
  1466. return(Error);
  1467. }
  1468. #if defined(REGISTRY_ROGUE)
  1469. } else {
  1470. // pull this out when we pull out the registry setting
  1471. BinlGlobalAuthorized = TRUE;
  1472. }
  1473. #endif
  1474. //
  1475. // finally set the server startup time.
  1476. //
  1477. //GetSystemTime(&BinlGlobalServerStartTime);
  1478. return ERROR_SUCCESS;
  1479. }
  1480. VOID
  1481. Shutdown(
  1482. IN DWORD ErrorCode
  1483. )
  1484. /*++
  1485. Routine Description:
  1486. This function shuts down the binl service.
  1487. Arguments:
  1488. ErrorCode - Supplies the error code of the failure
  1489. Return Value:
  1490. None.
  1491. --*/
  1492. {
  1493. DWORD Error;
  1494. BinlPrint((DEBUG_MISC, "Shutdown started ..\n" ));
  1495. //
  1496. // LOG an event if this is not a normal shutdown.
  1497. //
  1498. if( ErrorCode != ERROR_SUCCESS ) {
  1499. BinlServerEventLog(
  1500. EVENT_SERVER_SHUTDOWN,
  1501. EVENTLOG_ERROR_TYPE,
  1502. ErrorCode );
  1503. }
  1504. //
  1505. // Service is shuting down, may be due to some service problem or
  1506. // the administrator is stopping the service. Inform the service
  1507. // controller.
  1508. //
  1509. BinlGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  1510. BinlGlobalServiceStatus.dwCheckPoint = 1;
  1511. //
  1512. // Send the status response.
  1513. //
  1514. UpdateStatus();
  1515. if( BinlGlobalProcessTerminationEvent != NULL ) {
  1516. //
  1517. // set Termination Event so that other threads know about the
  1518. // shut down.
  1519. //
  1520. SetEvent( BinlGlobalProcessTerminationEvent );
  1521. //
  1522. // Close all sockets, so that the BinlProcessingLoop
  1523. // thread will come out of blocking Select() call.
  1524. //
  1525. // Close EndPoint sockets.
  1526. //
  1527. if( BinlGlobalEndpointList != NULL ) {
  1528. DWORD i;
  1529. for ( i = 0; i < BinlGlobalNumberOfNets ; i++ ) {
  1530. MaybeCloseEndpoint(&BinlGlobalEndpointList[i]);
  1531. }
  1532. BinlFreeMemory( BinlGlobalEndpointList );
  1533. }
  1534. BinlPnpSocket = INVALID_SOCKET;
  1535. //
  1536. // Wait for the threads to terminate, don't wait forever.
  1537. //
  1538. if( BinlGlobalProcessorHandle != NULL ) {
  1539. WaitForSingleObject(
  1540. BinlGlobalProcessorHandle,
  1541. THREAD_TERMINATION_TIMEOUT );
  1542. CloseHandle( BinlGlobalProcessorHandle );
  1543. BinlGlobalProcessorHandle = NULL;
  1544. }
  1545. //
  1546. // wait for the receive thread to complete.
  1547. //
  1548. if( BinlGlobalMessageHandle != NULL ) {
  1549. WaitForSingleObject(
  1550. BinlGlobalMessageHandle,
  1551. THREAD_TERMINATION_TIMEOUT );
  1552. CloseHandle( BinlGlobalMessageHandle );
  1553. BinlGlobalMessageHandle = NULL;
  1554. }
  1555. while ( !IsListEmpty( &BinlGlobalFreeRecvList ) )
  1556. {
  1557. BINL_REQUEST_CONTEXT *pRequestContext;
  1558. pRequestContext =
  1559. (BINL_REQUEST_CONTEXT *)
  1560. RemoveHeadList( &BinlGlobalFreeRecvList );
  1561. BinlFreeMemory( pRequestContext->ReceiveBuffer );
  1562. BinlFreeMemory( pRequestContext );
  1563. }
  1564. while ( !IsListEmpty( &BinlGlobalActiveRecvList ) )
  1565. {
  1566. BINL_REQUEST_CONTEXT *pRequestContext;
  1567. pRequestContext =
  1568. (BINL_REQUEST_CONTEXT *)
  1569. RemoveHeadList( &BinlGlobalActiveRecvList );
  1570. BinlFreeMemory( pRequestContext->ReceiveBuffer );
  1571. BinlFreeMemory( pRequestContext );
  1572. }
  1573. if ( BinlIsProcessMessageExecuting() )
  1574. {
  1575. //
  1576. // wait for the thread pool to shutdown
  1577. //
  1578. Error = WaitForSingleObject(
  1579. g_hevtProcessMessageComplete,
  1580. THREAD_TERMINATION_TIMEOUT
  1581. );
  1582. BinlAssert( WAIT_OBJECT_0 == Error );
  1583. }
  1584. //
  1585. // We free the ldap connections after all the threads are done because
  1586. // the connection BaseDN strings may be in use by the threads and
  1587. // we're about to free them in FreeConnections.
  1588. //
  1589. FreeConnections();
  1590. CloseHandle( g_hevtProcessMessageComplete );
  1591. g_hevtProcessMessageComplete = NULL;
  1592. }
  1593. BinlPrintDbg((DEBUG_MISC, "Client requests cleaned up.\n" ));
  1594. //
  1595. // send heart beat to the service controller.
  1596. //
  1597. //
  1598. BinlGlobalServiceStatus.dwCheckPoint++;
  1599. UpdateStatus();
  1600. //
  1601. // send heart beat to the service controller and
  1602. // reset wait time.
  1603. //
  1604. BinlGlobalServiceStatus.dwWaitHint = 60 * 1000; // 1 mins.
  1605. BinlGlobalServiceStatus.dwCheckPoint++;
  1606. UpdateStatus();
  1607. FreeIpAddressInfo();
  1608. //
  1609. // cleanup other data.
  1610. //
  1611. StopRogueThread( );
  1612. OscUninitialize();
  1613. WSACleanup();
  1614. DeleteCriticalSection( &BinlCacheListLock );
  1615. NetInfCloseHandler();
  1616. if ( BinlGlobalSCPPath ) {
  1617. BinlFreeMemory( BinlGlobalSCPPath );
  1618. BinlGlobalSCPPath = NULL;
  1619. }
  1620. if ( BinlGlobalServerDN ) {
  1621. BinlFreeMemory( BinlGlobalServerDN );
  1622. BinlGlobalServerDN = NULL;
  1623. }
  1624. if ( BinlGlobalGroupDN ) {
  1625. BinlFreeMemory( BinlGlobalGroupDN );
  1626. BinlGlobalGroupDN = NULL;
  1627. }
  1628. if ( BinlGlobalDefaultLanguage ) {
  1629. BinlFreeMemory( BinlGlobalDefaultLanguage );
  1630. BinlGlobalDefaultLanguage = NULL;
  1631. }
  1632. EnterCriticalSection( &gcsParameters );
  1633. if ( BinlGlobalDefaultContainer ) {
  1634. BinlFreeMemory( BinlGlobalDefaultContainer );
  1635. BinlGlobalDefaultContainer = NULL;
  1636. }
  1637. if ( NewMachineNamingPolicy != NULL ) {
  1638. BinlFreeMemory( NewMachineNamingPolicy );
  1639. NewMachineNamingPolicy = NULL;
  1640. }
  1641. if ( BinlGlobalOurDnsName ) {
  1642. BinlFreeMemory( BinlGlobalOurDnsName );
  1643. BinlGlobalOurDnsName = NULL;
  1644. }
  1645. if ( BinlGlobalOurDomainName ) {
  1646. BinlFreeMemory( BinlGlobalOurDomainName );
  1647. BinlGlobalOurDomainName = NULL;
  1648. }
  1649. if ( BinlGlobalOurServerName ) {
  1650. BinlFreeMemory( BinlGlobalOurServerName );
  1651. BinlGlobalOurServerName = NULL;
  1652. }
  1653. if ( BinlGlobalOurFQDNName ) {
  1654. BinlFreeMemory( BinlGlobalOurFQDNName );
  1655. BinlGlobalOurFQDNName = NULL;
  1656. }
  1657. LeaveCriticalSection( &gcsParameters );
  1658. if (BinlGlobalHaveOutstandingLsaNotify) {
  1659. Error = LsaUnregisterPolicyChangeNotification(
  1660. BINL_LSA_SERVER_NAME_POLICY,
  1661. BinlGlobalLsaDnsNameNotifyEvent
  1662. );
  1663. if (Error != ERROR_SUCCESS) {
  1664. BinlPrintDbg((DEBUG_INIT, "Can't close LSA notify, 0x%08x.\n", Error));
  1665. }
  1666. BinlGlobalHaveOutstandingLsaNotify = FALSE;
  1667. }
  1668. if (BinlGlobalLsaDnsNameNotifyEvent != NULL) {
  1669. CloseHandle( BinlGlobalLsaDnsNameNotifyEvent );
  1670. BinlGlobalLsaDnsNameNotifyEvent = NULL;
  1671. }
  1672. if ( BinlGlobalDefaultOrgname ) {
  1673. BinlFreeMemory( BinlGlobalDefaultOrgname );
  1674. BinlGlobalDefaultOrgname = NULL;
  1675. }
  1676. if ( BinlGlobalDefaultTimezone ) {
  1677. BinlFreeMemory( BinlGlobalDefaultTimezone );
  1678. BinlGlobalDefaultTimezone = NULL;
  1679. }
  1680. if ( BinlGlobalDefaultDS ) {
  1681. BinlFreeMemory( BinlGlobalDefaultDS );
  1682. BinlGlobalDefaultDS = NULL;
  1683. }
  1684. if ( BinlGlobalDefaultGC ) {
  1685. BinlFreeMemory( BinlGlobalDefaultGC );
  1686. BinlGlobalDefaultGC = NULL;
  1687. }
  1688. BinlPrint((DEBUG_MISC, "Shutdown Completed.\n" ));
  1689. //
  1690. // don't DebugUninitialize here -- we dump memory leaks
  1691. // during process detach which requires debug support.
  1692. //
  1693. //DebugUninitialize( );
  1694. //
  1695. // don't use BinlPrint past this point
  1696. //
  1697. BinlGlobalServiceStatus.dwCurrentState = SERVICE_STOPPED;
  1698. BinlGlobalServiceStatus.dwControlsAccepted = 0;
  1699. if ( ErrorCode >= 20000 && ErrorCode <= 20099 ) {
  1700. // Indicate that it is a BINL specific error code
  1701. BinlGlobalServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  1702. BinlGlobalServiceStatus.dwServiceSpecificExitCode = ErrorCode;
  1703. } else {
  1704. BinlGlobalServiceStatus.dwWin32ExitCode = ErrorCode;
  1705. BinlGlobalServiceStatus.dwServiceSpecificExitCode = 0;
  1706. }
  1707. BinlGlobalServiceStatus.dwCheckPoint = 0;
  1708. BinlGlobalServiceStatus.dwWaitHint = 0;
  1709. UpdateStatus();
  1710. }
  1711. VOID
  1712. ServiceEntry(
  1713. DWORD NumArgs,
  1714. LPWSTR *ArgsArray,
  1715. IN PTCPSVCS_GLOBAL_DATA pGlobalData
  1716. )
  1717. /*++
  1718. Routine Description:
  1719. This is the main routine of the BINL server service. After
  1720. the service has been initialized, this thread will wait on
  1721. BinlGlobalProcessTerminationEvent for a signal to terminate the service.
  1722. Arguments:
  1723. NumArgs - Supplies the number of strings specified in ArgsArray.
  1724. ArgsArray - Supplies string arguments that are specified in the
  1725. StartService API call. This parameter is ignored.
  1726. Return Value:
  1727. None.
  1728. --*/
  1729. {
  1730. DWORD Error;
  1731. #if !DBG
  1732. UNREFERENCED_PARAMETER(NumArgs);
  1733. UNREFERENCED_PARAMETER(ArgsArray);
  1734. #endif
  1735. DebugInitialize( );
  1736. #if DBG
  1737. //
  1738. // If we are running as a test process instead of as a service then
  1739. // recored it now so that we avoid calling into the service controller
  1740. // and failing.
  1741. //
  1742. if ((NumArgs == 2) &&
  1743. (ArgsArray == NULL)) {
  1744. BinlGlobalRunningAsProcess = TRUE;
  1745. } else {
  1746. BinlGlobalRunningAsProcess = FALSE;
  1747. }
  1748. #endif
  1749. //
  1750. // copy the process global data pointer to service global variable.
  1751. //
  1752. TcpsvcsGlobalData = pGlobalData;
  1753. Error = Initialize();
  1754. if ( Error == ERROR_SUCCESS) {
  1755. //
  1756. // If we were able to read our parameters from the DS, log an event
  1757. // indicating that we're ready to roll. If not, hold off on logging the
  1758. // event -- the scavenger will do it when it manages to get to the DS.
  1759. //
  1760. if ( BinlParametersRead ) {
  1761. BinlServerEventLog(
  1762. EVENT_SERVER_INIT_AND_READY,
  1763. EVENTLOG_INFORMATION_TYPE,
  1764. Error );
  1765. }
  1766. //
  1767. // perform Scavenge task until we are told to stop.
  1768. //
  1769. Error = Scavenger();
  1770. }
  1771. Shutdown( Error );
  1772. return;
  1773. }
  1774. VOID
  1775. BinlMessageLoop(
  1776. LPVOID Parameter
  1777. )
  1778. /*++
  1779. Routine Description:
  1780. This function is the message queuing thread. It loops
  1781. to receive messages that are arriving to all opened sockets and
  1782. queue them in the message queue. The queue length is fixed, so if the
  1783. queue becomes full, it deletes the oldest message from the queue to
  1784. add the new one.
  1785. The message processing thread pops out messages (last one first) and
  1786. process them. New messages are processed first because the
  1787. corresponding clients will least likely time-out, and hence the
  1788. throughput will be better. Also the processing thread throws
  1789. messages that are already timed out, this will stop server starving
  1790. problem.
  1791. Arguments:
  1792. Parameter - pointer to the parameter passed.
  1793. Return Value:
  1794. None.
  1795. --*/
  1796. {
  1797. DWORD Error,
  1798. SendResponse,
  1799. Signal;
  1800. BINL_REQUEST_CONTEXT *pRequestContext;
  1801. while ( 1 ) {
  1802. //
  1803. // dequeue an entry from the free list.
  1804. //
  1805. LOCK_RECV_LIST();
  1806. if( !IsListEmpty( &BinlGlobalFreeRecvList ) ) {
  1807. pRequestContext =
  1808. (BINL_REQUEST_CONTEXT *)
  1809. RemoveHeadList( &BinlGlobalFreeRecvList );
  1810. }
  1811. else {
  1812. //
  1813. // active message queue should be non-empty.
  1814. //
  1815. BinlAssert( IsListEmpty( &BinlGlobalActiveRecvList ) == FALSE );
  1816. BinlPrintDbg(( DEBUG_MISC, "A Message has been overwritten.\n"));
  1817. //
  1818. // dequeue an old entry from the queue.
  1819. //
  1820. pRequestContext =
  1821. (BINL_REQUEST_CONTEXT *)
  1822. RemoveHeadList( &BinlGlobalActiveRecvList );
  1823. }
  1824. UNLOCK_RECV_LIST();
  1825. //
  1826. // wait for message to arrive from of the open socket port.
  1827. //
  1828. MessageWait:
  1829. Error = BinlWaitForMessage( pRequestContext );
  1830. if( Error != ERROR_SUCCESS ) {
  1831. if( Error == ERROR_SEM_TIMEOUT ) {
  1832. //
  1833. // if we are asked to exit, do so.
  1834. //
  1835. Error = WaitForSingleObject( BinlGlobalProcessTerminationEvent, 0 );
  1836. if ( Error == ERROR_SUCCESS ) {
  1837. //
  1838. // The termination event has been signalled
  1839. //
  1840. //
  1841. // delete pRequestContext before exiting
  1842. //
  1843. ExitThread( 0 );
  1844. }
  1845. BinlAssert( Error == WAIT_TIMEOUT );
  1846. goto MessageWait;
  1847. }
  1848. else {
  1849. BinlPrintDbg(( DEBUG_ERRORS,
  1850. "BinlWaitForMessage failed, error = %ld\n", Error ));
  1851. goto MessageWait;
  1852. }
  1853. }
  1854. //
  1855. // time stamp the received message.
  1856. //
  1857. pRequestContext->TimeArrived = GetTickCount();
  1858. //
  1859. // queue the message in active queue.
  1860. //
  1861. LOCK_RECV_LIST();
  1862. //
  1863. // before adding this message, check the active list is empty, if
  1864. // so, signal the processing thread after adding this new message.
  1865. //
  1866. Signal = IsListEmpty( &BinlGlobalActiveRecvList );
  1867. InsertTailList( &BinlGlobalActiveRecvList, &pRequestContext->ListEntry );
  1868. if( Signal == TRUE ) {
  1869. if( !SetEvent( BinlGlobalRecvEvent) ) {
  1870. //
  1871. // Problem with setting the event to indicate the message
  1872. // processing queue the arrival of a new message.
  1873. //
  1874. BinlPrintDbg(( DEBUG_ERRORS,
  1875. "Error setting BinlGlobalRecvEvent %ld\n",
  1876. GetLastError()));
  1877. BinlAssert(FALSE);
  1878. }
  1879. }
  1880. UNLOCK_RECV_LIST();
  1881. }
  1882. //
  1883. // Abnormal thread termination.
  1884. //
  1885. ExitThread( 1 );
  1886. }
  1887. DWORD
  1888. BinlStartWorkerThread(
  1889. BINL_REQUEST_CONTEXT **ppContext
  1890. )
  1891. {
  1892. BYTE *pbSendBuffer = NULL,
  1893. *pbReceiveBuffer = NULL;
  1894. DWORD dwResult;
  1895. BINL_REQUEST_CONTEXT *pNewContext,
  1896. *pTempContext;
  1897. DWORD dwID;
  1898. HANDLE hThread;
  1899. pNewContext = BinlAllocateMemory( sizeof( *pNewContext ) );
  1900. if ( !pNewContext )
  1901. {
  1902. goto t_cleanup;
  1903. }
  1904. pbSendBuffer = BinlAllocateMemory( DHCP_SEND_MESSAGE_SIZE );
  1905. if ( !pbSendBuffer )
  1906. {
  1907. goto t_cleanup;
  1908. }
  1909. pbReceiveBuffer = BinlAllocateMemory( DHCP_RECV_MESSAGE_SIZE + 1 );
  1910. if ( !pbReceiveBuffer )
  1911. {
  1912. goto t_cleanup;
  1913. }
  1914. //
  1915. // Pass the input context to the worker thread and return the new
  1916. // context to the caller. This saves a memory copy.
  1917. //
  1918. SWAP( *ppContext, pNewContext );
  1919. (*ppContext)->ReceiveBuffer = pbReceiveBuffer;
  1920. pNewContext->SendBuffer = pbSendBuffer;
  1921. EnterCriticalSection( &g_ProcessMessageCritSect );
  1922. ++g_cProcessMessageThreads;
  1923. BinlAssert( g_cProcessMessageThreads <= g_cMaxProcessingThreads );
  1924. hThread = CreateThread(
  1925. NULL,
  1926. 0,
  1927. (LPTHREAD_START_ROUTINE) ProcessMessage,
  1928. pNewContext,
  1929. 0,
  1930. &dwID
  1931. );
  1932. if ( hThread )
  1933. {
  1934. //
  1935. // success
  1936. //
  1937. CloseHandle( hThread );
  1938. LeaveCriticalSection( &g_ProcessMessageCritSect );
  1939. return ERROR_SUCCESS;
  1940. }
  1941. --g_cProcessMessageThreads;
  1942. LeaveCriticalSection( &g_ProcessMessageCritSect );
  1943. //
  1944. // CreateThread failed. Swap restores the context pointers.
  1945. //
  1946. SWAP( *ppContext, pNewContext );
  1947. BinlPrintDbg( (DEBUG_ERRORS,
  1948. "BinlStartWorkerThread: CreateThread failed: %d\n" )
  1949. );
  1950. t_cleanup:
  1951. if ( pbReceiveBuffer )
  1952. {
  1953. BinlFreeMemory( pbReceiveBuffer );
  1954. }
  1955. if ( pbSendBuffer )
  1956. {
  1957. BinlFreeMemory( pbSendBuffer );
  1958. }
  1959. if ( pNewContext )
  1960. {
  1961. BinlFreeMemory( pNewContext );
  1962. }
  1963. BinlPrintDbg( ( DEBUG_ERRORS,
  1964. "BinlStartWorkerThread failed.\n"
  1965. ) );
  1966. return ERROR_NOT_ENOUGH_MEMORY;
  1967. }
  1968. #define PROCESS_TERMINATE_EVENT 0
  1969. #define PROCESS_MESSAGE_RECVD 1
  1970. #define PROCESS_EVENT_COUNT 2
  1971. VOID
  1972. BinlProcessingLoop(
  1973. VOID
  1974. )
  1975. /*++
  1976. Routine Description:
  1977. This function is the starting point for the main processing thread.
  1978. It loops to process queued messages, and sends replies.
  1979. Arguments:
  1980. RequestContext - A pointer to the request context block for
  1981. for this thread to use.
  1982. Return Value:
  1983. None.
  1984. --*/
  1985. {
  1986. DWORD Error,
  1987. Result;
  1988. HANDLE WaitHandle[PROCESS_EVENT_COUNT];
  1989. BINL_REQUEST_CONTEXT *pRequestContext;
  1990. WaitHandle[PROCESS_MESSAGE_RECVD] = BinlGlobalRecvEvent;
  1991. WaitHandle[PROCESS_TERMINATE_EVENT] = BinlGlobalProcessTerminationEvent;
  1992. while ( 1 ) {
  1993. //
  1994. // wait for one of the following event to occur :
  1995. // 1. if we are notified about the incoming message.
  1996. // 2. if we are asked to terminate
  1997. //
  1998. Result = WaitForMultipleObjects(
  1999. PROCESS_EVENT_COUNT, // num. of handles.
  2000. WaitHandle, // handle array.
  2001. FALSE, // wait for any.
  2002. INFINITE ); // timeout in msecs.
  2003. if (Result == PROCESS_TERMINATE_EVENT) {
  2004. //
  2005. // The termination event has been signalled
  2006. //
  2007. break;
  2008. }
  2009. if ( Result != PROCESS_MESSAGE_RECVD) {
  2010. BinlPrintDbg(( DEBUG_ERRORS,
  2011. "WaitForMultipleObjects returned invalid result, %ld.\n",
  2012. Result ));
  2013. //
  2014. // go back to wait.
  2015. //
  2016. continue;
  2017. }
  2018. //
  2019. // process all queued messages.
  2020. //
  2021. while( TRUE )
  2022. {
  2023. if ( BinlIsProcessMessageBusy() )
  2024. {
  2025. //
  2026. // All worker threads are active, so break to the outer loop.
  2027. // When a worker thread is finished it will set the
  2028. // PROCESS_MESSAGE_RECVD event.
  2029. BinlPrintDbg( (DEBUG_STOC,
  2030. "BinlProcessingLoop: All worker threads busy.\n" )
  2031. );
  2032. break;
  2033. }
  2034. LOCK_RECV_LIST();
  2035. if( IsListEmpty( &BinlGlobalActiveRecvList ) ) {
  2036. //
  2037. // no more message.
  2038. //
  2039. UNLOCK_RECV_LIST();
  2040. break;
  2041. }
  2042. //
  2043. // pop out a message from the active list ( *last one first* ).
  2044. //
  2045. pRequestContext =
  2046. (BINL_REQUEST_CONTEXT *) RemoveHeadList(&BinlGlobalActiveRecvList );
  2047. UNLOCK_RECV_LIST();
  2048. //
  2049. // if the message is too old, or if the maximum number of worker threads
  2050. // are running, discard the message.
  2051. //
  2052. if( GetTickCount() - pRequestContext->TimeArrived <
  2053. WAIT_FOR_RESPONSE_TIME * 1000 )
  2054. {
  2055. Error = BinlStartWorkerThread( &pRequestContext );
  2056. if ( ERROR_SUCCESS != Error )
  2057. {
  2058. BinlPrintDbg( (DEBUG_ERRORS,
  2059. "BinlProcessingLoop: BinlStartWorkerThread failed: %d\n",
  2060. Error )
  2061. );
  2062. }
  2063. } // if ( ( GetTickCount() < pRequestContext->TimeArrived...
  2064. else
  2065. {
  2066. BinlPrintDbg(( DEBUG_ERRORS, "A message has been timed out.\n" ));
  2067. }
  2068. //
  2069. // return this context to the free list
  2070. //
  2071. LOCK_RECV_LIST();
  2072. InsertTailList(
  2073. &BinlGlobalFreeRecvList,
  2074. &pRequestContext->ListEntry );
  2075. UNLOCK_RECV_LIST();
  2076. } // while (TRUE)
  2077. } // while( 1 )
  2078. //
  2079. // Abnormal thread termination.
  2080. //
  2081. ExitThread( 1 );
  2082. }
  2083. BOOL
  2084. BinlIsProcessMessageExecuting(
  2085. VOID
  2086. )
  2087. {
  2088. BOOL f;
  2089. EnterCriticalSection( &g_ProcessMessageCritSect );
  2090. f = g_cProcessMessageThreads;
  2091. LeaveCriticalSection( &g_ProcessMessageCritSect );
  2092. return f;
  2093. }
  2094. BOOL
  2095. BinlIsProcessMessageBusy(
  2096. VOID
  2097. )
  2098. {
  2099. BOOL f;
  2100. EnterCriticalSection( &g_ProcessMessageCritSect );
  2101. f = ( g_cProcessMessageThreads == g_cMaxProcessingThreads );
  2102. LeaveCriticalSection( &g_ProcessMessageCritSect );
  2103. return f;
  2104. }
  2105. #undef PROCESS_TERMINATE_EVENT
  2106. #undef PROCESS_EVENT_COUNT
  2107. #define PROCESS_TERMINATE_EVENT 0
  2108. #define PROCESS_PNP_EVENT 1
  2109. #define PROCESS_LSA_EVENT 2
  2110. #define PROCESS_EVENT_COUNT 3
  2111. DWORD
  2112. Scavenger(
  2113. VOID
  2114. )
  2115. /*++
  2116. Routine Description:
  2117. This function runs as an independant thread. It periodically wakes
  2118. up. Currently we have no work for it to do but I'm sure we will in the future.
  2119. Arguments:
  2120. None.
  2121. Return Value:
  2122. None.
  2123. --*/
  2124. {
  2125. BOOL fLeftCriticalSection = FALSE;
  2126. DWORD TimeOfLastScavenge = GetTickCount();
  2127. DWORD TimeOfLastDSScavenge = GetTickCount();
  2128. DWORD TimeOfLastParameterCheck = 0;
  2129. DWORD Error,
  2130. Result;
  2131. HANDLE WaitHandle[PROCESS_EVENT_COUNT];
  2132. DWORD secondsSinceLastScavenge;
  2133. WaitHandle[PROCESS_TERMINATE_EVENT] = BinlGlobalProcessTerminationEvent;
  2134. WaitHandle[PROCESS_PNP_EVENT] = BinlGlobalPnpEvent;
  2135. WaitHandle[PROCESS_LSA_EVENT] = BinlGlobalLsaDnsNameNotifyEvent;
  2136. while ((!BinlGlobalSystemShuttingDown) &&
  2137. (BinlGlobalServiceStatus.dwCurrentState != SERVICE_STOP_PENDING))
  2138. {
  2139. DWORD CurrentTime;
  2140. PLIST_ENTRY p;
  2141. //
  2142. // wait for one of the following event to occur :
  2143. // 1. if we are notified about a pnp change.
  2144. // 2. if we are asked to terminate
  2145. //
  2146. Result = WaitForMultipleObjects(
  2147. PROCESS_EVENT_COUNT, // num. of handles.
  2148. WaitHandle, // handle array.
  2149. FALSE, // wait for any.
  2150. BINL_HYPERMODE_TIMEOUT ); // timeout in msecs.
  2151. if (Result == PROCESS_TERMINATE_EVENT) {
  2152. //
  2153. // The termination event has been signalled
  2154. //
  2155. break;
  2156. } else if (Result == PROCESS_PNP_EVENT) {
  2157. //
  2158. // The pnp notify event has been signalled
  2159. //
  2160. GetIpAddressInfo( BINL_PNP_DELAY_SECONDS * 1000 );
  2161. Error = BinlSetupPnpWait( );
  2162. if (Error != 0) {
  2163. BinlPrintDbg(( DEBUG_ERRORS, "BinlScavenger could not set pnp event, %ld.\n", Error ));
  2164. }
  2165. } else if (Result == PROCESS_LSA_EVENT) {
  2166. Error = GetOurServerInfo( );
  2167. if (Error != ERROR_SUCCESS) {
  2168. BinlPrintDbg(( DEBUG_ERRORS, "BinlScavenger could not get server name info, 0x%08x.\n", Error ));
  2169. }
  2170. }
  2171. //
  2172. // Capture the current time (in milliseconds).
  2173. //
  2174. CurrentTime = GetTickCount( );
  2175. secondsSinceLastScavenge = CurrentTime - TimeOfLastScavenge;
  2176. //
  2177. // If we haven't scavenged recently, do so now.
  2178. //
  2179. if ( secondsSinceLastScavenge >= BinlGlobalScavengerSleep ) {
  2180. HANDLE hFind;
  2181. WCHAR SifFilePath[MAX_PATH];
  2182. WIN32_FIND_DATA FindData;
  2183. ULARGE_INTEGER CurrentTimeConv,FileTime;
  2184. FILETIME CurrentFileTime;
  2185. PWSTR ptr;
  2186. TimeOfLastScavenge = CurrentTime;
  2187. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging Clients...\n"));
  2188. fLeftCriticalSection = FALSE;
  2189. EnterCriticalSection(&ClientsCriticalSection);
  2190. for (p = ClientsQueue.Flink; p != &ClientsQueue; p = p->Flink)
  2191. {
  2192. PCLIENT_STATE TempClient;
  2193. TempClient = CONTAINING_RECORD(p, CLIENT_STATE, Linkage);
  2194. if ( CurrentTime - TempClient->LastUpdate > BinlClientTimeout * 1000 )
  2195. {
  2196. BOOL FreeClientState;
  2197. BinlPrintDbg((DEBUG_SCAVENGER, "Savenger deleting client = 0x%08x\n", TempClient ));
  2198. RemoveEntryList(&TempClient->Linkage);
  2199. TempClient->PositiveRefCount++; // one for CS
  2200. LeaveCriticalSection(&ClientsCriticalSection);
  2201. fLeftCriticalSection = TRUE;
  2202. EnterCriticalSection(&TempClient->CriticalSection);
  2203. TempClient->NegativeRefCount += 2; // one for CS and one of Logoff
  2204. //
  2205. // FreeClientState will be TRUE if the two refcounts are equal.
  2206. // Otherwize another thread is being held by the clientState's CS
  2207. // and it will take care of deleting the CS when it's done.
  2208. //
  2209. FreeClientState = (BOOL)(TempClient->PositiveRefCount == TempClient->NegativeRefCount);
  2210. LeaveCriticalSection(&TempClient->CriticalSection);
  2211. if (FreeClientState)
  2212. {
  2213. FreeClient(TempClient);
  2214. }
  2215. break;
  2216. }
  2217. }
  2218. if ( !fLeftCriticalSection ) {
  2219. LeaveCriticalSection(&ClientsCriticalSection);
  2220. }
  2221. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging Clients Complete\n"));
  2222. //
  2223. // scavenge the SIF files
  2224. //
  2225. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging SIF Files...\n"));
  2226. GetSystemTimeAsFileTime( &CurrentFileTime );
  2227. CurrentTimeConv.LowPart = CurrentFileTime.dwLowDateTime;
  2228. CurrentTimeConv.HighPart = CurrentFileTime.dwHighDateTime;
  2229. if ( _snwprintf( SifFilePath,
  2230. sizeof(SifFilePath) / sizeof(SifFilePath[0]),
  2231. L"%ws\\%ws\\",
  2232. IntelliMirrorPathW,
  2233. TEMP_DIRECTORY ) >= 0 ) {
  2234. SifFilePath[MAX_PATH-1] = L'\0'; // throw in terminating null just to be safe
  2235. ptr = SifFilePath + wcslen(SifFilePath);
  2236. wcscat(SifFilePath,L"*.sif");
  2237. hFind = FindFirstFile(SifFilePath,&FindData);
  2238. if (hFind != INVALID_HANDLE_VALUE) {
  2239. do {
  2240. FileTime.LowPart = FindData.ftCreationTime.dwLowDateTime;
  2241. FileTime.HighPart = FindData.ftCreationTime.dwHighDateTime;
  2242. FileTime.QuadPart += BinlSifFileScavengerTime.QuadPart;
  2243. //
  2244. // if the file has been on the server long enough,
  2245. // we delete it
  2246. //
  2247. if (_wcsicmp(FindData.cFileName,L".") != 0 &&
  2248. _wcsicmp(FindData.cFileName,L"..") != 0 &&
  2249. CurrentTimeConv.QuadPart > FileTime.QuadPart) {
  2250. *ptr = L'\0';
  2251. wcscat(SifFilePath,FindData.cFileName);
  2252. BinlPrintDbg((DEBUG_SCAVENGER,
  2253. "Attempting to scavenge SIF File %S...\n",
  2254. SifFilePath));
  2255. SetFileAttributes(SifFilePath,FILE_ATTRIBUTE_NORMAL);
  2256. if (!DeleteFile(SifFilePath)) {
  2257. BinlPrintDbg((DEBUG_SCAVENGER,
  2258. "Failed to scavenge SIF File %S, ec = %d\n",
  2259. SifFilePath,
  2260. GetLastError() ));
  2261. }
  2262. }
  2263. } while ( FindNextFile(hFind,&FindData) );
  2264. FindClose( hFind );
  2265. }
  2266. }
  2267. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging SIF Files Complete\n"));
  2268. }
  2269. secondsSinceLastScavenge = CurrentTime - TimeOfLastDSScavenge;
  2270. if ( secondsSinceLastScavenge >= BinlGlobalLdapErrorScavenger) {
  2271. TimeOfLastDSScavenge = CurrentTime;
  2272. if (BinlGlobalLdapErrorCount >= BinlGlobalMaxLdapErrorsLogged) {
  2273. ULONG seconds = BinlGlobalLdapErrorScavenger / 1000;
  2274. PWCHAR strings[2];
  2275. WCHAR secondsString[10];
  2276. swprintf(secondsString, L"%d", seconds);
  2277. strings[0] = secondsString;
  2278. strings[1] = NULL;
  2279. BinlReportEventW( EVENT_WARNING_LDAP_ERRORS,
  2280. EVENTLOG_WARNING_TYPE,
  2281. 1,
  2282. sizeof(BinlGlobalLdapErrorCount),
  2283. strings,
  2284. &BinlGlobalLdapErrorCount
  2285. );
  2286. }
  2287. BinlGlobalLdapErrorCount = 0;
  2288. }
  2289. //
  2290. // If we haven't read our parameters recently, do so now.
  2291. //
  2292. // "Recently" is normally a long time period -- defaulting to four hours.
  2293. // But when we are in "hyper" mode, we read our parameters every minute.
  2294. // There are two reasons to be in "hyper" mode:
  2295. //
  2296. // 1. We were not able to read our parameters during initialization. We
  2297. // need to get the parameters quickly so that we can truly consider
  2298. // ourselves initialized. In this case, BinlHyperUpdateCount will
  2299. // always be 1.
  2300. //
  2301. // 2. We were told by the admin UI that our parameters had changed. We
  2302. // need to read the parameters a number of times over a period of
  2303. // time because of DS propagation delays. In this case,
  2304. // BinlHyperUpdateCount starts at BINL_HYPERMODE_RETRY_COUNT (30),
  2305. // and is decremented each time we attempt to read our parameters.
  2306. //
  2307. // If we are not in hyper mode, then we try to read our parameters and
  2308. // we don't care if we fail. If we are in hyper mode, then we decrement
  2309. // BinlHyperUpdateCount each time we try to read our parameters, and we
  2310. // stay in hyper mode until BinlHyperUpdateCount is decremented to 0.
  2311. // But we don't let the count go to 0 until we have successfully read
  2312. // our parameters at least once while in hyper mode.
  2313. if ( (CurrentTime - TimeOfLastParameterCheck) >=
  2314. ((BinlHyperUpdateCount != 0) ? BINL_HYPERMODE_TIMEOUT : BinlUpdateFromDSTimeout) ) {
  2315. TimeOfLastParameterCheck = CurrentTime;
  2316. BinlPrintDbg((DEBUG_SCAVENGER, "Reading parameters...\n"));
  2317. Error = BinlReadParameters( );
  2318. //
  2319. // If we're not in hyper mode, we don't care if reading the
  2320. // parameters failed. But if we're in hyper mode, we have
  2321. // to do some extra work.
  2322. //
  2323. if ( BinlHyperUpdateCount != 0 ) {
  2324. //
  2325. // If the read worked, then we set BinlHyperUpdateSatisfied.
  2326. // Also, if this is the first time we've managed to read
  2327. // our parameters, we log an event indicating that we're
  2328. // ready.
  2329. //
  2330. if ( Error == ERROR_SUCCESS ) {
  2331. BinlHyperUpdateSatisfied = TRUE;
  2332. if ( !BinlParametersRead ) {
  2333. BinlParametersRead = TRUE;
  2334. BinlServerEventLog(
  2335. EVENT_SERVER_INIT_AND_READY,
  2336. EVENTLOG_INFORMATION_TYPE,
  2337. Error );
  2338. }
  2339. }
  2340. //
  2341. // Decrement the update count. However, if we have not yet
  2342. // managed to read our parameters while in hyper mode, don't
  2343. // let the count go to 0.
  2344. //
  2345. BinlHyperUpdateCount--;
  2346. if ( (BinlHyperUpdateCount == 0) && !BinlHyperUpdateSatisfied ) {
  2347. BinlHyperUpdateCount = 1;
  2348. }
  2349. BinlPrintDbg((DEBUG_SCAVENGER, "Hypermode count: %u\n", BinlHyperUpdateCount ));
  2350. }
  2351. BinlPrintDbg((DEBUG_SCAVENGER, "Reading parameters complete\n"));
  2352. }
  2353. }
  2354. if (BinlGlobalPnpEvent != NULL) {
  2355. CloseHandle( BinlGlobalPnpEvent );
  2356. BinlGlobalPnpEvent = NULL;
  2357. }
  2358. return( ERROR_SUCCESS );
  2359. }
  2360. VOID
  2361. TellBinlState(
  2362. int NewState
  2363. )
  2364. /*++
  2365. Routine Description:
  2366. This routine is called by DHCP when it starts (when we need to stop
  2367. listening on the DHCP socket) and when it stops (when we need to start).
  2368. Arguments:
  2369. NewState - Supplies DHCP's state.
  2370. Return Value:
  2371. None.
  2372. --*/
  2373. {
  2374. BOOLEAN haveLock = TRUE;
  2375. EnterCriticalSection(&gcsDHCPBINL);
  2376. //
  2377. // If BinlGlobalEndpointList is NULL then BINL isn't started so just
  2378. // record the NewState
  2379. //
  2380. if (NewState == DHCP_STARTING) {
  2381. if (DHCPState == DHCP_STOPPED) {
  2382. // DHCP is going from stopped to running.
  2383. DHCPState = NewState;
  2384. // BINL needs to close the DHCP socket so that DHCP can receive datagrams
  2385. if (BinlCurrentState != BINL_STOPPED) {
  2386. MaybeCloseEndpoint( &BinlGlobalEndpointList[0]);
  2387. LeaveCriticalSection(&gcsDHCPBINL);
  2388. haveLock = FALSE;
  2389. StopRogueThread( );
  2390. }
  2391. } else {
  2392. BinlAssert( DHCPState == DHCP_STARTING );
  2393. }
  2394. } else if (NewState == DHCP_STOPPED) {
  2395. if (DHCPState == DHCP_STARTING) {
  2396. // DHCP is going from running to stopped.
  2397. DHCPState = NewState;
  2398. if (BinlCurrentState != BINL_STOPPED) {
  2399. MaybeInitializeEndpoint( &BinlGlobalEndpointList[0],
  2400. NULL,
  2401. DHCP_SERVR_PORT);
  2402. LeaveCriticalSection(&gcsDHCPBINL);
  2403. haveLock = FALSE;
  2404. MaybeStartRogueThread( );
  2405. }
  2406. } else {
  2407. BinlAssert( DHCPState == DHCP_STOPPED );
  2408. }
  2409. } else if (NewState == DHCP_AUTHORIZED) {
  2410. HandleRogueAuthorized( );
  2411. } else if (NewState == DHCP_NOT_AUTHORIZED) {
  2412. HandleRogueUnauthorized( );
  2413. } else {
  2414. BinlPrintDbg((DEBUG_ERRORS, "TellBinlState called with 0x%x\n", NewState ));
  2415. }
  2416. if (haveLock) {
  2417. LeaveCriticalSection(&gcsDHCPBINL);
  2418. }
  2419. return;
  2420. }
  2421. BOOL
  2422. BinlState (
  2423. VOID
  2424. )
  2425. /*++
  2426. Routine Description:
  2427. This routine is called by DHCP when it starts (when we need to stop
  2428. listening on the DHCP socket) and when it stops (when we need to start).
  2429. Arguments:
  2430. None.
  2431. Return Value:
  2432. TRUE if BINL running.
  2433. --*/
  2434. {
  2435. return (BinlCurrentState == BINL_STARTED)?TRUE:FALSE;
  2436. }
  2437. BOOLEAN
  2438. BinlDllInitialize(
  2439. IN HINSTANCE DllHandle,
  2440. IN ULONG Reason,
  2441. IN LPVOID lpReserved OPTIONAL
  2442. )
  2443. {
  2444. //
  2445. // Handle attaching binlsvc.dll to a new process.
  2446. //
  2447. //DebugBreak( );
  2448. if (Reason == DLL_PROCESS_ATTACH) {
  2449. INITIALIZE_TRACE_MEMORY;
  2450. //
  2451. // Initialize critical sections.
  2452. //
  2453. InitializeCriticalSection( &gcsDHCPBINL );
  2454. InitializeCriticalSection( &gcsParameters );
  2455. // don't call in here with thread attach/detach notices please...
  2456. DisableThreadLibraryCalls( DllHandle );
  2457. //
  2458. // When DLL_PROCESS_DETACH and lpReserved is NULL, then a FreeLibrary
  2459. // call is being made. If lpReserved is Non-NULL, and ExitProcess is
  2460. // in progress. These cleanup routines will only be called when
  2461. // a FreeLibrary is being called. ExitProcess will automatically
  2462. // clean up all process resources, handles, and pending io.
  2463. //
  2464. } else if ((Reason == DLL_PROCESS_DETACH) &&
  2465. (lpReserved == NULL)) {
  2466. UNINITIALIZE_TRACE_MEMORY;
  2467. DeleteCriticalSection( &gcsParameters );
  2468. DeleteCriticalSection( &gcsDHCPBINL );
  2469. //
  2470. // uninitialize the debugging engine last, after
  2471. // we're done printing out the memory leak list,
  2472. // etc.
  2473. //
  2474. DebugUninitialize();
  2475. }
  2476. return TRUE;
  2477. }
  2478. VOID
  2479. SendWakeup(
  2480. PENDPOINT pEndpoint
  2481. )
  2482. /*++
  2483. Routine Description:
  2484. Send a loopback packet to the BINL socket. This will cause the
  2485. select to change so that it includes or excludes the DHCP socket
  2486. as appropriate.
  2487. Arguments:
  2488. pEndpoint - Supplies the socket to send the packet on.
  2489. Return Value:
  2490. None.
  2491. --*/
  2492. {
  2493. DHCP_MESSAGE SendBuffer;
  2494. SOCKADDR_IN saUdpServ;
  2495. RtlZeroMemory(&SendBuffer, sizeof(SendBuffer));
  2496. // We ignore anything that is not BOOT_REQUEST
  2497. SendBuffer.Operation = ~BOOT_REQUEST;
  2498. saUdpServ.sin_family = AF_INET;
  2499. saUdpServ.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
  2500. saUdpServ.sin_port = htons ( (USHORT)g_Port );
  2501. BinlPrintDbg((DEBUG_MISC, "Sending dummy packet\n"));
  2502. sendto( pEndpoint->Socket,
  2503. (char *)&SendBuffer,
  2504. sizeof(SendBuffer),
  2505. 0,
  2506. (const struct sockaddr *)&saUdpServ,
  2507. sizeof ( SOCKADDR_IN )
  2508. );
  2509. }
  2510. DWORD
  2511. MaybeInitializeEndpoint(
  2512. PENDPOINT pEndpoint,
  2513. PDHCP_IP_ADDRESS pIpAddress,
  2514. DWORD Port
  2515. )
  2516. /*++
  2517. Routine Description:
  2518. This function initializes an endpoint by creating and binding a
  2519. socket to the local address if DHCP is not running.
  2520. Arguments:
  2521. pEndpoint - Receives a pointer to the newly created socket
  2522. pIpAddress - The IP address to initialize to INADDR_ANY if NULL.
  2523. Port - The port to bind to.
  2524. Return Value:
  2525. The status of the operation.
  2526. --*/
  2527. {
  2528. DWORD Error = ERROR_SUCCESS;
  2529. EnterCriticalSection(&gcsDHCPBINL);
  2530. if (DHCPState == DHCP_STOPPED) {
  2531. Error = BinlInitializeEndpoint( pEndpoint,
  2532. pIpAddress,
  2533. Port);
  2534. BinlPrintDbg((DEBUG_MISC, "Opened Socket %lx\n", pEndpoint->Socket ));
  2535. //
  2536. // We may have a thread already doing a select and listening to
  2537. // the BINL socket. Send a dummy packet so that it will do a new
  2538. // select that includes this socket.
  2539. //
  2540. if ( Error == ERROR_SUCCESS ) {
  2541. SendWakeup(pEndpoint);
  2542. }
  2543. }
  2544. LeaveCriticalSection(&gcsDHCPBINL);
  2545. return Error;
  2546. }
  2547. VOID
  2548. MaybeCloseEndpoint(
  2549. PENDPOINT pEndpoint
  2550. )
  2551. /*++
  2552. Routine Description:
  2553. This function closes an endpoint if it is open. Usually caused
  2554. when DHCP starts/
  2555. Arguments:
  2556. pEndpoint - Pointer to the socket
  2557. Return Value:
  2558. None.
  2559. --*/
  2560. {
  2561. EnterCriticalSection(&gcsDHCPBINL);
  2562. if( pEndpoint->Socket != 0 ) {
  2563. //
  2564. // Set pEndpoint->Socket to 0 first so that the wait loop gets only
  2565. // one error when we close the socket. Otherwise there is a race until
  2566. // we get it set to 0 where the wait loop will loop quickly failing.
  2567. //
  2568. SOCKET Socket = pEndpoint->Socket;
  2569. BinlPrintDbg((DEBUG_MISC, "Close Socket %lx\n", Socket ));
  2570. pEndpoint->Socket = 0;
  2571. closesocket( Socket );
  2572. }
  2573. LeaveCriticalSection(&gcsDHCPBINL);
  2574. }
  2575. //
  2576. // Create a copy of a string by allocating heap memory.
  2577. //
  2578. LPSTR
  2579. BinlStrDupA( LPCSTR pStr )
  2580. {
  2581. DWORD dwLen;
  2582. LPSTR psz;
  2583. if (!pStr) {
  2584. return(NULL);
  2585. }
  2586. dwLen = (strlen( pStr ) + 1) * sizeof(CHAR);
  2587. psz = BinlAllocateMemory( dwLen );
  2588. if (psz) {
  2589. memcpy( psz, pStr, dwLen );
  2590. }
  2591. return psz;
  2592. }
  2593. LPWSTR
  2594. BinlStrDupW( LPCWSTR pStr )
  2595. {
  2596. DWORD dwLen;
  2597. LPWSTR psz;
  2598. if (!pStr) {
  2599. return(NULL);
  2600. }
  2601. dwLen = (wcslen( pStr ) + 1) * sizeof(WCHAR);
  2602. psz = (LPWSTR) BinlAllocateMemory( dwLen );
  2603. if (psz) {
  2604. memcpy( psz, pStr, dwLen );
  2605. }
  2606. return psz;
  2607. }
  2608. BOOL
  2609. BinlAnsiToUnicode(
  2610. IN PSTR AnsiString,
  2611. OUT PWSTR UnicodeBuffer,
  2612. IN OUT USHORT UnicodeBufferSize
  2613. )
  2614. {
  2615. ANSI_STRING aString;
  2616. UNICODE_STRING uString;
  2617. NTSTATUS Status;
  2618. RtlInitAnsiString(&aString, AnsiString);
  2619. uString.Buffer = UnicodeBuffer;
  2620. uString.Length = uString.MaximumLength = UnicodeBufferSize;
  2621. Status = RtlAnsiStringToUnicodeString(&uString,&aString,FALSE);
  2622. return (NT_SUCCESS(Status));
  2623. }
  2624. BOOL
  2625. BinlUnicodeToAnsi(
  2626. IN PWSTR UnicodeString,
  2627. OUT PSTR AnsiBuffer,
  2628. OUT USHORT AnsiBufferSize
  2629. )
  2630. {
  2631. ANSI_STRING aString;
  2632. UNICODE_STRING uString;
  2633. NTSTATUS Status;
  2634. RtlInitUnicodeString(&uString, UnicodeString);
  2635. aString.Buffer = AnsiBuffer;
  2636. aString.Length = aString.MaximumLength = AnsiBufferSize;
  2637. Status = RtlUnicodeStringToAnsiString(&aString,&uString,FALSE);
  2638. return (NT_SUCCESS(Status));
  2639. }
  2640. NTSTATUS
  2641. BinlSetupPnpWait (
  2642. VOID
  2643. )
  2644. {
  2645. NTSTATUS Error;
  2646. ULONG bytesRequired = 0;
  2647. BinlAssert(BinlPnpSocket != INVALID_SOCKET);
  2648. memset((PCHAR) &BinlPnpOverlapped, '\0', sizeof( WSAOVERLAPPED ));
  2649. BinlPnpOverlapped.hEvent = BinlGlobalPnpEvent;
  2650. Error = WSAIoctl( BinlPnpSocket,
  2651. SIO_ADDRESS_LIST_CHANGE,
  2652. NULL,
  2653. 0,
  2654. NULL,
  2655. 0,
  2656. &bytesRequired,
  2657. &BinlPnpOverlapped,
  2658. NULL
  2659. );
  2660. if (Error != 0) {
  2661. Error = WSAGetLastError();
  2662. //
  2663. // a return code of ERROR_IO_PENDING is perfectly valid here.
  2664. //
  2665. if (Error == ERROR_IO_PENDING) {
  2666. Error = 0;
  2667. }
  2668. }
  2669. return Error;
  2670. }