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

3447 lines
91 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. //
  21. // The following was lifted from \nt\private\ds\src\inc\ntdsa.h
  22. //
  23. #define NTDS_DELAYED_STARTUP_COMPLETED_EVENT TEXT("NtdsDelayedStartupCompletedEvent")
  24. #define BINL_PNP_DELAY_SECONDS 10
  25. #define BINL_LSA_SERVER_NAME_POLICY PolicyNotifyDnsDomainInformation
  26. //
  27. // module variables
  28. //
  29. PSECURITY_DESCRIPTOR s_SecurityDescriptor = NULL;
  30. struct l_timeval BinlLdapSearchTimeout;
  31. ULARGE_INTEGER BinlSifFileScavengerTime;
  32. #if defined(REGISTRY_ROGUE)
  33. BOOL RogueDetection = FALSE;
  34. #endif
  35. VOID
  36. FreeClient(
  37. PCLIENT_STATE client
  38. );
  39. DWORD
  40. UpdateStatus(
  41. VOID
  42. )
  43. /*++
  44. Routine Description:
  45. This function updates the binl service status with the Service
  46. Controller.
  47. Arguments:
  48. None.
  49. Return Value:
  50. Return code from SetServiceStatus.
  51. --*/
  52. {
  53. DWORD Error = ERROR_SUCCESS;
  54. #if DBG
  55. if (BinlGlobalRunningAsProcess) {
  56. return(Error);
  57. }
  58. #endif
  59. if ( BinlGlobalServiceStatusHandle != 0 ) {
  60. if (!SetServiceStatus(
  61. BinlGlobalServiceStatusHandle,
  62. &BinlGlobalServiceStatus)) {
  63. Error = GetLastError();
  64. BinlPrintDbg((DEBUG_ERRORS, "SetServiceStatus failed, %ld.\n", Error ));
  65. }
  66. }
  67. return(Error);
  68. }
  69. //
  70. // BinlReadParameters( )
  71. //
  72. DWORD
  73. BinlReadParameters( )
  74. {
  75. DWORD dwDSErr;
  76. DWORD dwErr;
  77. HKEY KeyHandle;
  78. UINT uResult;
  79. PWCHAR LanguageString;
  80. PWCHAR OrgnameString;
  81. PWCHAR TimezoneString;
  82. TIME_ZONE_INFORMATION TimeZoneInformation;
  83. HKEY KeyHandle2 = NULL;
  84. DWORD Index;
  85. //
  86. // Get any registry overrides
  87. //
  88. dwErr = RegOpenKeyEx(
  89. HKEY_LOCAL_MACHINE,
  90. BINL_PARAMETERS_KEY,
  91. 0,
  92. KEY_QUERY_VALUE,
  93. &KeyHandle );
  94. if ( dwErr != ERROR_SUCCESS ) {
  95. KeyHandle = NULL;
  96. }
  97. BinlRegGetValue( KeyHandle, BINL_DEFAULT_CONTAINER , REG_SZ, (LPBYTE *)&BinlGlobalDefaultContainer );
  98. BinlRegGetValue( KeyHandle, BINL_DEFAULT_DOMAIN, REG_SZ, (LPBYTE *)&DefaultDomain );
  99. BinlRegGetValue( KeyHandle, BINL_DEFAULT_DS, REG_SZ, (LPBYTE *)&BinlGlobalDefaultDS );
  100. BinlRegGetValue( KeyHandle, BINL_DEFAULT_GC, REG_SZ, (LPBYTE *)&BinlGlobalDefaultGC );
  101. AllowNewClients = ReadDWord( KeyHandle, BINL_ALLOW_NEW_CLIENTS, AllowNewClients );
  102. #if defined(REGISTRY_ROGUE)
  103. RogueDetection = ReadDWord( KeyHandle, L"RogueDetection", RogueDetection );
  104. #endif
  105. BinlClientTimeout = ReadDWord( KeyHandle, BINL_CLIENT_TIMEOUT, 900 );
  106. BinlPrint((DEBUG_OPTIONS, "Client Timeout = %u seconds\n", BinlClientTimeout ));
  107. g_Port = ReadDWord( KeyHandle, BINL_PORT_NAME, BINL_DEFAULT_PORT );
  108. BinlPrint((DEBUG_OPTIONS, "Port Number = %u\n", g_Port ));
  109. //
  110. // BinlGlobalScavengerSleep and BinlUpdateFromDSTimeout are specified in
  111. // the registry in seconds, but are maintained internally in milliseconds.
  112. //
  113. BinlGlobalScavengerSleep = ReadDWord( KeyHandle, BINL_SCAVENGER_SLEEP, 60 ); // seconds
  114. BinlGlobalScavengerSleep *= 1000; // convert to milliseconds
  115. BinlPrint((DEBUG_OPTIONS, "Scavenger Timeout = %u milliseconds\n", BinlGlobalScavengerSleep ));
  116. Index = ReadDWord( KeyHandle, BINL_SCAVENGER_SIFFILE, 24 ); // hours
  117. if (Index == 0 ) {
  118. Index = 24;
  119. }
  120. //
  121. // BinlSifFileScavengerTime is read from the registry in seconds, but is
  122. // maintained internally as a filetime, which has a resolution of 100 ns
  123. // intervals (100 ns == 10^7)
  124. //
  125. BinlSifFileScavengerTime.QuadPart = (ULONGLONG)(Index * 60) * 60 * 1000 * 10000;
  126. BinlPrint((DEBUG_OPTIONS, "SIF File Scavenger Timeout = %d hours\n", Index ));
  127. BinlUpdateFromDSTimeout = ReadDWord( KeyHandle, BINL_UPDATE_PARAMETER_POLL, 4 * 60 * 60 ); // seconds
  128. BinlUpdateFromDSTimeout *= 1000; // convert to milliseconds
  129. BinlPrint((DEBUG_OPTIONS, "Update from DS Timeout = %u milliseconds\n", BinlUpdateFromDSTimeout ));
  130. //
  131. // Setup the variables which control how many ldap errors we log at most
  132. // during a given time period and what the time period is.
  133. //
  134. BinlGlobalMaxLdapErrorsLogged = ReadDWord( KeyHandle, BINL_DS_ERROR_COUNT_PARAMETER, 10 );
  135. BinlGlobalLdapErrorScavenger = ReadDWord( KeyHandle, BINL_DS_ERROR_SLEEP, 10 * 60 ); // seconds, default to 10 minutes
  136. BinlGlobalLdapErrorScavenger *= 1000; // convert to milliseconds
  137. BinlPrint((DEBUG_OPTIONS, "DS Error log timeout = %u milliseconds\n", BinlGlobalLdapErrorScavenger ));
  138. //
  139. // get the min time to wait before we respond to a new client
  140. //
  141. // It defaults to 7 because it will then ignore the first two packets
  142. // and respond starting at the third. After testing, we may change
  143. // this to 3.
  144. //
  145. BinlMinDelayResponseForNewClients = (DWORD) ReadDWord( KeyHandle,
  146. BINL_MIN_RESPONSE_TIME,
  147. 0 );
  148. BinlPrint((DEBUG_OPTIONS, "New Client Timeout Minimum = %u seconds\n", BinlMinDelayResponseForNewClients ));
  149. //
  150. // Get the max time we'll wait for an ldap request
  151. //
  152. BinlLdapSearchTimeout.tv_usec = 0;
  153. BinlLdapSearchTimeout.tv_sec = (DWORD) ReadDWord( KeyHandle,
  154. BINL_LDAP_SEARCH_TIMEOUT,
  155. BINL_LDAP_SEARCH_TIMEOUT_SECONDS );
  156. BinlPrint((DEBUG_OPTIONS, "LDAP Search Timeout = %u seconds\n", BinlLdapSearchTimeout.tv_sec ));
  157. //
  158. // We need to give the DS some time to find the entries. If the user
  159. // specified 0 timeout, default to some decent minimum.
  160. //
  161. if (BinlLdapSearchTimeout.tv_sec == 0) {
  162. BinlLdapSearchTimeout.tv_usec = BINL_LDAP_SEARCH_MIN_TIMEOUT_MSECS;
  163. }
  164. BinlCacheExpireMilliseconds = (ULONG) ReadDWord( KeyHandle, BINL_CACHE_EXPIRE, BINL_CACHE_EXPIRE_DEFAULT);
  165. BinlPrint(( DEBUG_OPTIONS, "Cache Entry Expire Time = %u milliseconds\n", BinlCacheExpireMilliseconds ));
  166. BinlGlobalCacheCountLimit = (ULONG) ReadDWord( KeyHandle, BINL_CACHE_MAX_COUNT, BINL_CACHE_COUNT_LIMIT_DEFAULT);
  167. BinlPrint(( DEBUG_OPTIONS, "Maximum Cache Count = %u entries\n", BinlGlobalCacheCountLimit ));
  168. #if DBG
  169. //
  170. // Test for repeat ACKs - 0 = disabled
  171. //
  172. BinlRepeatSleep = (DWORD) ReadDWord( KeyHandle, BINL_REPEAT_RESPONSE, 0 );
  173. #endif
  174. //
  175. // Turn on/off LDAP_OPT_REFERRALS
  176. //
  177. BinlLdapOptReferrals = (DWORD) ReadDWord( KeyHandle, BINL_LDAP_OPT_REFERRALS, (ULONG) ((ULONG_PTR)LDAP_OPT_OFF) );
  178. //
  179. // Determine whether to assign new client accounts to the creating server.
  180. //
  181. AssignNewClientsToServer = (DWORD) ReadDWord( KeyHandle, BINL_ASSIGN_NEW_CLIENTS_TO_SERVER, AssignNewClientsToServer );
  182. BinlPrint(( DEBUG_OPTIONS, "Assign new clients to this server = %u\n", AssignNewClientsToServer ));
  183. if (KeyHandle) {
  184. RegCloseKey(KeyHandle);
  185. }
  186. //
  187. // Determine the default language.
  188. //
  189. LanguageString = NULL;
  190. uResult = GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, NULL, 0);
  191. if (uResult != 0) {
  192. LanguageString = BinlAllocateMemory(uResult * sizeof(WCHAR) );
  193. if (LanguageString != NULL) {
  194. uResult = GetLocaleInfo(
  195. LOCALE_SYSTEM_DEFAULT,
  196. LOCALE_SENGLANGUAGE,
  197. LanguageString,
  198. uResult );
  199. if (uResult == 0) {
  200. BinlFreeMemory( LanguageString );
  201. LanguageString = NULL;
  202. }
  203. }
  204. }
  205. //
  206. // Determine the default organization to put in .sif files.
  207. //
  208. OrgnameString = NULL;
  209. dwErr = RegOpenKeyEx(
  210. HKEY_LOCAL_MACHINE,
  211. L"Software\\Microsoft\\Windows NT\\CurrentVersion",
  212. 0,
  213. KEY_QUERY_VALUE,
  214. &KeyHandle );
  215. if ( dwErr == ERROR_SUCCESS ) {
  216. dwErr = BinlRegGetValue(
  217. KeyHandle,
  218. L"RegisteredOrganization",
  219. REG_SZ,
  220. (LPBYTE *)&OrgnameString );
  221. if ( dwErr != ERROR_SUCCESS ) {
  222. ASSERT( OrgnameString == NULL );
  223. }
  224. RegCloseKey(KeyHandle);
  225. }
  226. //
  227. // Determine the default timezone to put in .sif files.
  228. //
  229. TimezoneString = NULL;
  230. if (GetTimeZoneInformation(&TimeZoneInformation) != TIME_ZONE_ID_INVALID) {
  231. //
  232. // We need to find the value of
  233. // "Software\\Microsoft\\Windows NT\\CurrentVersion\Time Zones\
  234. // {TimeZoneInformation.StandardName}\Index.
  235. //
  236. dwErr = RegOpenKeyEx(
  237. HKEY_LOCAL_MACHINE,
  238. L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
  239. 0,
  240. KEY_READ,
  241. &KeyHandle );
  242. if (dwErr == ERROR_SUCCESS) {
  243. dwErr = RegOpenKeyEx(
  244. KeyHandle,
  245. TimeZoneInformation.StandardName,
  246. 0,
  247. KEY_QUERY_VALUE,
  248. &KeyHandle2);
  249. //
  250. // In Far East NT, the TimeZoneInformation.StandardName gets a
  251. // localized string of the English time zone name, but the subkey
  252. // name remains in English. For example, if the time zone is
  253. // "Pacific Standard Time", TimeZoneInformation.StandardName will
  254. // be the localized string for this English string, but the subkey
  255. // name will still be "Pacific Standard Time".
  256. //
  257. // So if we pass this Localized string to RegOpenKeyEx(), we may
  258. // get error value (0x00000002).
  259. //
  260. // The above code works fine in US Build, but for FE build, we
  261. // have to add a code block to get the correct Key.
  262. //
  263. if ( dwErr != ERROR_SUCCESS ) {
  264. //
  265. // This is for FE builds. Normally, in US Build, code will
  266. // not go to here.
  267. //
  268. WCHAR pszSubKeyName[MAX_PATH];
  269. WCHAR pszAlternateName[MAX_PATH];
  270. DWORD cbName;
  271. LONG lRetValue;
  272. DWORD dwIndex;
  273. dwIndex = 0;
  274. //
  275. // The alternate name is the name returned by
  276. // GetTimeZoneInformation with "Standard Time"
  277. // added at the end -- NT4 upgraded machines
  278. // may return the old names.
  279. //
  280. wcscpy(pszAlternateName, TimeZoneInformation.StandardName);
  281. wcscat(pszAlternateName, L" Standard Time");
  282. cbName = MAX_PATH;
  283. lRetValue = RegEnumKeyEx(
  284. KeyHandle,
  285. dwIndex,
  286. pszSubKeyName,
  287. &cbName,
  288. NULL,
  289. NULL,
  290. NULL,
  291. NULL );
  292. KeyHandle2 = NULL;
  293. while ( lRetValue != ERROR_NO_MORE_ITEMS ) {
  294. if ( KeyHandle2 != NULL ) {
  295. RegCloseKey( KeyHandle2 );
  296. KeyHandle2 = NULL;
  297. }
  298. dwErr = RegOpenKeyEx(
  299. KeyHandle,
  300. pszSubKeyName,
  301. 0,
  302. KEY_QUERY_VALUE,
  303. &KeyHandle2);
  304. if ( dwErr == ERROR_SUCCESS ) {
  305. WCHAR StdName[MAX_PATH];
  306. DWORD cb;
  307. cb = MAX_PATH;
  308. dwErr = RegQueryValueEx(KeyHandle2,
  309. TEXT("Std"),
  310. NULL,
  311. NULL,
  312. (PBYTE)StdName,
  313. &cb);
  314. if (!lstrcmp(StdName,TimeZoneInformation.StandardName) ||
  315. !lstrcmp(StdName,pszAlternateName) ){
  316. // get 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. BinlReadParameters( );
  981. break;
  982. case BINL_SERVICE_REREAD_SETTINGS: // custom message
  983. BinlPrint(( DEBUG_MISC, "Service received paramchange message.\n"));
  984. Error = BinlReadParameters( );
  985. //
  986. // Cause the service to poll frequently for a while and then return to
  987. // normal polling. If we managed to read the DS above, then we don't
  988. // need to succeed again, but if we failed above, then we want to keep
  989. // trying until we succeed at least once.
  990. //
  991. BinlHyperUpdateCount = BINL_HYPERMODE_RETRY_COUNT;
  992. BinlHyperUpdateSatisfied = (BOOL)(Error == ERROR_SUCCESS);
  993. break;
  994. default:
  995. BinlPrintDbg(( DEBUG_MISC, "Service received unknown control.\n"));
  996. break;
  997. }
  998. //
  999. // Send the status response.
  1000. //
  1001. UpdateStatus();
  1002. LeaveCriticalSection(&gcsDHCPBINL);
  1003. }
  1004. DWORD
  1005. BinlInitializeEndpoint(
  1006. PENDPOINT pEndpoint,
  1007. PDHCP_IP_ADDRESS pIpAddress,
  1008. DWORD Port
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This function initializes an endpoint by creating and binding a
  1013. socket to the local address.
  1014. Arguments:
  1015. pEndpoint - Receives a pointer to the newly created socket
  1016. pIpAddress - The IP address to initialize to INADDR_ANY if NULL.
  1017. Port - The port to bind to.
  1018. Return Value:
  1019. The status of the operation.
  1020. --*/
  1021. {
  1022. DWORD Error;
  1023. SOCKET Sock;
  1024. DWORD OptValue;
  1025. #define SOCKET_RECEIVE_BUFFER_SIZE 1024 * 64 // 64K max.
  1026. struct sockaddr_in SocketName;
  1027. pEndpoint->Port = Port;
  1028. //
  1029. // Create a socket
  1030. //
  1031. Sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
  1032. if ( Sock == INVALID_SOCKET ) {
  1033. Error = WSAGetLastError();
  1034. goto Cleanup;
  1035. }
  1036. //
  1037. // Make the socket share-able
  1038. //
  1039. OptValue = TRUE;
  1040. Error = setsockopt(
  1041. Sock,
  1042. SOL_SOCKET,
  1043. SO_REUSEADDR,
  1044. (LPBYTE)&OptValue,
  1045. sizeof(OptValue) );
  1046. if ( Error != ERROR_SUCCESS ) {
  1047. Error = WSAGetLastError();
  1048. goto Cleanup;
  1049. }
  1050. OptValue = TRUE;
  1051. Error = setsockopt(
  1052. Sock,
  1053. SOL_SOCKET,
  1054. SO_BROADCAST,
  1055. (LPBYTE)&OptValue,
  1056. sizeof(OptValue) );
  1057. if ( Error != ERROR_SUCCESS ) {
  1058. Error = WSAGetLastError();
  1059. goto Cleanup;
  1060. }
  1061. OptValue = SOCKET_RECEIVE_BUFFER_SIZE;
  1062. Error = setsockopt(
  1063. Sock,
  1064. SOL_SOCKET,
  1065. SO_RCVBUF,
  1066. (LPBYTE)&OptValue,
  1067. sizeof(OptValue) );
  1068. if ( Error != ERROR_SUCCESS ) {
  1069. Error = WSAGetLastError();
  1070. goto Cleanup;
  1071. }
  1072. SocketName.sin_family = PF_INET;
  1073. SocketName.sin_port = htons( (unsigned short)Port );
  1074. if (pIpAddress) {
  1075. SocketName.sin_addr.s_addr = *pIpAddress;
  1076. } else {
  1077. SocketName.sin_addr.s_addr = INADDR_ANY;
  1078. }
  1079. RtlZeroMemory( SocketName.sin_zero, 8);
  1080. //
  1081. // Bind this socket to the server port
  1082. //
  1083. Error = bind(
  1084. Sock,
  1085. (struct sockaddr FAR *)&SocketName,
  1086. sizeof( SocketName )
  1087. );
  1088. if ( Error != ERROR_SUCCESS ) {
  1089. Error = WSAGetLastError();
  1090. goto Cleanup;
  1091. }
  1092. pEndpoint->Socket = Sock;
  1093. //
  1094. // if this is 4011, then we setup for the pnp notification.
  1095. //
  1096. if ((Port == g_Port) &&
  1097. (BinlGlobalPnpEvent != NULL) &&
  1098. (BinlPnpSocket == INVALID_SOCKET)) {
  1099. BinlPnpSocket = Sock;
  1100. Error = BinlSetupPnpWait( );
  1101. if (Error != 0) {
  1102. BinlPrintDbg(( DEBUG_ERRORS, "BinlInitializeEndpoint could not set pnp event, %ld.\n", Error ));
  1103. }
  1104. }
  1105. if (!pIpAddress) {
  1106. PHOSTENT Host = gethostbyname(NULL); // winsock2 allows us to do this.
  1107. if (Host) {
  1108. pEndpoint->IpAddress = *(PDHCP_IP_ADDRESS)Host->h_addr;
  1109. } else {
  1110. Error = WSAGetLastError();
  1111. BinlPrintDbg(( DEBUG_ERRORS, "BinlInitializeEndpoint could not get ip addr, %ld.\n", Error ));
  1112. pEndpoint->IpAddress = 0;
  1113. }
  1114. } else {
  1115. pEndpoint->IpAddress = *pIpAddress;
  1116. }
  1117. Error = ERROR_SUCCESS;
  1118. Cleanup:
  1119. if( Error != ERROR_SUCCESS ) {
  1120. //
  1121. // if we aren't successful, close the socket if it is opened.
  1122. //
  1123. if( Sock != INVALID_SOCKET ) {
  1124. closesocket( Sock );
  1125. }
  1126. BinlPrintDbg(( DEBUG_ERRORS,
  1127. "BinlInitializeEndpoint failed, %ld.\n", Error ));
  1128. }
  1129. return( Error );
  1130. }
  1131. DWORD
  1132. WaitForDsStartup(
  1133. VOID
  1134. )
  1135. {
  1136. const DWORD dwMaxWaitForDS = 5*60*1000;
  1137. HANDLE hDsStartupCompletedEvent = NULL;
  1138. DWORD i;
  1139. DWORD err = ERROR_DS_UNAVAILABLE;
  1140. DWORD waitStatus;
  1141. DWORD waitTime = BinlGlobalServiceStatus.dwWaitHint;
  1142. NT_PRODUCT_TYPE productType;
  1143. //
  1144. // Find out if we're on a DC. If we're not, there's no need to wait for
  1145. // the DS.
  1146. //
  1147. // RtlGetNtProductType shouldn't fail. If it does, just assume we're
  1148. // not on a DC.
  1149. //
  1150. if (!RtlGetNtProductType(&productType) || (productType != NtProductLanManNt)) {
  1151. return NO_ERROR;
  1152. }
  1153. //
  1154. // Wait up to five minutes for DS to finish startup, if it hasn't done so
  1155. // already.
  1156. //
  1157. for (i = 0; i < dwMaxWaitForDS; i += waitTime) {
  1158. if (hDsStartupCompletedEvent == NULL) {
  1159. hDsStartupCompletedEvent = OpenEvent(SYNCHRONIZE,
  1160. FALSE,
  1161. NTDS_DELAYED_STARTUP_COMPLETED_EVENT);
  1162. }
  1163. if (hDsStartupCompletedEvent == NULL) {
  1164. //
  1165. // DS hasn't even gotten around to creating this event. This
  1166. // probably means the DS isn't *going* to be started, but let's
  1167. // not jump to conclusions.
  1168. //
  1169. BinlPrint((DEBUG_INIT, "DS startup has not begun; sleeping...\n"));
  1170. Sleep(waitTime);
  1171. } else {
  1172. //
  1173. // DS startup has begun.
  1174. //
  1175. waitStatus = WaitForSingleObject(hDsStartupCompletedEvent, waitTime);
  1176. if (waitStatus == WAIT_OBJECT_0) {
  1177. //
  1178. // DS startup completed (or failed).
  1179. //
  1180. BinlPrint((DEBUG_INIT, "DS startup completed.\n"));
  1181. err = NO_ERROR;
  1182. break;
  1183. } else if (WAIT_TIMEOUT == waitStatus) {
  1184. //
  1185. // DS startup still in progress.
  1186. //
  1187. BinlPrint((DEBUG_INIT, "DS is starting...\n"));
  1188. } else {
  1189. //
  1190. // Wait failure. Ignore the error.
  1191. //
  1192. BinlPrint((DEBUG_INIT, "Failed to wait on DS event handle;"
  1193. " waitStatus = %d, GLE = %d.\n", waitStatus, GetLastError()));
  1194. }
  1195. }
  1196. UpdateStatus();
  1197. }
  1198. if (hDsStartupCompletedEvent != NULL) {
  1199. CloseHandle(hDsStartupCompletedEvent);
  1200. }
  1201. return err;
  1202. }
  1203. DWORD
  1204. Initialize(
  1205. VOID
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This function initialize the binl service global data structures and
  1210. starts up the service.
  1211. Arguments:
  1212. None.
  1213. Return Value:
  1214. The initialization status.
  1215. 0 - Success.
  1216. Positive - A windows error occurred.
  1217. Negative - A service specific error occured.
  1218. --*/
  1219. {
  1220. DWORD threadId;
  1221. DWORD Error;
  1222. WSADATA wsaData;
  1223. //
  1224. // Initialize all the status fields so that subsequent calls to
  1225. // SetServiceStatus need to only update fields that changed.
  1226. //
  1227. BinlGlobalServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  1228. BinlGlobalServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  1229. BinlGlobalServiceStatus.dwControlsAccepted = 0;
  1230. BinlGlobalServiceStatus.dwCheckPoint = 1;
  1231. BinlGlobalServiceStatus.dwWaitHint = 60000; // 60 secs.
  1232. BinlGlobalServiceStatus.dwWin32ExitCode = ERROR_SUCCESS;
  1233. BinlGlobalServiceStatus.dwServiceSpecificExitCode = 0;
  1234. //
  1235. // Initialize binl to receive service requests by registering the
  1236. // control handler.
  1237. //
  1238. #if DBG
  1239. if (!BinlGlobalRunningAsProcess) {
  1240. #endif
  1241. BinlGlobalServiceStatusHandle = RegisterServiceCtrlHandler(
  1242. BINL_SERVER,
  1243. ServiceControlHandler );
  1244. if ( BinlGlobalServiceStatusHandle == 0 ) {
  1245. Error = GetLastError();
  1246. BinlPrintDbg((DEBUG_INIT, "RegisterServiceCtrlHandlerW failed, "
  1247. "%ld.\n", Error));
  1248. BinlServerEventLog(
  1249. EVENT_SERVER_FAILED_REGISTER_SC,
  1250. EVENTLOG_ERROR_TYPE,
  1251. Error );
  1252. return(Error);
  1253. }
  1254. #if DBG
  1255. } // if (!BinlGlobalRunningAsProcess)
  1256. #endif
  1257. //
  1258. // Tell Service Controller that we are start pending.
  1259. //
  1260. UpdateStatus();
  1261. //
  1262. // Create the process termination event.
  1263. //
  1264. BinlGlobalProcessTerminationEvent =
  1265. CreateEvent(
  1266. NULL, // no security descriptor
  1267. TRUE, // MANUAL reset
  1268. FALSE, // initial state: not signalled
  1269. NULL); // no name
  1270. if ( BinlGlobalProcessTerminationEvent == NULL ) {
  1271. Error = GetLastError();
  1272. BinlPrintDbg((DEBUG_INIT, "Can't create ProcessTerminationEvent, "
  1273. "%ld.\n", Error));
  1274. return(Error);
  1275. }
  1276. BinlGlobalPnpEvent =
  1277. CreateEvent(
  1278. NULL, // no security descriptor
  1279. FALSE, // auto reset
  1280. FALSE, // initial state: not signalled
  1281. NULL); // no name
  1282. if ( BinlGlobalPnpEvent == NULL ) {
  1283. Error = GetLastError();
  1284. BinlPrintDbg((DEBUG_INIT, "Can't create PNP event, "
  1285. "%ld.\n", Error));
  1286. return(Error);
  1287. }
  1288. //
  1289. // create the ProcessMessage termination event
  1290. //
  1291. g_hevtProcessMessageComplete = CreateEvent(
  1292. NULL,
  1293. FALSE,
  1294. FALSE,
  1295. NULL
  1296. );
  1297. if ( !g_hevtProcessMessageComplete )
  1298. {
  1299. Error = GetLastError();
  1300. BinlPrintDbg( (DEBUG_INIT,
  1301. "Initialize(...) CreateEvent returned error %x\n",
  1302. Error )
  1303. );
  1304. return Error;
  1305. }
  1306. BinlPrint(( DEBUG_INIT, "Initializing .. \n", 0 ));
  1307. //
  1308. // Wait for the DS to start up.
  1309. //
  1310. Error = WaitForDsStartup();
  1311. if ( Error != ERROR_SUCCESS ) {
  1312. BinlPrintDbg(( DEBUG_INIT, "Wait for DS failed, %ld.\n", Error ));
  1313. BinlServerEventLog(
  1314. EVENT_SERVER_DS_WAIT_FAILED,
  1315. EVENTLOG_ERROR_TYPE,
  1316. Error );
  1317. return(Error);
  1318. }
  1319. Error = WSAStartup( WS_VERSION_REQUIRED, &wsaData);
  1320. if ( Error != ERROR_SUCCESS ) {
  1321. BinlPrintDbg(( DEBUG_INIT, "WSAStartup failed, %ld.\n", Error ));
  1322. BinlServerEventLog(
  1323. EVENT_SERVER_INIT_WINSOCK_FAILED,
  1324. EVENTLOG_ERROR_TYPE,
  1325. Error );
  1326. return(Error);
  1327. }
  1328. Error = InitializeData();
  1329. if ( Error != ERROR_SUCCESS ) {
  1330. BinlPrintDbg(( DEBUG_INIT, "Data initialization failed, %ld.\n",
  1331. Error ));
  1332. BinlServerEventLog(
  1333. EVENT_SERVER_INIT_DATA_FAILED,
  1334. EVENTLOG_ERROR_TYPE,
  1335. Error );
  1336. return(Error);
  1337. }
  1338. //
  1339. // if the SCP hasn't been created yet, then try to create it now.
  1340. // We do this before trying the read the SCP from the DS
  1341. // -- failure to read the SCP will mean that BINL won't startup properly
  1342. //
  1343. Error = CreateSCPIfNeeded(&BinlParametersRead);
  1344. if (Error != ERROR_SUCCESS ) {
  1345. BinlPrintDbg(( DEBUG_INIT, "Create SCP failed, %ld.\n", Error ));
  1346. BinlServerEventLog(
  1347. ERROR_BINL_SCP_CREATION_FAILED,
  1348. EVENTLOG_ERROR_TYPE,
  1349. Error );
  1350. }
  1351. if (BinlParametersRead) {
  1352. //
  1353. // this means that we created the SCP. When we try to read the SCP
  1354. // from the DS, it will probably fail the first time.
  1355. //
  1356. BinlPrint(( DEBUG_INIT, "BINLSVC created the SCP.\n" ));
  1357. }
  1358. BinlParametersRead = FALSE;
  1359. Error = BinlReadParameters( );
  1360. if ( Error != ERROR_SUCCESS ) {
  1361. BinlPrintDbg(( DEBUG_INIT, "Read parameters failed, %ld.\n",
  1362. Error ));
  1363. //
  1364. // Tell the scavenger to be hyper about reading parameters. Also, log
  1365. // an event indicating that we're in hyper mode and not truly
  1366. // initialized yet.
  1367. //
  1368. // In spite of this failure, we DO NOT fail to initialize BINLSVC.
  1369. // We assume that we'll eventually be able to read our parameters.
  1370. //
  1371. BinlHyperUpdateCount = 1;
  1372. BinlHyperUpdateSatisfied = FALSE;
  1373. BinlServerEventLog(
  1374. EVENT_SERVER_INIT_PARAMETERS_FAILED,
  1375. EVENTLOG_WARNING_TYPE,
  1376. Error );
  1377. } else {
  1378. BinlParametersRead = TRUE;
  1379. }
  1380. BinlPrintDbg(( DEBUG_INIT, "Data initialization succeeded.\n", 0 ));
  1381. // Get the DHCP UDP socket
  1382. Error = MaybeInitializeEndpoint( &BinlGlobalEndpointList[0],
  1383. NULL,
  1384. DHCP_SERVR_PORT);
  1385. if ( Error != ERROR_SUCCESS ) {
  1386. return WSAGetLastError();
  1387. };
  1388. if (g_Port) {
  1389. // Get the BINL UDP socket
  1390. Error = BinlInitializeEndpoint( &BinlGlobalEndpointList[1],
  1391. NULL,
  1392. g_Port);
  1393. if ( Error != ERROR_SUCCESS ) {
  1394. return WSAGetLastError();
  1395. };
  1396. }
  1397. //
  1398. // Initialize the OSChooser server.
  1399. //
  1400. Error = OscInitialize();
  1401. if ( Error != ERROR_SUCCESS ) {
  1402. BinlPrint(( DEBUG_INIT, "OSChooser initialization failed, %ld.\n",
  1403. Error ));
  1404. return Error;
  1405. };
  1406. //
  1407. // send heart beat to the service controller.
  1408. //
  1409. //
  1410. BinlGlobalServiceStatus.dwCheckPoint++;
  1411. UpdateStatus();
  1412. //
  1413. // Start a thread to queue the incoming BINL messages
  1414. //
  1415. BinlGlobalMessageHandle = CreateThread(
  1416. NULL,
  1417. 0,
  1418. (LPTHREAD_START_ROUTINE)BinlMessageLoop,
  1419. NULL,
  1420. 0,
  1421. &threadId );
  1422. if ( BinlGlobalMessageHandle == NULL ) {
  1423. Error = GetLastError();
  1424. BinlPrint((DEBUG_INIT, "Can't create Message Thread, %ld.\n", Error));
  1425. return(Error);
  1426. }
  1427. //
  1428. // Start a thread to process BINL messages
  1429. //
  1430. BinlGlobalProcessorHandle = CreateThread(
  1431. NULL,
  1432. 0,
  1433. (LPTHREAD_START_ROUTINE)BinlProcessingLoop,
  1434. NULL,
  1435. 0,
  1436. &threadId );
  1437. if ( BinlGlobalProcessorHandle == NULL ) {
  1438. Error = GetLastError();
  1439. BinlPrint((DEBUG_INIT, "Can't create ProcessThread, %ld.\n", Error));
  1440. return(Error);
  1441. }
  1442. Error = NetInfStartHandler();
  1443. if ( Error != ERROR_SUCCESS ) {
  1444. BinlPrint((DEBUG_INIT, "Can't start INF Handler thread, %ld.\n", Error));
  1445. return(Error);
  1446. }
  1447. BinlGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
  1448. BinlGlobalServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  1449. SERVICE_ACCEPT_SHUTDOWN |
  1450. SERVICE_ACCEPT_PAUSE_CONTINUE;
  1451. UpdateStatus();
  1452. BinlCurrentState = BINL_STARTED;
  1453. #if defined(REGISTRY_ROGUE)
  1454. //
  1455. // for now, temporarily set the rogue logic disabled. it can be
  1456. // enabled in the registry
  1457. //
  1458. if (RogueDetection) {
  1459. #endif
  1460. //
  1461. // initialize the rogue thread if DHCP server isn't running.
  1462. //
  1463. BinlRogueLoggedState = FALSE;
  1464. Error = MaybeStartRogueThread();
  1465. if ( Error != ERROR_SUCCESS ) {
  1466. BinlPrint((DEBUG_INIT, "Can't start rogue logic, %ld.\n", Error));
  1467. return(Error);
  1468. }
  1469. #if defined(REGISTRY_ROGUE)
  1470. } else {
  1471. // pull this out when we pull out the registry setting
  1472. BinlGlobalAuthorized = TRUE;
  1473. }
  1474. #endif
  1475. //
  1476. // finally set the server startup time.
  1477. //
  1478. //GetSystemTime(&BinlGlobalServerStartTime);
  1479. return ERROR_SUCCESS;
  1480. }
  1481. VOID
  1482. Shutdown(
  1483. IN DWORD ErrorCode
  1484. )
  1485. /*++
  1486. Routine Description:
  1487. This function shuts down the binl service.
  1488. Arguments:
  1489. ErrorCode - Supplies the error code of the failure
  1490. Return Value:
  1491. None.
  1492. --*/
  1493. {
  1494. DWORD Error;
  1495. BinlPrint((DEBUG_MISC, "Shutdown started ..\n" ));
  1496. //
  1497. // LOG an event if this is not a normal shutdown.
  1498. //
  1499. if( ErrorCode != ERROR_SUCCESS ) {
  1500. BinlServerEventLog(
  1501. EVENT_SERVER_SHUTDOWN,
  1502. EVENTLOG_ERROR_TYPE,
  1503. ErrorCode );
  1504. }
  1505. //
  1506. // Service is shuting down, may be due to some service problem or
  1507. // the administrator is stopping the service. Inform the service
  1508. // controller.
  1509. //
  1510. BinlGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  1511. BinlGlobalServiceStatus.dwCheckPoint = 1;
  1512. //
  1513. // Send the status response.
  1514. //
  1515. UpdateStatus();
  1516. if( BinlGlobalProcessTerminationEvent != NULL ) {
  1517. //
  1518. // set Termination Event so that other threads know about the
  1519. // shut down.
  1520. //
  1521. SetEvent( BinlGlobalProcessTerminationEvent );
  1522. //
  1523. // Close all sockets, so that the BinlProcessingLoop
  1524. // thread will come out of blocking Select() call.
  1525. //
  1526. // Close EndPoint sockets.
  1527. //
  1528. if( BinlGlobalEndpointList != NULL ) {
  1529. DWORD i;
  1530. for ( i = 0; i < BinlGlobalNumberOfNets ; i++ ) {
  1531. MaybeCloseEndpoint(&BinlGlobalEndpointList[i]);
  1532. }
  1533. BinlFreeMemory( BinlGlobalEndpointList );
  1534. }
  1535. BinlPnpSocket = INVALID_SOCKET;
  1536. //
  1537. // Wait for the threads to terminate, don't wait forever.
  1538. //
  1539. if( BinlGlobalProcessorHandle != NULL ) {
  1540. WaitForSingleObject(
  1541. BinlGlobalProcessorHandle,
  1542. THREAD_TERMINATION_TIMEOUT );
  1543. CloseHandle( BinlGlobalProcessorHandle );
  1544. BinlGlobalProcessorHandle = NULL;
  1545. }
  1546. //
  1547. // wait for the receive thread to complete.
  1548. //
  1549. if( BinlGlobalMessageHandle != NULL ) {
  1550. WaitForSingleObject(
  1551. BinlGlobalMessageHandle,
  1552. THREAD_TERMINATION_TIMEOUT );
  1553. CloseHandle( BinlGlobalMessageHandle );
  1554. BinlGlobalMessageHandle = NULL;
  1555. }
  1556. while ( !IsListEmpty( &BinlGlobalFreeRecvList ) )
  1557. {
  1558. BINL_REQUEST_CONTEXT *pRequestContext;
  1559. pRequestContext =
  1560. (BINL_REQUEST_CONTEXT *)
  1561. RemoveHeadList( &BinlGlobalFreeRecvList );
  1562. BinlFreeMemory( pRequestContext->ReceiveBuffer );
  1563. BinlFreeMemory( pRequestContext );
  1564. }
  1565. while ( !IsListEmpty( &BinlGlobalActiveRecvList ) )
  1566. {
  1567. BINL_REQUEST_CONTEXT *pRequestContext;
  1568. pRequestContext =
  1569. (BINL_REQUEST_CONTEXT *)
  1570. RemoveHeadList( &BinlGlobalActiveRecvList );
  1571. BinlFreeMemory( pRequestContext->ReceiveBuffer );
  1572. BinlFreeMemory( pRequestContext );
  1573. }
  1574. if ( BinlIsProcessMessageExecuting() )
  1575. {
  1576. //
  1577. // wait for the thread pool to shutdown
  1578. //
  1579. Error = WaitForSingleObject(
  1580. g_hevtProcessMessageComplete,
  1581. THREAD_TERMINATION_TIMEOUT
  1582. );
  1583. BinlAssert( WAIT_OBJECT_0 == Error );
  1584. }
  1585. //
  1586. // We free the ldap connections after all the threads are done because
  1587. // the connection BaseDN strings may be in use by the threads and
  1588. // we're about to free them in FreeConnections.
  1589. //
  1590. FreeConnections();
  1591. CloseHandle( g_hevtProcessMessageComplete );
  1592. g_hevtProcessMessageComplete = NULL;
  1593. }
  1594. BinlPrintDbg((DEBUG_MISC, "Client requests cleaned up.\n" ));
  1595. //
  1596. // send heart beat to the service controller.
  1597. //
  1598. //
  1599. BinlGlobalServiceStatus.dwCheckPoint++;
  1600. UpdateStatus();
  1601. //
  1602. // send heart beat to the service controller and
  1603. // reset wait time.
  1604. //
  1605. BinlGlobalServiceStatus.dwWaitHint = 60 * 1000; // 1 mins.
  1606. BinlGlobalServiceStatus.dwCheckPoint++;
  1607. UpdateStatus();
  1608. FreeIpAddressInfo();
  1609. //
  1610. // cleanup other data.
  1611. //
  1612. StopRogueThread( );
  1613. OscUninitialize();
  1614. WSACleanup();
  1615. DeleteCriticalSection( &BinlCacheListLock );
  1616. NetInfCloseHandler();
  1617. if ( BinlGlobalSCPPath ) {
  1618. BinlFreeMemory( BinlGlobalSCPPath );
  1619. BinlGlobalSCPPath = NULL;
  1620. }
  1621. if ( BinlGlobalServerDN ) {
  1622. BinlFreeMemory( BinlGlobalServerDN );
  1623. BinlGlobalServerDN = NULL;
  1624. }
  1625. if ( BinlGlobalGroupDN ) {
  1626. BinlFreeMemory( BinlGlobalGroupDN );
  1627. BinlGlobalGroupDN = NULL;
  1628. }
  1629. if ( BinlGlobalDefaultLanguage ) {
  1630. BinlFreeMemory( BinlGlobalDefaultLanguage );
  1631. BinlGlobalDefaultLanguage = NULL;
  1632. }
  1633. EnterCriticalSection( &gcsParameters );
  1634. if ( BinlGlobalDefaultContainer ) {
  1635. BinlFreeMemory( BinlGlobalDefaultContainer );
  1636. BinlGlobalDefaultContainer = NULL;
  1637. }
  1638. if ( NewMachineNamingPolicy != NULL ) {
  1639. BinlFreeMemory( NewMachineNamingPolicy );
  1640. NewMachineNamingPolicy = NULL;
  1641. }
  1642. if ( BinlGlobalOurDnsName ) {
  1643. BinlFreeMemory( BinlGlobalOurDnsName );
  1644. BinlGlobalOurDnsName = NULL;
  1645. }
  1646. if ( BinlGlobalOurDomainName ) {
  1647. BinlFreeMemory( BinlGlobalOurDomainName );
  1648. BinlGlobalOurDomainName = NULL;
  1649. }
  1650. if ( BinlGlobalOurServerName ) {
  1651. BinlFreeMemory( BinlGlobalOurServerName );
  1652. BinlGlobalOurServerName = NULL;
  1653. }
  1654. if ( BinlGlobalOurFQDNName ) {
  1655. BinlFreeMemory( BinlGlobalOurFQDNName );
  1656. BinlGlobalOurFQDNName = NULL;
  1657. }
  1658. LeaveCriticalSection( &gcsParameters );
  1659. if (BinlGlobalHaveOutstandingLsaNotify) {
  1660. Error = LsaUnregisterPolicyChangeNotification(
  1661. BINL_LSA_SERVER_NAME_POLICY,
  1662. BinlGlobalLsaDnsNameNotifyEvent
  1663. );
  1664. if (Error != ERROR_SUCCESS) {
  1665. BinlPrintDbg((DEBUG_INIT, "Can't close LSA notify, 0x%08x.\n", Error));
  1666. }
  1667. BinlGlobalHaveOutstandingLsaNotify = FALSE;
  1668. }
  1669. if (BinlGlobalLsaDnsNameNotifyEvent != NULL) {
  1670. CloseHandle( BinlGlobalLsaDnsNameNotifyEvent );
  1671. BinlGlobalLsaDnsNameNotifyEvent = NULL;
  1672. }
  1673. if ( BinlGlobalDefaultOrgname ) {
  1674. BinlFreeMemory( BinlGlobalDefaultOrgname );
  1675. BinlGlobalDefaultOrgname = NULL;
  1676. }
  1677. if ( BinlGlobalDefaultTimezone ) {
  1678. BinlFreeMemory( BinlGlobalDefaultTimezone );
  1679. BinlGlobalDefaultTimezone = NULL;
  1680. }
  1681. if ( BinlGlobalDefaultDS ) {
  1682. BinlFreeMemory( BinlGlobalDefaultDS );
  1683. BinlGlobalDefaultDS = NULL;
  1684. }
  1685. if ( BinlGlobalDefaultGC ) {
  1686. BinlFreeMemory( BinlGlobalDefaultGC );
  1687. BinlGlobalDefaultGC = NULL;
  1688. }
  1689. BinlPrint((DEBUG_MISC, "Shutdown Completed.\n" ));
  1690. DebugUninitialize( );
  1691. //
  1692. // don't use BinlPrint past this point
  1693. //
  1694. BinlGlobalServiceStatus.dwCurrentState = SERVICE_STOPPED;
  1695. BinlGlobalServiceStatus.dwControlsAccepted = 0;
  1696. if ( ErrorCode >= 20000 && ErrorCode <= 20099 ) {
  1697. // Indicate that it is a BINL specific error code
  1698. BinlGlobalServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  1699. BinlGlobalServiceStatus.dwServiceSpecificExitCode = ErrorCode;
  1700. } else {
  1701. BinlGlobalServiceStatus.dwWin32ExitCode = ErrorCode;
  1702. BinlGlobalServiceStatus.dwServiceSpecificExitCode = 0;
  1703. }
  1704. BinlGlobalServiceStatus.dwCheckPoint = 0;
  1705. BinlGlobalServiceStatus.dwWaitHint = 0;
  1706. UpdateStatus();
  1707. }
  1708. VOID
  1709. ServiceEntry(
  1710. DWORD NumArgs,
  1711. LPWSTR *ArgsArray,
  1712. IN PTCPSVCS_GLOBAL_DATA pGlobalData
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. This is the main routine of the BINL server service. After
  1717. the service has been initialized, this thread will wait on
  1718. BinlGlobalProcessTerminationEvent for a signal to terminate the service.
  1719. Arguments:
  1720. NumArgs - Supplies the number of strings specified in ArgsArray.
  1721. ArgsArray - Supplies string arguments that are specified in the
  1722. StartService API call. This parameter is ignored.
  1723. Return Value:
  1724. None.
  1725. --*/
  1726. {
  1727. DWORD Error;
  1728. UNREFERENCED_PARAMETER(NumArgs);
  1729. UNREFERENCED_PARAMETER(ArgsArray);
  1730. DebugInitialize( );
  1731. #if DBG
  1732. //
  1733. // If we are running as a test process instead of as a service then
  1734. // recored it now so that we avoid calling into the service controller
  1735. // and failing.
  1736. //
  1737. if ((NumArgs == 2) &&
  1738. (ArgsArray == NULL)) {
  1739. BinlGlobalRunningAsProcess = TRUE;
  1740. } else {
  1741. BinlGlobalRunningAsProcess = FALSE;
  1742. }
  1743. #endif
  1744. //
  1745. // copy the process global data pointer to service global variable.
  1746. //
  1747. TcpsvcsGlobalData = pGlobalData;
  1748. Error = Initialize();
  1749. if ( Error == ERROR_SUCCESS) {
  1750. //
  1751. // If we were able to read our parameters from the DS, log an event
  1752. // indicating that we're ready to roll. If not, hold off on logging the
  1753. // event -- the scavenger will do it when it manages to get to the DS.
  1754. //
  1755. if ( BinlParametersRead ) {
  1756. BinlServerEventLog(
  1757. EVENT_SERVER_INIT_AND_READY,
  1758. EVENTLOG_INFORMATION_TYPE,
  1759. Error );
  1760. }
  1761. //
  1762. // perform Scavenge task until we are told to stop.
  1763. //
  1764. Error = Scavenger();
  1765. }
  1766. Shutdown( Error );
  1767. return;
  1768. }
  1769. VOID
  1770. BinlMessageLoop(
  1771. LPVOID Parameter
  1772. )
  1773. /*++
  1774. Routine Description:
  1775. This function is the message queuing thread. It loops
  1776. to receive messages that are arriving to all opened sockets and
  1777. queue them in the message queue. The queue length is fixed, so if the
  1778. queue becomes full, it deletes the oldest message from the queue to
  1779. add the new one.
  1780. The message processing thread pops out messages (last one first) and
  1781. process them. New messages are processed first because the
  1782. corresponding clients will least likely time-out, and hence the
  1783. throughput will be better. Also the processing thread throws
  1784. messages that are already timed out, this will stop server starving
  1785. problem.
  1786. Arguments:
  1787. Parameter - pointer to the parameter passed.
  1788. Return Value:
  1789. None.
  1790. --*/
  1791. {
  1792. DWORD Error,
  1793. SendResponse,
  1794. Signal;
  1795. BINL_REQUEST_CONTEXT *pRequestContext;
  1796. while ( 1 ) {
  1797. //
  1798. // dequeue an entry from the free list.
  1799. //
  1800. LOCK_RECV_LIST();
  1801. if( !IsListEmpty( &BinlGlobalFreeRecvList ) ) {
  1802. pRequestContext =
  1803. (BINL_REQUEST_CONTEXT *)
  1804. RemoveHeadList( &BinlGlobalFreeRecvList );
  1805. }
  1806. else {
  1807. //
  1808. // active message queue should be non-empty.
  1809. //
  1810. BinlAssert( IsListEmpty( &BinlGlobalActiveRecvList ) == FALSE );
  1811. BinlPrintDbg(( DEBUG_MISC, "A Message has been overwritten.\n"));
  1812. //
  1813. // dequeue an old entry from the queue.
  1814. //
  1815. pRequestContext =
  1816. (BINL_REQUEST_CONTEXT *)
  1817. RemoveHeadList( &BinlGlobalActiveRecvList );
  1818. }
  1819. UNLOCK_RECV_LIST();
  1820. //
  1821. // wait for message to arrive from of the open socket port.
  1822. //
  1823. MessageWait:
  1824. Error = BinlWaitForMessage( pRequestContext );
  1825. if( Error != ERROR_SUCCESS ) {
  1826. if( Error == ERROR_SEM_TIMEOUT ) {
  1827. //
  1828. // if we are asked to exit, do so.
  1829. //
  1830. Error = WaitForSingleObject( BinlGlobalProcessTerminationEvent, 0 );
  1831. if ( Error == ERROR_SUCCESS ) {
  1832. //
  1833. // The termination event has been signalled
  1834. //
  1835. //
  1836. // delete pRequestContext before exiting
  1837. //
  1838. #if 0
  1839. BinlFreeMemory( pRequestContext->ReceiveBuffer );
  1840. BinlFreeMemory( pRequestContext );
  1841. #endif
  1842. ExitThread( 0 );
  1843. }
  1844. BinlAssert( Error == WAIT_TIMEOUT );
  1845. goto MessageWait;
  1846. }
  1847. else {
  1848. BinlPrintDbg(( DEBUG_ERRORS,
  1849. "BinlWaitForMessage failed, error = %ld\n", Error ));
  1850. goto MessageWait;
  1851. }
  1852. }
  1853. //
  1854. // time stamp the received message.
  1855. //
  1856. pRequestContext->TimeArrived = GetTickCount();
  1857. //
  1858. // queue the message in active queue.
  1859. //
  1860. LOCK_RECV_LIST();
  1861. //
  1862. // before adding this message, check the active list is empty, if
  1863. // so, signal the processing thread after adding this new message.
  1864. //
  1865. Signal = IsListEmpty( &BinlGlobalActiveRecvList );
  1866. InsertTailList( &BinlGlobalActiveRecvList, &pRequestContext->ListEntry );
  1867. if( Signal == TRUE ) {
  1868. if( !SetEvent( BinlGlobalRecvEvent) ) {
  1869. //
  1870. // Problem with setting the event to indicate the message
  1871. // processing queue the arrival of a new message.
  1872. //
  1873. BinlPrintDbg(( DEBUG_ERRORS,
  1874. "Error setting BinlGlobalRecvEvent %ld\n",
  1875. GetLastError()));
  1876. BinlAssert(FALSE);
  1877. }
  1878. }
  1879. UNLOCK_RECV_LIST();
  1880. }
  1881. //
  1882. // Abnormal thread termination.
  1883. //
  1884. ExitThread( 1 );
  1885. }
  1886. DWORD
  1887. BinlStartWorkerThread(
  1888. BINL_REQUEST_CONTEXT **ppContext
  1889. )
  1890. {
  1891. BYTE *pbSendBuffer = NULL,
  1892. *pbReceiveBuffer = NULL;
  1893. DWORD dwResult;
  1894. BINL_REQUEST_CONTEXT *pNewContext,
  1895. *pTempContext;
  1896. DWORD dwID;
  1897. HANDLE hThread;
  1898. pNewContext = BinlAllocateMemory( sizeof( *pNewContext ) );
  1899. if ( !pNewContext )
  1900. {
  1901. goto t_cleanup;
  1902. }
  1903. pbSendBuffer = BinlAllocateMemory( DHCP_SEND_MESSAGE_SIZE );
  1904. if ( !pbSendBuffer )
  1905. {
  1906. goto t_cleanup;
  1907. }
  1908. pbReceiveBuffer = BinlAllocateMemory( DHCP_RECV_MESSAGE_SIZE + 1 );
  1909. if ( !pbReceiveBuffer )
  1910. {
  1911. goto t_cleanup;
  1912. }
  1913. //
  1914. // Pass the input context to the worker thread and return the new
  1915. // context to the caller. This saves a memory copy.
  1916. //
  1917. SWAP( *ppContext, pNewContext );
  1918. (*ppContext)->ReceiveBuffer = pbReceiveBuffer;
  1919. pNewContext->SendBuffer = pbSendBuffer;
  1920. EnterCriticalSection( &g_ProcessMessageCritSect );
  1921. ++g_cProcessMessageThreads;
  1922. BinlAssert( g_cProcessMessageThreads <= g_cMaxProcessingThreads );
  1923. hThread = CreateThread(
  1924. NULL,
  1925. 0,
  1926. (LPTHREAD_START_ROUTINE) ProcessMessage,
  1927. pNewContext,
  1928. 0,
  1929. &dwID
  1930. );
  1931. if ( hThread )
  1932. {
  1933. //
  1934. // success
  1935. //
  1936. CloseHandle( hThread );
  1937. LeaveCriticalSection( &g_ProcessMessageCritSect );
  1938. return ERROR_SUCCESS;
  1939. }
  1940. --g_cProcessMessageThreads;
  1941. LeaveCriticalSection( &g_ProcessMessageCritSect );
  1942. //
  1943. // CreateThread failed. Swap restores the context pointers.
  1944. //
  1945. SWAP( *ppContext, pNewContext );
  1946. BinlPrintDbg( (DEBUG_ERRORS,
  1947. "BinlStartWorkerThread: CreateThread failed: %d\n" )
  1948. );
  1949. t_cleanup:
  1950. if ( pbReceiveBuffer )
  1951. {
  1952. BinlFreeMemory( pbReceiveBuffer );
  1953. }
  1954. if ( pbSendBuffer )
  1955. {
  1956. BinlFreeMemory( pbSendBuffer );
  1957. }
  1958. if ( pNewContext )
  1959. {
  1960. BinlFreeMemory( pNewContext );
  1961. }
  1962. BinlPrintDbg( ( DEBUG_ERRORS,
  1963. "BinlStartWorkerThread failed.\n"
  1964. ) );
  1965. return ERROR_NOT_ENOUGH_MEMORY;
  1966. }
  1967. #define PROCESS_TERMINATE_EVENT 0
  1968. #define PROCESS_MESSAGE_RECVD 1
  1969. #define PROCESS_EVENT_COUNT 2
  1970. VOID
  1971. BinlProcessingLoop(
  1972. VOID
  1973. )
  1974. /*++
  1975. Routine Description:
  1976. This function is the starting point for the main processing thread.
  1977. It loops to process queued messages, and sends replies.
  1978. Arguments:
  1979. RequestContext - A pointer to the request context block for
  1980. for this thread to use.
  1981. Return Value:
  1982. None.
  1983. --*/
  1984. {
  1985. DWORD Error,
  1986. Result;
  1987. HANDLE WaitHandle[PROCESS_EVENT_COUNT];
  1988. BINL_REQUEST_CONTEXT *pRequestContext;
  1989. WaitHandle[PROCESS_MESSAGE_RECVD] = BinlGlobalRecvEvent;
  1990. WaitHandle[PROCESS_TERMINATE_EVENT] = BinlGlobalProcessTerminationEvent;
  1991. while ( 1 ) {
  1992. //
  1993. // wait for one of the following event to occur :
  1994. // 1. if we are notified about the incoming message.
  1995. // 2. if we are asked to terminate
  1996. //
  1997. Result = WaitForMultipleObjects(
  1998. PROCESS_EVENT_COUNT, // num. of handles.
  1999. WaitHandle, // handle array.
  2000. FALSE, // wait for any.
  2001. INFINITE ); // timeout in msecs.
  2002. if (Result == PROCESS_TERMINATE_EVENT) {
  2003. //
  2004. // The termination event has been signalled
  2005. //
  2006. break;
  2007. }
  2008. if ( Result != PROCESS_MESSAGE_RECVD) {
  2009. BinlPrintDbg(( DEBUG_ERRORS,
  2010. "WaitForMultipleObjects returned invalid result, %ld.\n",
  2011. Result ));
  2012. //
  2013. // go back to wait.
  2014. //
  2015. continue;
  2016. }
  2017. //
  2018. // process all queued messages.
  2019. //
  2020. while( TRUE )
  2021. {
  2022. if ( BinlIsProcessMessageBusy() )
  2023. {
  2024. //
  2025. // All worker threads are active, so break to the outer loop.
  2026. // When a worker thread is finished it will set the
  2027. // PROCESS_MESSAGE_RECVD event.
  2028. BinlPrintDbg( (DEBUG_STOC,
  2029. "BinlProcessingLoop: All worker threads busy.\n" )
  2030. );
  2031. break;
  2032. }
  2033. LOCK_RECV_LIST();
  2034. if( IsListEmpty( &BinlGlobalActiveRecvList ) ) {
  2035. //
  2036. // no more message.
  2037. //
  2038. UNLOCK_RECV_LIST();
  2039. break;
  2040. }
  2041. //
  2042. // pop out a message from the active list ( *last one first* ).
  2043. //
  2044. pRequestContext =
  2045. (BINL_REQUEST_CONTEXT *) RemoveHeadList(&BinlGlobalActiveRecvList );
  2046. UNLOCK_RECV_LIST();
  2047. //
  2048. // if the message is too old, or if the maximum number of worker threads
  2049. // are running, discard the message.
  2050. //
  2051. if( GetTickCount() - pRequestContext->TimeArrived <
  2052. WAIT_FOR_RESPONSE_TIME * 1000 )
  2053. {
  2054. Error = BinlStartWorkerThread( &pRequestContext );
  2055. if ( ERROR_SUCCESS != Error )
  2056. {
  2057. BinlPrintDbg( (DEBUG_ERRORS,
  2058. "BinlProcessingLoop: BinlStartWorkerThread failed: %d\n",
  2059. Error )
  2060. );
  2061. }
  2062. } // if ( ( GetTickCount() < pRequestContext->TimeArrived...
  2063. else
  2064. {
  2065. BinlPrintDbg(( DEBUG_ERRORS, "A message has been timed out.\n" ));
  2066. }
  2067. //
  2068. // return this context to the free list
  2069. //
  2070. LOCK_RECV_LIST();
  2071. InsertTailList(
  2072. &BinlGlobalFreeRecvList,
  2073. &pRequestContext->ListEntry );
  2074. UNLOCK_RECV_LIST();
  2075. } // while (TRUE)
  2076. } // while( 1 )
  2077. //
  2078. // Abnormal thread termination.
  2079. //
  2080. ExitThread( 1 );
  2081. }
  2082. BOOL
  2083. BinlIsProcessMessageExecuting(
  2084. VOID
  2085. )
  2086. {
  2087. BOOL f;
  2088. EnterCriticalSection( &g_ProcessMessageCritSect );
  2089. f = g_cProcessMessageThreads;
  2090. LeaveCriticalSection( &g_ProcessMessageCritSect );
  2091. return f;
  2092. }
  2093. BOOL
  2094. BinlIsProcessMessageBusy(
  2095. VOID
  2096. )
  2097. {
  2098. BOOL f;
  2099. EnterCriticalSection( &g_ProcessMessageCritSect );
  2100. f = ( g_cProcessMessageThreads == g_cMaxProcessingThreads );
  2101. LeaveCriticalSection( &g_ProcessMessageCritSect );
  2102. return f;
  2103. }
  2104. #undef PROCESS_TERMINATE_EVENT
  2105. #undef PROCESS_EVENT_COUNT
  2106. #define PROCESS_TERMINATE_EVENT 0
  2107. #define PROCESS_PNP_EVENT 1
  2108. #define PROCESS_LSA_EVENT 2
  2109. #define PROCESS_EVENT_COUNT 3
  2110. DWORD
  2111. Scavenger(
  2112. VOID
  2113. )
  2114. /*++
  2115. Routine Description:
  2116. This function runs as an independant thread. It periodically wakes
  2117. up. Currently we have no work for it to do but I'm sure we will in the future.
  2118. Arguments:
  2119. None.
  2120. Return Value:
  2121. None.
  2122. --*/
  2123. {
  2124. BOOL fLeftCriticalSection = FALSE;
  2125. DWORD TimeOfLastScavenge = GetTickCount();
  2126. DWORD TimeOfLastDSScavenge = GetTickCount();
  2127. DWORD TimeOfLastParameterCheck = 0;
  2128. DWORD Error,
  2129. Result;
  2130. HANDLE WaitHandle[PROCESS_EVENT_COUNT];
  2131. DWORD secondsSinceLastScavenge;
  2132. WaitHandle[PROCESS_TERMINATE_EVENT] = BinlGlobalProcessTerminationEvent;
  2133. WaitHandle[PROCESS_PNP_EVENT] = BinlGlobalPnpEvent;
  2134. WaitHandle[PROCESS_LSA_EVENT] = BinlGlobalLsaDnsNameNotifyEvent;
  2135. while ((!BinlGlobalSystemShuttingDown) &&
  2136. (BinlGlobalServiceStatus.dwCurrentState != SERVICE_STOP_PENDING))
  2137. {
  2138. DWORD CurrentTime;
  2139. PLIST_ENTRY p;
  2140. //
  2141. // wait for one of the following event to occur :
  2142. // 1. if we are notified about a pnp change.
  2143. // 2. if we are asked to terminate
  2144. //
  2145. Result = WaitForMultipleObjects(
  2146. PROCESS_EVENT_COUNT, // num. of handles.
  2147. WaitHandle, // handle array.
  2148. FALSE, // wait for any.
  2149. BINL_HYPERMODE_TIMEOUT ); // timeout in msecs.
  2150. if (Result == PROCESS_TERMINATE_EVENT) {
  2151. //
  2152. // The termination event has been signalled
  2153. //
  2154. break;
  2155. } else if (Result == PROCESS_PNP_EVENT) {
  2156. //
  2157. // The pnp notify event has been signalled
  2158. //
  2159. GetIpAddressInfo( BINL_PNP_DELAY_SECONDS * 1000 );
  2160. Error = BinlSetupPnpWait( );
  2161. if (Error != 0) {
  2162. BinlPrintDbg(( DEBUG_ERRORS, "BinlScavenger could not set pnp event, %ld.\n", Error ));
  2163. }
  2164. } else if (Result == PROCESS_LSA_EVENT) {
  2165. Error = GetOurServerInfo( );
  2166. if (Error != ERROR_SUCCESS) {
  2167. BinlPrintDbg(( DEBUG_ERRORS, "BinlScavenger could not get server name info, 0x%08x.\n", Error ));
  2168. }
  2169. }
  2170. //
  2171. // Capture the current time (in milliseconds).
  2172. //
  2173. CurrentTime = GetTickCount( );
  2174. secondsSinceLastScavenge = CurrentTime - TimeOfLastScavenge;
  2175. //
  2176. // If we haven't scavenged recently, do so now.
  2177. //
  2178. if ( secondsSinceLastScavenge >= BinlGlobalScavengerSleep ) {
  2179. HANDLE hFind;
  2180. WCHAR SifFilePath[MAX_PATH];
  2181. WIN32_FIND_DATA FindData;
  2182. ULARGE_INTEGER CurrentTimeConv,FileTime;
  2183. FILETIME CurrentFileTime;
  2184. PWSTR ptr;
  2185. TimeOfLastScavenge = CurrentTime;
  2186. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging Clients...\n"));
  2187. fLeftCriticalSection = FALSE;
  2188. EnterCriticalSection(&ClientsCriticalSection);
  2189. for (p = ClientsQueue.Flink; p != &ClientsQueue; p = p->Flink)
  2190. {
  2191. PCLIENT_STATE TempClient;
  2192. TempClient = CONTAINING_RECORD(p, CLIENT_STATE, Linkage);
  2193. if ( CurrentTime - TempClient->LastUpdate > BinlClientTimeout * 1000 )
  2194. {
  2195. BOOL FreeClientState;
  2196. BinlPrintDbg((DEBUG_SCAVENGER, "Savenger deleting client = 0x%08x\n", TempClient ));
  2197. RemoveEntryList(&TempClient->Linkage);
  2198. TempClient->PositiveRefCount++; // one for CS
  2199. LeaveCriticalSection(&ClientsCriticalSection);
  2200. fLeftCriticalSection = TRUE;
  2201. EnterCriticalSection(&TempClient->CriticalSection);
  2202. TempClient->NegativeRefCount += 2; // one for CS and one of Logoff
  2203. //
  2204. // FreeClientState will be TRUE if the two refcounts are equal.
  2205. // Otherwize another thread is being held by the clientState's CS
  2206. // and it will take care of deleting the CS when it's done.
  2207. //
  2208. FreeClientState = (BOOL)(TempClient->PositiveRefCount == TempClient->NegativeRefCount);
  2209. LeaveCriticalSection(&TempClient->CriticalSection);
  2210. if (FreeClientState)
  2211. {
  2212. FreeClient(TempClient);
  2213. }
  2214. break;
  2215. }
  2216. }
  2217. if ( !fLeftCriticalSection ) {
  2218. LeaveCriticalSection(&ClientsCriticalSection);
  2219. }
  2220. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging Clients Complete\n"));
  2221. //
  2222. // scavenge the SIF files
  2223. //
  2224. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging SIF Files...\n"));
  2225. GetSystemTimeAsFileTime( &CurrentFileTime );
  2226. CurrentTimeConv.LowPart = CurrentFileTime.dwLowDateTime;
  2227. CurrentTimeConv.HighPart = CurrentFileTime.dwHighDateTime;
  2228. if ( _snwprintf( SifFilePath,
  2229. sizeof(SifFilePath) / sizeof(SifFilePath[0]),
  2230. L"%ws\\%ws\\",
  2231. IntelliMirrorPathW,
  2232. TEMP_DIRECTORY ) != -1 ) {
  2233. ptr = SifFilePath + wcslen(SifFilePath);
  2234. wcscat(SifFilePath,L"*.sif");
  2235. hFind = FindFirstFile(SifFilePath,&FindData);
  2236. if (hFind != INVALID_HANDLE_VALUE) {
  2237. do {
  2238. FileTime.LowPart = FindData.ftCreationTime.dwLowDateTime;
  2239. FileTime.HighPart = FindData.ftCreationTime.dwHighDateTime;
  2240. FileTime.QuadPart += BinlSifFileScavengerTime.QuadPart;
  2241. //
  2242. // if the file has been on the server long enough,
  2243. // we delete it
  2244. //
  2245. if (_wcsicmp(FindData.cFileName,L".") != 0 &&
  2246. _wcsicmp(FindData.cFileName,L"..") != 0 &&
  2247. CurrentTimeConv.QuadPart > FileTime.QuadPart) {
  2248. *ptr = L'\0';
  2249. wcscat(SifFilePath,FindData.cFileName);
  2250. BinlPrintDbg((DEBUG_SCAVENGER,
  2251. "Attempting to scavenge SIF File %S...\n",
  2252. SifFilePath));
  2253. SetFileAttributes(SifFilePath,FILE_ATTRIBUTE_NORMAL);
  2254. if (!DeleteFile(SifFilePath)) {
  2255. BinlPrintDbg((DEBUG_SCAVENGER,
  2256. "Failed to scavenge SIF File %S, ec = %d\n",
  2257. SifFilePath,
  2258. GetLastError() ));
  2259. }
  2260. }
  2261. } while ( FindNextFile(hFind,&FindData) );
  2262. FindClose( hFind );
  2263. }
  2264. }
  2265. BinlPrintDbg((DEBUG_SCAVENGER, "Scavenging SIF Files Complete\n"));
  2266. }
  2267. secondsSinceLastScavenge = CurrentTime - TimeOfLastDSScavenge;
  2268. if ( secondsSinceLastScavenge >= BinlGlobalLdapErrorScavenger) {
  2269. TimeOfLastDSScavenge = CurrentTime;
  2270. if (BinlGlobalLdapErrorCount >= BinlGlobalMaxLdapErrorsLogged) {
  2271. ULONG seconds = BinlGlobalLdapErrorScavenger / 1000;
  2272. PWCHAR strings[2];
  2273. WCHAR secondsString[10];
  2274. swprintf(secondsString, L"%d", seconds);
  2275. strings[0] = secondsString;
  2276. strings[1] = NULL;
  2277. BinlReportEventW( EVENT_WARNING_LDAP_ERRORS,
  2278. EVENTLOG_WARNING_TYPE,
  2279. 1,
  2280. sizeof(BinlGlobalLdapErrorCount),
  2281. strings,
  2282. &BinlGlobalLdapErrorCount
  2283. );
  2284. }
  2285. BinlGlobalLdapErrorCount = 0;
  2286. }
  2287. //
  2288. // If we haven't read our parameters recently, do so now.
  2289. //
  2290. // "Recently" is normally a long time period -- defaulting to four hours.
  2291. // But when we are in "hyper" mode, we read our parameters every minute.
  2292. // There are two reasons to be in "hyper" mode:
  2293. //
  2294. // 1. We were not able to read our parameters during initialization. We
  2295. // need to get the parameters quickly so that we can truly consider
  2296. // ourselves initialized. In this case, BinlHyperUpdateCount will
  2297. // always be 1.
  2298. //
  2299. // 2. We were told by the admin UI that our parameters had changed. We
  2300. // need to read the parameters a number of times over a period of
  2301. // time because of DS propagation delays. In this case,
  2302. // BinlHyperUpdateCount starts at BINL_HYPERMODE_RETRY_COUNT (30),
  2303. // and is decremented each time we attempt to read our parameters.
  2304. //
  2305. // If we are not in hyper mode, then we try to read our parameters and
  2306. // we don't care if we fail. If we are in hyper mode, then we decrement
  2307. // BinlHyperUpdateCount each time we try to read our parameters, and we
  2308. // stay in hyper mode until BinlHyperUpdateCount is decremented to 0.
  2309. // But we don't let the count go to 0 until we have successfully read
  2310. // our parameters at least once while in hyper mode.
  2311. if ( (CurrentTime - TimeOfLastParameterCheck) >=
  2312. ((BinlHyperUpdateCount != 0) ? BINL_HYPERMODE_TIMEOUT : BinlUpdateFromDSTimeout) ) {
  2313. TimeOfLastParameterCheck = CurrentTime;
  2314. BinlPrintDbg((DEBUG_SCAVENGER, "Reading parameters...\n"));
  2315. Error = BinlReadParameters( );
  2316. //
  2317. // If we're not in hyper mode, we don't care if reading the
  2318. // parameters failed. But if we're in hyper mode, we have
  2319. // to do some extra work.
  2320. //
  2321. if ( BinlHyperUpdateCount != 0 ) {
  2322. //
  2323. // If the read worked, then we set BinlHyperUpdateSatisfied.
  2324. // Also, if this is the first time we've managed to read
  2325. // our parameters, we log an event indicating that we're
  2326. // ready.
  2327. //
  2328. if ( Error == ERROR_SUCCESS ) {
  2329. BinlHyperUpdateSatisfied = TRUE;
  2330. if ( !BinlParametersRead ) {
  2331. BinlParametersRead = TRUE;
  2332. BinlServerEventLog(
  2333. EVENT_SERVER_INIT_AND_READY,
  2334. EVENTLOG_INFORMATION_TYPE,
  2335. Error );
  2336. }
  2337. }
  2338. //
  2339. // Decrement the update count. However, if we have not yet
  2340. // managed to read our parameters while in hyper mode, don't
  2341. // let the count go to 0.
  2342. //
  2343. BinlHyperUpdateCount--;
  2344. if ( (BinlHyperUpdateCount == 0) && !BinlHyperUpdateSatisfied ) {
  2345. BinlHyperUpdateCount = 1;
  2346. }
  2347. BinlPrintDbg((DEBUG_SCAVENGER, "Hypermode count: %u\n", BinlHyperUpdateCount ));
  2348. }
  2349. BinlPrintDbg((DEBUG_SCAVENGER, "Reading parameters complete\n"));
  2350. }
  2351. }
  2352. if (BinlGlobalPnpEvent != NULL) {
  2353. CloseHandle( BinlGlobalPnpEvent );
  2354. BinlGlobalPnpEvent = NULL;
  2355. }
  2356. return( ERROR_SUCCESS );
  2357. }
  2358. VOID
  2359. TellBinlState(
  2360. int NewState
  2361. )
  2362. /*++
  2363. Routine Description:
  2364. This routine is called by DHCP when it starts (when we need to stop
  2365. listening on the DHCP socket) and when it stops (when we need to start).
  2366. Arguments:
  2367. NewState - Supplies DHCP's state.
  2368. Return Value:
  2369. None.
  2370. --*/
  2371. {
  2372. BOOLEAN haveLock = TRUE;
  2373. EnterCriticalSection(&gcsDHCPBINL);
  2374. //
  2375. // If BinlGlobalEndpointList is NULL then BINL isn't started so just
  2376. // record the NewState
  2377. //
  2378. if (NewState == DHCP_STARTING) {
  2379. if (DHCPState == DHCP_STOPPED) {
  2380. // DHCP is going from stopped to running.
  2381. DHCPState = NewState;
  2382. // BINL needs to close the DHCP socket so that DHCP can receive datagrams
  2383. if (BinlCurrentState != BINL_STOPPED) {
  2384. MaybeCloseEndpoint( &BinlGlobalEndpointList[0]);
  2385. LeaveCriticalSection(&gcsDHCPBINL);
  2386. haveLock = FALSE;
  2387. StopRogueThread( );
  2388. }
  2389. } else {
  2390. BinlAssert( DHCPState == DHCP_STARTING );
  2391. }
  2392. } else if (NewState == DHCP_STOPPED) {
  2393. if (DHCPState == DHCP_STARTING) {
  2394. // DHCP is going from running to stopped.
  2395. DHCPState = NewState;
  2396. if (BinlCurrentState != BINL_STOPPED) {
  2397. MaybeInitializeEndpoint( &BinlGlobalEndpointList[0],
  2398. NULL,
  2399. DHCP_SERVR_PORT);
  2400. LeaveCriticalSection(&gcsDHCPBINL);
  2401. haveLock = FALSE;
  2402. MaybeStartRogueThread( );
  2403. }
  2404. } else {
  2405. BinlAssert( DHCPState == DHCP_STOPPED );
  2406. }
  2407. } else if (NewState == DHCP_AUTHORIZED) {
  2408. HandleRogueAuthorized( );
  2409. } else if (NewState == DHCP_NOT_AUTHORIZED) {
  2410. HandleRogueUnauthorized( );
  2411. } else {
  2412. BinlPrintDbg((DEBUG_ERRORS, "TellBinlState called with 0x%x\n", NewState ));
  2413. }
  2414. if (haveLock) {
  2415. LeaveCriticalSection(&gcsDHCPBINL);
  2416. }
  2417. return;
  2418. }
  2419. BOOL
  2420. BinlState (
  2421. VOID
  2422. )
  2423. /*++
  2424. Routine Description:
  2425. This routine is called by DHCP when it starts (when we need to stop
  2426. listening on the DHCP socket) and when it stops (when we need to start).
  2427. Arguments:
  2428. None.
  2429. Return Value:
  2430. TRUE if BINL running.
  2431. --*/
  2432. {
  2433. return (BinlCurrentState == BINL_STARTED)?TRUE:FALSE;
  2434. }
  2435. BOOLEAN
  2436. BinlDllInitialize(
  2437. IN HINSTANCE DllHandle,
  2438. IN ULONG Reason,
  2439. IN LPVOID lpReserved OPTIONAL
  2440. )
  2441. {
  2442. //
  2443. // Handle attaching binlsvc.dll to a new process.
  2444. //
  2445. //DebugBreak( );
  2446. if (Reason == DLL_PROCESS_ATTACH) {
  2447. INITIALIZE_TRACE_MEMORY;
  2448. //
  2449. // Initialize critical sections.
  2450. //
  2451. InitializeCriticalSection( &gcsDHCPBINL );
  2452. InitializeCriticalSection( &gcsParameters );
  2453. // don't call in here with thread attach/detach notices please...
  2454. DisableThreadLibraryCalls( DllHandle );
  2455. //
  2456. // When DLL_PROCESS_DETACH and lpReserved is NULL, then a FreeLibrary
  2457. // call is being made. If lpReserved is Non-NULL, and ExitProcess is
  2458. // in progress. These cleanup routines will only be called when
  2459. // a FreeLibrary is being called. ExitProcess will automatically
  2460. // clean up all process resources, handles, and pending io.
  2461. //
  2462. } else if ((Reason == DLL_PROCESS_DETACH) &&
  2463. (lpReserved == NULL)) {
  2464. UNINITIALIZE_TRACE_MEMORY;
  2465. DeleteCriticalSection( &gcsParameters );
  2466. DeleteCriticalSection( &gcsDHCPBINL );
  2467. }
  2468. return TRUE;
  2469. }
  2470. VOID
  2471. SendWakeup(
  2472. PENDPOINT pEndpoint
  2473. )
  2474. /*++
  2475. Routine Description:
  2476. Send a loopback packet to the BINL socket. This will cause the
  2477. select to change so that it includes or excludes the DHCP socket
  2478. as appropriate.
  2479. Arguments:
  2480. pEndpoint - Supplies the socket to send the packet on.
  2481. Return Value:
  2482. None.
  2483. --*/
  2484. {
  2485. DHCP_MESSAGE SendBuffer;
  2486. SOCKADDR_IN saUdpServ;
  2487. RtlZeroMemory(&SendBuffer, sizeof(SendBuffer));
  2488. // We ignore anything that is not BOOT_REQUEST
  2489. SendBuffer.Operation = ~BOOT_REQUEST;
  2490. saUdpServ.sin_family = AF_INET;
  2491. saUdpServ.sin_addr.s_addr = htonl ( INADDR_LOOPBACK );
  2492. saUdpServ.sin_port = htons ( (USHORT)g_Port );
  2493. BinlPrintDbg((DEBUG_MISC, "Sending dummy packet\n"));
  2494. sendto( pEndpoint->Socket,
  2495. (char *)&SendBuffer,
  2496. sizeof(SendBuffer),
  2497. 0,
  2498. (const struct sockaddr *)&saUdpServ,
  2499. sizeof ( SOCKADDR_IN )
  2500. );
  2501. }
  2502. DWORD
  2503. MaybeInitializeEndpoint(
  2504. PENDPOINT pEndpoint,
  2505. PDHCP_IP_ADDRESS pIpAddress,
  2506. DWORD Port
  2507. )
  2508. /*++
  2509. Routine Description:
  2510. This function initializes an endpoint by creating and binding a
  2511. socket to the local address if DHCP is not running.
  2512. Arguments:
  2513. pEndpoint - Receives a pointer to the newly created socket
  2514. pIpAddress - The IP address to initialize to INADDR_ANY if NULL.
  2515. Port - The port to bind to.
  2516. Return Value:
  2517. The status of the operation.
  2518. --*/
  2519. {
  2520. DWORD Error = ERROR_SUCCESS;
  2521. EnterCriticalSection(&gcsDHCPBINL);
  2522. if (DHCPState == DHCP_STOPPED) {
  2523. Error = BinlInitializeEndpoint( pEndpoint,
  2524. pIpAddress,
  2525. Port);
  2526. BinlPrintDbg((DEBUG_MISC, "Opened Socket %lx\n", pEndpoint->Socket ));
  2527. //
  2528. // We may have a thread already doing a select and listening to
  2529. // the BINL socket. Send a dummy packet so that it will do a new
  2530. // select that includes this socket.
  2531. //
  2532. if ( Error == ERROR_SUCCESS ) {
  2533. SendWakeup(pEndpoint);
  2534. }
  2535. }
  2536. LeaveCriticalSection(&gcsDHCPBINL);
  2537. return Error;
  2538. }
  2539. VOID
  2540. MaybeCloseEndpoint(
  2541. PENDPOINT pEndpoint
  2542. )
  2543. /*++
  2544. Routine Description:
  2545. This function closes an endpoint if it is open. Usually caused
  2546. when DHCP starts/
  2547. Arguments:
  2548. pEndpoint - Pointer to the socket
  2549. Return Value:
  2550. None.
  2551. --*/
  2552. {
  2553. EnterCriticalSection(&gcsDHCPBINL);
  2554. if( pEndpoint->Socket != 0 ) {
  2555. //
  2556. // Set pEndpoint->Socket to 0 first so that the wait loop gets only
  2557. // one error when we close the socket. Otherwise there is a race until
  2558. // we get it set to 0 where the wait loop will loop quickly failing.
  2559. //
  2560. SOCKET Socket = pEndpoint->Socket;
  2561. BinlPrintDbg((DEBUG_MISC, "Close Socket %lx\n", Socket ));
  2562. pEndpoint->Socket = 0;
  2563. closesocket( Socket );
  2564. }
  2565. LeaveCriticalSection(&gcsDHCPBINL);
  2566. }
  2567. //
  2568. // Create a copy of a string by allocating heap memory.
  2569. //
  2570. LPSTR
  2571. BinlStrDupA( LPCSTR pStr )
  2572. {
  2573. DWORD dwLen = (strlen( pStr ) + 1) * sizeof(CHAR);
  2574. LPSTR psz = BinlAllocateMemory( dwLen );
  2575. if (psz) {
  2576. memcpy( psz, pStr, dwLen );
  2577. }
  2578. return psz;
  2579. }
  2580. LPWSTR
  2581. BinlStrDupW( LPCWSTR pStr )
  2582. {
  2583. DWORD dwLen = (wcslen( pStr ) + 1) * sizeof(WCHAR);
  2584. LPWSTR psz = (LPWSTR) BinlAllocateMemory( dwLen );
  2585. if (psz) {
  2586. memcpy( psz, pStr, dwLen );
  2587. }
  2588. return psz;
  2589. }
  2590. NTSTATUS
  2591. BinlSetupPnpWait (
  2592. VOID
  2593. )
  2594. {
  2595. NTSTATUS Error;
  2596. ULONG bytesRequired = 0;
  2597. BinlAssert(BinlPnpSocket != INVALID_SOCKET);
  2598. memset((PCHAR) &BinlPnpOverlapped, '\0', sizeof( WSAOVERLAPPED ));
  2599. BinlPnpOverlapped.hEvent = BinlGlobalPnpEvent;
  2600. Error = WSAIoctl( BinlPnpSocket,
  2601. SIO_ADDRESS_LIST_CHANGE,
  2602. NULL,
  2603. 0,
  2604. NULL,
  2605. 0,
  2606. &bytesRequired,
  2607. &BinlPnpOverlapped,
  2608. NULL
  2609. );
  2610. if (Error != 0) {
  2611. Error = WSAGetLastError();
  2612. //
  2613. // a return code of ERROR_IO_PENDING is perfectly valid here.
  2614. //
  2615. if (Error == ERROR_IO_PENDING) {
  2616. Error = 0;
  2617. }
  2618. }
  2619. return Error;
  2620. }