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.

1744 lines
48 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. browser.c
  5. Abstract:
  6. This module contains the worker routines for the NetWksta APIs
  7. implemented in the Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 20-Feb-1991
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <lmuse.h> // NetUseDel
  15. //-------------------------------------------------------------------//
  16. // //
  17. // Local structure definitions //
  18. // //
  19. //-------------------------------------------------------------------//
  20. // Used to throttle our event logging in the case of unexpected network outages
  21. #define BR_LIST_RETRIEVAL_ERROR_MAX 4
  22. //-------------------------------------------------------------------//
  23. // //
  24. // Local function prototypes //
  25. // //
  26. //-------------------------------------------------------------------//
  27. VOID
  28. CompleteAsyncBrowserIoControl(
  29. IN PVOID ApcContext,
  30. IN PIO_STATUS_BLOCK IoStatusBlock,
  31. IN ULONG Reserved
  32. );
  33. VOID
  34. BecomeBackupCompletion (
  35. IN PVOID Ctx
  36. );
  37. VOID
  38. ChangeBrowserRole (
  39. IN PVOID Ctx
  40. );
  41. NET_API_STATUS
  42. PostWaitForNewMasterName(
  43. PNETWORK Network,
  44. LPWSTR MasterName OPTIONAL
  45. );
  46. VOID
  47. NewMasterCompletionRoutine(
  48. IN PVOID Ctx
  49. );
  50. NET_API_STATUS
  51. BrRetrieveInterimServerList(
  52. IN PNETWORK Network,
  53. IN ULONG ServerType
  54. );
  55. //-------------------------------------------------------------------//
  56. // //
  57. // Global function prototypes //
  58. // //
  59. //-------------------------------------------------------------------//
  60. NET_API_STATUS
  61. BrBecomeBackup(
  62. IN PNETWORK Network
  63. )
  64. /*++
  65. Routine Description:
  66. This function performs all the operations needed to make a browser server
  67. a backup browser server when starting the browser from scratch.
  68. Arguments:
  69. Network - Network to become backup browser for
  70. Return Value:
  71. Status - The status of the operation.
  72. --*/
  73. {
  74. NET_API_STATUS Status;
  75. //
  76. // Checkpoint the service controller - this gives us 30 seconds/transport
  77. // before the service controller gets unhappy.
  78. //
  79. (void) BrGiveInstallHints( SERVICE_START_PENDING );
  80. if (!LOCK_NETWORK(Network)) {
  81. return NERR_InternalError;
  82. }
  83. //
  84. // We want to ignore any failures from becoming a backup browser.
  85. //
  86. // We do this because we will fail to become a backup on a disconnected
  87. // (or connected) RAS link, and if we failed this routine, we would
  88. // fail to start at all.
  89. //
  90. // We will handle failure to become a backup in a "reasonable manner"
  91. // inside BecomeBackup.
  92. //
  93. BecomeBackup(Network, NULL);
  94. UNLOCK_NETWORK(Network);
  95. return NERR_Success;
  96. }
  97. NET_API_STATUS
  98. BecomeBackup(
  99. IN PNETWORK Network,
  100. IN PVOID Context
  101. )
  102. /*++
  103. Routine Description:
  104. This function performs all the operations needed to make a browser server
  105. a backup browser server
  106. Arguments:
  107. None.
  108. Return Value:
  109. Status - The status of the operation.
  110. NOTE:::: THIS ROUTINE IS CALLED WITH THE NETWORK STRUCTURE LOCKED!!!!!
  111. --*/
  112. {
  113. NET_API_STATUS Status = NERR_Success;
  114. PUNICODE_STRING MasterName = Context;
  115. BrPrint(( BR_BACKUP,
  116. "%ws: %ws: BecomeBackup called\n",
  117. Network->DomainInfo->DomUnicodeDomainName,
  118. Network->NetworkName.Buffer));
  119. if (Network->TimeStoppedBackup != 0 &&
  120. (BrCurrentSystemTime() - Network->TimeStoppedBackup) <= (BrInfo.BackupBrowserRecoveryTime / 1000)) {
  121. //
  122. // We stopped being a backup too recently for us to restart being
  123. // a backup again, so just return a generic error.
  124. //
  125. //
  126. // Before we return, make sure we're not a backup in the eyes of
  127. // the browser.
  128. //
  129. BrPrint(( BR_BACKUP,
  130. "%ws: %ws: can't BecomeBackup since we were backup recently.\n",
  131. Network->DomainInfo->DomUnicodeDomainName,
  132. Network->NetworkName.Buffer));
  133. BrStopBackup(Network);
  134. return ERROR_ACCESS_DENIED;
  135. }
  136. //
  137. // If we know the name of the master, then we must have become a backup
  138. // after being a potential, in which case we already have a
  139. // becomemaster request outstanding.
  140. //
  141. if (MasterName == NULL) {
  142. //
  143. // Post a BecomeMaster request for each server. This will complete
  144. // when the machine becomes the master browser server (ie. it wins an
  145. // election).
  146. //
  147. //
  148. // Please note that we only post it if the machine is a backup -
  149. // if it's a potential master, then the become master will have
  150. // already been posted.
  151. //
  152. Status = PostBecomeMaster(Network);
  153. if (Status != NERR_Success) {
  154. return(Status);
  155. }
  156. //
  157. // Find out the name of the master on each network. This will force an
  158. // election if necessary. Please note that we must post the BecomeMaster
  159. // IoControl first to allow us to handle an election.
  160. //
  161. //
  162. // We unlock the network, because this may cause us to become promoted
  163. // to a master.
  164. //
  165. BrPrint(( BR_BACKUP,
  166. "%ws: %ws: FindMaster called from BecomeBackup\n",
  167. Network->DomainInfo->DomUnicodeDomainName,
  168. Network->NetworkName.Buffer));
  169. UNLOCK_NETWORK(Network);
  170. Status = GetMasterServerNames(Network);
  171. if (Status != NERR_Success) {
  172. //
  173. // Re-lock the network structure so we will return with the
  174. // network locked.
  175. //
  176. if (!LOCK_NETWORK(Network)) {
  177. return NERR_InternalError;
  178. }
  179. //
  180. // We couldn't find who the master is. Stop being a backup now.
  181. //
  182. BrPrint(( BR_BACKUP,
  183. "%ws: %ws: can't BecomeBackup since we can't find master.\n",
  184. Network->DomainInfo->DomUnicodeDomainName,
  185. Network->NetworkName.Buffer));
  186. BrStopBackup(Network);
  187. //
  188. // If we're a master now, we should return success. We've not
  189. // become a backup, but it wasn't an error.
  190. //
  191. // ERROR_MORE_DATA is the mapping for
  192. // STATUS_MORE_PROCESSING_REQUIRED which is returned when this
  193. // situation happens.
  194. //
  195. if ((Status == ERROR_MORE_DATA) || (Network->Role & ROLE_MASTER)) {
  196. Status = NERR_Success;
  197. }
  198. return(Status);
  199. }
  200. if (!LOCK_NETWORK(Network)) {
  201. return NERR_InternalError;
  202. }
  203. //
  204. // We managed to become a master. We want to return right away.
  205. //
  206. if (Network->Role & ROLE_MASTER) {
  207. return NERR_Success;
  208. }
  209. }
  210. #ifdef notdef
  211. //
  212. // ?? For now, we'll always PostForRoleChange on all transports regardless
  213. // of role.
  214. // We not only need to do it here. But we need to do it when we become
  215. // the master so we can find out when we loose an election.
  216. //
  217. //
  218. // We're now a backup, we need to issue an API that will complete if the
  219. // browse master doesn't like us (and thus forces us to shutdown).
  220. //
  221. //
  222. PostWaitForRoleChange ( Network );
  223. #endif // notdef
  224. PostWaitForNewMasterName(Network, Network->UncMasterBrowserName );
  225. //
  226. // Unlock the network structure before calling BackupBrowserTimerRoutine.
  227. //
  228. UNLOCK_NETWORK(Network);
  229. //
  230. // Run the timer that causes the browser to download a new browse list
  231. // from the master. This will seed our server and domain lists to
  232. // guarantee that any clients have a reasonable list. It will also
  233. // restart the timer to announce later on.
  234. //
  235. Status = BackupBrowserTimerRoutine(Network);
  236. if (!LOCK_NETWORK(Network)) {
  237. return NERR_InternalError;
  238. }
  239. if (Status == NERR_Success) {
  240. // Might not be since we dropped the lock.
  241. // ASSERT (Network->Role & ROLE_BACKUP);
  242. //
  243. // We're now a backup server, announce ourselves as such.
  244. //
  245. Status = BrUpdateNetworkAnnouncementBits(Network, 0);
  246. if (Status != NERR_Success) {
  247. BrPrint(( BR_CRITICAL,
  248. "%ws: %ws: Unable to become backup: %ld\n",
  249. Network->DomainInfo->DomUnicodeDomainName,
  250. Network->NetworkName.Buffer,
  251. Status));
  252. if (Network->Role & ROLE_BACKUP) {
  253. //
  254. // We were unable to become a backup.
  255. //
  256. // We need to back out and become a potential browser now.
  257. //
  258. //
  259. BrPrint(( BR_BACKUP,
  260. "%ws: %ws: can't BecomeBackup since we can't update announce bits.\n",
  261. Network->DomainInfo->DomUnicodeDomainName,
  262. Network->NetworkName.Buffer));
  263. BrStopBackup(Network);
  264. //
  265. // Make sure that we're going to become a potential browser
  266. // (we might not if we're an advanced server).
  267. //
  268. PostBecomeBackup(Network);
  269. }
  270. }
  271. return Status;
  272. }
  273. return Status;
  274. }
  275. NET_API_STATUS
  276. BrBecomePotentialBrowser (
  277. IN PVOID TimerContext
  278. )
  279. /*++
  280. Routine Description:
  281. This routine is called when a machine has stopped being a backup browser.
  282. It runs after a reasonable timeout period has elapsed, and marks the
  283. machine as a potential browser.
  284. Arguments:
  285. None.
  286. Return Value:
  287. Status - The status of the operation.
  288. --*/
  289. {
  290. IN PNETWORK Network = TimerContext;
  291. NET_API_STATUS Status;
  292. //
  293. // Prevent the network from being deleted while we're in this timer routine.
  294. //
  295. if ( BrReferenceNetwork( Network ) == NULL ) {
  296. return NERR_InternalError;
  297. }
  298. //
  299. // Mark this guy as a potential browser.
  300. //
  301. try {
  302. if (!LOCK_NETWORK(Network)) {
  303. try_return(Status = NERR_InternalError );
  304. }
  305. BrPrint(( BR_BACKUP,
  306. "%ws: %ws: BrBecomePotentialBrowser called\n",
  307. Network->DomainInfo->DomUnicodeDomainName,
  308. Network->NetworkName.Buffer));
  309. //
  310. // Reset that we've stopped being a backup, since it's been long
  311. // enough.
  312. //
  313. Network->TimeStoppedBackup = 0;
  314. if (BrInfo.MaintainServerList == 0) {
  315. Network->Role |= ROLE_POTENTIAL_BACKUP;
  316. Status = BrUpdateNetworkAnnouncementBits(Network, 0);
  317. if (Status != NERR_Success) {
  318. BrPrint(( BR_BACKUP,
  319. "%ws: %ws: Unable to reset backup announcement bits: %ld\n",
  320. Network->DomainInfo->DomUnicodeDomainName,
  321. Network->NetworkName.Buffer,
  322. Status));
  323. try_return(Status);
  324. }
  325. } else {
  326. //
  327. // If we're configured to be a backup browser, then we want to
  328. // become a backup once again.
  329. //
  330. BecomeBackup(Network, NULL);
  331. }
  332. Status = NO_ERROR;
  333. try_exit:NOTHING;
  334. } finally {
  335. UNLOCK_NETWORK(Network);
  336. BrDereferenceNetwork( Network );
  337. }
  338. return Status;
  339. }
  340. NET_API_STATUS
  341. BrStopBackup (
  342. IN PNETWORK Network
  343. )
  344. /*++
  345. Routine Description:
  346. This routine is called to stop a machine from being a backup browser.
  347. It is typically called after some form of error has occurred while
  348. running as a browser to make sure that we aren't telling anyone that
  349. we're a backup browser.
  350. We are also called when we receive a "reset state" tickle packet.
  351. Arguments:
  352. Network - The network being shut down.
  353. Return Value:
  354. Status - The status of the operation.
  355. --*/
  356. {
  357. NET_API_STATUS Status;
  358. //
  359. // This guy is shutting down - set his role to 0 and announce.
  360. //
  361. if (!LOCK_NETWORK(Network)) {
  362. return NERR_InternalError;
  363. }
  364. try {
  365. BrPrint(( BR_BACKUP,
  366. "%ws: %ws: BrStopBackup called\n",
  367. Network->DomainInfo->DomUnicodeDomainName,
  368. Network->NetworkName.Buffer));
  369. Network->Role &= ~(ROLE_BACKUP|ROLE_POTENTIAL_BACKUP);
  370. Status = BrUpdateNetworkAnnouncementBits( Network, 0 );
  371. if (Status != NERR_Success) {
  372. BrPrint(( BR_CRITICAL,
  373. "%ws: %ws: Unable to clear backup announcement bits: %ld\n",
  374. Network->DomainInfo->DomUnicodeDomainName,
  375. Network->NetworkName.Buffer,
  376. Status));
  377. try_return(Status);
  378. }
  379. Status = BrCancelTimer(&Network->BackupBrowserTimer);
  380. if (Status != NERR_Success) {
  381. BrPrint(( BR_CRITICAL,
  382. "%ws: %ws: Unable to clear backup browser timer: %ld\n",
  383. Network->DomainInfo->DomUnicodeDomainName,
  384. Network->NetworkName.Buffer,
  385. Status));
  386. try_return(Status);
  387. }
  388. if (Network->BackupDomainList != NULL) {
  389. NetApiBufferFree(Network->BackupDomainList);
  390. Network->BackupDomainList = NULL;
  391. Network->TotalBackupDomainListEntries = 0;
  392. }
  393. if (Network->BackupServerList != NULL) {
  394. NetApiBufferFree(Network->BackupServerList);
  395. Network->BackupServerList = NULL;
  396. Network->TotalBackupServerListEntries = 0;
  397. }
  398. BrDestroyResponseCache(Network);
  399. //
  400. // After our recovery time, we can become a potential browser again.
  401. //
  402. Status = BrSetTimer(&Network->BackupBrowserTimer, BrInfo.BackupBrowserRecoveryTime, BrBecomePotentialBrowser, Network);
  403. if (Status != NERR_Success) {
  404. BrPrint(( BR_CRITICAL,
  405. "%ws: %ws: Unable to clear backup browser timer: %ld\n",
  406. Network->DomainInfo->DomUnicodeDomainName,
  407. Network->NetworkName.Buffer,
  408. Status));
  409. try_return(Status);
  410. }
  411. try_exit:NOTHING;
  412. } finally {
  413. //
  414. // Remember when we were asked to stop being a backup browser.
  415. //
  416. Network->TimeStoppedBackup = BrCurrentSystemTime();
  417. UNLOCK_NETWORK(Network);
  418. }
  419. return Status;
  420. }
  421. NET_API_STATUS
  422. BackupBrowserTimerRoutine (
  423. IN PVOID TimerContext
  424. )
  425. {
  426. IN PNETWORK Network = TimerContext;
  427. NET_API_STATUS Status;
  428. PVOID ServerList = NULL;
  429. BOOLEAN NetworkLocked = FALSE;
  430. #ifdef ENABLE_PSEUDO_BROWSER
  431. if ( BrInfo.PseudoServerLevel == BROWSER_PSEUDO ) {
  432. //
  433. // No-op for Pseudo server
  434. //
  435. BrFreeNetworkTables(Network);
  436. return NERR_Success;
  437. }
  438. #endif
  439. //
  440. // Prevent the network from being deleted while we're in this timer routine.
  441. //
  442. if ( BrReferenceNetwork( Network ) == NULL ) {
  443. return NERR_InternalError;
  444. }
  445. try {
  446. if (!LOCK_NETWORK(Network)) {
  447. try_return(Status = NERR_InternalError );
  448. }
  449. NetworkLocked = TRUE;
  450. ASSERT (Network->LockCount == 1);
  451. ASSERT ( NetpIsUncComputerNameValid( Network->UncMasterBrowserName ) );
  452. BrPrint(( BR_BACKUP,
  453. "%ws: %ws: BackupBrowserTimerRoutine called\n",
  454. Network->DomainInfo->DomUnicodeDomainName,
  455. Network->NetworkName.Buffer));
  456. //
  457. // Make sure there's a become master oustanding.
  458. //
  459. PostBecomeMaster(Network);
  460. //
  461. // We managed to become a master by the time we locked the structure.
  462. // We want to return right away.
  463. //
  464. if (Network->Role & ROLE_MASTER) {
  465. try_return(Status = NERR_Success);
  466. }
  467. Status = BrRetrieveInterimServerList(Network, SV_TYPE_ALL);
  468. //
  469. // Bail out if we didn't get any new servers.
  470. //
  471. if (Status != NERR_Success && Status != ERROR_MORE_DATA) {
  472. //
  473. // Try again after an appropriate error delay.
  474. //
  475. try_return(Status);
  476. }
  477. //
  478. // Now do everything that we did above for the server list for the
  479. // list of domains.
  480. //
  481. Status = BrRetrieveInterimServerList(Network, SV_TYPE_DOMAIN_ENUM);
  482. //
  483. // We successfully updated the server and domain lists for this
  484. // server. Now age all the cached domain entries out of the cache.
  485. //
  486. if (Status == NERR_Success || Status == ERROR_MORE_DATA) {
  487. BrAgeResponseCache(Network);
  488. }
  489. try_return(Status);
  490. try_exit:NOTHING;
  491. } finally {
  492. NET_API_STATUS NetStatus;
  493. if (!NetworkLocked) {
  494. if (!LOCK_NETWORK(Network)) {
  495. Status = NERR_InternalError;
  496. goto finally_exit;
  497. }
  498. NetworkLocked = TRUE;
  499. }
  500. //
  501. // If the API succeeded, Mark that we're a backup and
  502. // reset the timer.
  503. //
  504. if (Status == NERR_Success || Status == ERROR_MORE_DATA ) {
  505. if ((Network->Role & ROLE_BACKUP) == 0) {
  506. //
  507. // If we weren't a backup, we are one now.
  508. //
  509. Network->Role |= ROLE_BACKUP;
  510. Status = BrUpdateNetworkAnnouncementBits(Network, 0);
  511. }
  512. Network->NumberOfFailedBackupTimers = 0;
  513. Network->TimeStoppedBackup = 0;
  514. //
  515. // Restart the timer for this domain.
  516. //
  517. NetStatus = BrSetTimer(&Network->BackupBrowserTimer, BrInfo.BackupPeriodicity*1000, BackupBrowserTimerRoutine, Network);
  518. if (NetStatus != NERR_Success) {
  519. BrPrint(( BR_CRITICAL,
  520. "%ws: %ws: Unable to restart browser backup timer: %lx\n",
  521. Network->DomainInfo->DomUnicodeDomainName,
  522. Network->NetworkName.Buffer,
  523. Status));
  524. }
  525. } else {
  526. //
  527. // We failed to retrieve a backup list, remember the failure and
  528. // decide if it's been too many failures. If not, just log
  529. // the error, if it has, stop being a backup browser.
  530. //
  531. Network->NumberOfFailedBackupTimers += 1;
  532. if (Network->NumberOfFailedBackupTimers >= BACKUP_ERROR_FAILURE) {
  533. LPWSTR SubStrings[1];
  534. SubStrings[0] = Network->NetworkName.Buffer;
  535. //
  536. // This guy can't be a backup any more, bail out now.
  537. //
  538. BrLogEvent(EVENT_BROWSER_BACKUP_STOPPED, Status, 1, SubStrings);
  539. BrPrint(( BR_BACKUP,
  540. "%ws: %ws: BackupBrowserTimerRoutine retrieve backup list so stop being backup.\n",
  541. Network->DomainInfo->DomUnicodeDomainName,
  542. Network->NetworkName.Buffer));
  543. BrStopBackup(Network);
  544. } else {
  545. //
  546. // Restart the timer for this domain.
  547. //
  548. NetStatus = BrSetTimer(&Network->BackupBrowserTimer, BACKUP_ERROR_PERIODICITY*1000, BackupBrowserTimerRoutine, Network);
  549. if (NetStatus != NERR_Success) {
  550. BrPrint(( BR_CRITICAL,
  551. "%ws: %ws: Unable to restart browser backup timer: %lx\n",
  552. Network->DomainInfo->DomUnicodeDomainName,
  553. Network->NetworkName.Buffer,
  554. Status));
  555. }
  556. }
  557. }
  558. if (NetworkLocked) {
  559. UNLOCK_NETWORK(Network);
  560. }
  561. BrDereferenceNetwork( Network );
  562. finally_exit:;
  563. }
  564. return Status;
  565. }
  566. NET_API_STATUS
  567. BrRetrieveInterimServerList(
  568. IN PNETWORK Network,
  569. IN ULONG ServerType
  570. )
  571. {
  572. ULONG EntriesInList;
  573. ULONG TotalEntriesInList;
  574. ULONG RetryCount = 2;
  575. TCHAR ServerName[UNCLEN+1];
  576. WCHAR ShareName[UNCLEN+1+LM20_NNLEN];
  577. LPTSTR TransportName;
  578. BOOLEAN NetworkLocked = TRUE;
  579. NET_API_STATUS Status;
  580. PVOID Buffer = NULL;
  581. ULONG ModifiedServerType = ServerType;
  582. LPTSTR ModifiedTransportName;
  583. ASSERT (Network->LockCount == 1);
  584. #ifdef ENABLE_PSEUDO_BROWSER
  585. if ( BrInfo.PseudoServerLevel == BROWSER_PSEUDO ) {
  586. //
  587. // No-op for Pseudo black hole server.
  588. //
  589. return NERR_Success;
  590. }
  591. #endif
  592. wcscpy(ServerName, Network->UncMasterBrowserName );
  593. BrPrint(( BR_BACKUP,
  594. "%ws: %ws: BrRetrieveInterimServerList: UNC servername is %ws\n",
  595. Network->DomainInfo->DomUnicodeDomainName,
  596. Network->NetworkName.Buffer,
  597. ServerName));
  598. try {
  599. TransportName = Network->NetworkName.Buffer;
  600. ModifiedTransportName = TransportName;
  601. //
  602. // If this is direct host IPX,
  603. // we remote the API over the Netbios IPX transport since
  604. // the NT redir doesn't support direct host IPX.
  605. //
  606. if ( (Network->Flags & NETWORK_IPX) &&
  607. Network->AlternateNetwork != NULL) {
  608. //
  609. // Use the alternate transport
  610. //
  611. ModifiedTransportName = Network->AlternateNetwork->NetworkName.Buffer;
  612. //
  613. // Tell the server to use it's alternate transport.
  614. //
  615. if ( ServerType == SV_TYPE_ALL ) {
  616. ModifiedServerType = SV_TYPE_ALTERNATE_XPORT;
  617. } else {
  618. ModifiedServerType |= SV_TYPE_ALTERNATE_XPORT;
  619. }
  620. }
  621. while (RetryCount--) {
  622. //
  623. // If we are promoted to master and fail to become the master,
  624. // we will still be marked as being the master in our network
  625. // structure, thus we should bail out of the loop in order
  626. // to prevent us from looping back on ourselves.
  627. //
  628. if (STRICMP(&ServerName[2], Network->DomainInfo->DomUnicodeComputerName) == 0) {
  629. if (NetworkLocked) {
  630. UNLOCK_NETWORK(Network);
  631. NetworkLocked = FALSE;
  632. }
  633. //
  634. // We were unable to find the master. Attempt to find out who
  635. // the master is. If there is none, this will force an
  636. // election.
  637. //
  638. BrPrint(( BR_BACKUP,
  639. "%ws: %ws: FindMaster called from BrRetrieveInterimServerList\n",
  640. Network->DomainInfo->DomUnicodeDomainName,
  641. Network->NetworkName.Buffer));
  642. Status = GetMasterServerNames(Network);
  643. if (Status != NERR_Success) {
  644. try_return(Status);
  645. }
  646. ASSERT (!NetworkLocked);
  647. if (!LOCK_NETWORK(Network)) {
  648. try_return(Status = NERR_InternalError);
  649. }
  650. NetworkLocked = TRUE;
  651. break;
  652. }
  653. //
  654. // If we somehow became the master, we don't want to try to
  655. // retrieve the list from ourselves either.
  656. //
  657. if (Network->Role & ROLE_MASTER) {
  658. try_return(Status = NERR_Success);
  659. }
  660. ASSERT (Network->LockCount == 1);
  661. if (NetworkLocked) {
  662. UNLOCK_NETWORK(Network);
  663. NetworkLocked = FALSE;
  664. }
  665. EntriesInList = 0;
  666. Status = RxNetServerEnum(ServerName, // Server name
  667. ModifiedTransportName, // Transport name
  668. 101, // Level
  669. (LPBYTE *)&Buffer, // Buffer
  670. 0xffffffff, // Prefered Max Length
  671. &EntriesInList, // EntriesRead
  672. &TotalEntriesInList, // TotalEntries
  673. ModifiedServerType, // Server type
  674. NULL, // Domain (use default)
  675. NULL // Resume key
  676. );
  677. //
  678. // If the redir is being possesive of some other transport,
  679. // urge it to behave.
  680. //
  681. if ( Status == ERROR_CONNECTION_ACTIVE ) {
  682. BrPrint(( BR_BACKUP,
  683. "%ws: %ws: Failed to retrieve %s list from server %ws: Connection is active (Try NetUseDel)\n",
  684. Network->DomainInfo->DomUnicodeDomainName,
  685. TransportName,
  686. (ServerType == SV_TYPE_ALL ? "server" : "domain"),
  687. ServerName ));
  688. //
  689. // Delete the IPC$ share.
  690. //
  691. Status = NetUseDel( NULL,
  692. ShareName,
  693. USE_FORCE );
  694. if ( Status != NO_ERROR ) {
  695. BrPrint(( BR_BACKUP,
  696. "%ws: %ws: Failed to retrieve %s list from server %ws: NetUseDel failed: %ld\n",
  697. Network->DomainInfo->DomUnicodeDomainName,
  698. TransportName,
  699. (ServerType == SV_TYPE_ALL ? "server" : "domain"),
  700. ServerName,
  701. Status));
  702. Status = ERROR_CONNECTION_ACTIVE;
  703. //
  704. // That worked so try it again.
  705. //
  706. } else {
  707. EntriesInList = 0;
  708. Status = RxNetServerEnum(ServerName, // Server name
  709. ModifiedTransportName, // Transport name
  710. 101, // Level
  711. (LPBYTE *)&Buffer, // Buffer
  712. 0xffffffff, // Prefered Max Length
  713. &EntriesInList, // EntriesRead
  714. &TotalEntriesInList, // TotalEntries
  715. ModifiedServerType, // Server type
  716. NULL, // Domain (use default)
  717. NULL // Resume key
  718. );
  719. }
  720. }
  721. if (Status != NERR_Success && Status != ERROR_MORE_DATA) {
  722. // Temporary network outages are actually expected. Lets not log an event until the
  723. // network has been unavailible 4 times in a row.
  724. Network->NetworkAccessFailures++;
  725. if( Network->NetworkAccessFailures > BR_LIST_RETRIEVAL_ERROR_MAX )
  726. {
  727. LPWSTR SubStrings[2];
  728. SubStrings[0] = ServerName;
  729. SubStrings[1] = TransportName;
  730. BrLogEvent((ServerType == SV_TYPE_DOMAIN_ENUM ?
  731. EVENT_BROWSER_DOMAIN_LIST_FAILED :
  732. EVENT_BROWSER_SERVER_LIST_FAILED),
  733. Status,
  734. 2,
  735. SubStrings);
  736. BrPrint(( BR_BACKUP,
  737. "%ws: %ws: Failed to retrieve %s list from server %ws: %ld\n",
  738. Network->DomainInfo->DomUnicodeDomainName,
  739. TransportName,
  740. (ServerType == SV_TYPE_ALL ? "server" : "domain"),
  741. ServerName,
  742. Status));
  743. Network->NetworkAccessFailures = 0;
  744. }
  745. } else {
  746. BrPrint(( BR_BACKUP,
  747. "%ws: %ws: Retrieved %s list from server %ws: E:%ld, T:%ld\n",
  748. Network->DomainInfo->DomUnicodeDomainName,
  749. TransportName,
  750. (ServerType == SV_TYPE_ALL ? "server" : "domain"),
  751. ServerName,
  752. EntriesInList,
  753. TotalEntriesInList));
  754. Network->NetworkAccessFailures = 0;
  755. }
  756. //
  757. // If we succeeded in retrieving the list, but we only got
  758. // a really small number of either servers or domains,
  759. // we want to turn this into a failure.
  760. //
  761. if (Status == NERR_Success) {
  762. if (((ServerType == SV_TYPE_DOMAIN_ENUM) &&
  763. (EntriesInList < BROWSER_MINIMUM_DOMAIN_NUMBER)) ||
  764. ((ServerType == SV_TYPE_ALL) &&
  765. (EntriesInList < BROWSER_MINIMUM_SERVER_NUMBER))) {
  766. Status = ERROR_INSUFFICIENT_BUFFER;
  767. }
  768. }
  769. if ((Status == NERR_Success) || (Status == ERROR_MORE_DATA)) {
  770. ASSERT (!NetworkLocked);
  771. if (!LOCK_NETWORK(Network)) {
  772. Status = NERR_InternalError;
  773. if ((EntriesInList != 0) && (Buffer != NULL)) {
  774. NetApiBufferFree(Buffer);
  775. Buffer = NULL;
  776. }
  777. break;
  778. }
  779. NetworkLocked = TRUE;
  780. ASSERT (Network->LockCount == 1);
  781. #if DBG
  782. BrUpdateDebugInformation((ServerType == SV_TYPE_DOMAIN_ENUM ?
  783. L"LastDomainListRead" :
  784. L"LastServerListRead"),
  785. L"BrowserServerName",
  786. TransportName,
  787. ServerName,
  788. 0);
  789. #endif
  790. //
  791. // We've retrieved a new list from the browse master, save
  792. // the new list away in the "appropriate" spot.
  793. //
  794. //
  795. // Of course, we free up the old buffer before we do this..
  796. //
  797. if (ServerType == SV_TYPE_DOMAIN_ENUM) {
  798. if (Network->BackupDomainList != NULL) {
  799. NetApiBufferFree(Network->BackupDomainList);
  800. }
  801. Network->BackupDomainList = Buffer;
  802. Network->TotalBackupDomainListEntries = EntriesInList;
  803. } else {
  804. if (Network->BackupServerList != NULL) {
  805. NetApiBufferFree(Network->BackupServerList);
  806. }
  807. Network->BackupServerList = Buffer;
  808. Network->TotalBackupServerListEntries = EntriesInList;
  809. }
  810. break;
  811. } else {
  812. NET_API_STATUS GetMasterNameStatus;
  813. if ((EntriesInList != 0) && (Buffer != NULL)) {
  814. NetApiBufferFree(Buffer);
  815. Buffer = NULL;
  816. }
  817. BrPrint(( BR_BACKUP,
  818. "%ws: %ws: Unable to contact browser server %ws: %lx\n",
  819. Network->DomainInfo->DomUnicodeDomainName,
  820. TransportName,
  821. ServerName,
  822. Status));
  823. if (NetworkLocked) {
  824. //
  825. // We were unable to find the master. Attempt to find out who
  826. // the master is. If there is none, this will force an
  827. // election.
  828. //
  829. ASSERT (Network->LockCount == 1);
  830. UNLOCK_NETWORK(Network);
  831. NetworkLocked = FALSE;
  832. }
  833. BrPrint(( BR_BACKUP,
  834. "%ws: %ws: FindMaster called from BrRetrieveInterimServerList for failure\n",
  835. Network->DomainInfo->DomUnicodeDomainName,
  836. Network->NetworkName.Buffer));
  837. GetMasterNameStatus = GetMasterServerNames(Network);
  838. //
  839. // We were able to find out who the master is.
  840. //
  841. // Retry and retrieve the server/domain list.
  842. //
  843. if (GetMasterNameStatus == NERR_Success) {
  844. ASSERT (!NetworkLocked);
  845. if (!LOCK_NETWORK(Network)) {
  846. try_return(Status = NERR_InternalError);
  847. }
  848. NetworkLocked = TRUE;
  849. ASSERT (Network->LockCount == 1);
  850. //
  851. // We managed to become a master. We want to return right away.
  852. //
  853. if (Network->Role & ROLE_MASTER) {
  854. try_return(Status = NERR_InternalError);
  855. }
  856. wcscpy(ServerName, Network->UncMasterBrowserName );
  857. ASSERT ( NetpIsUncComputerNameValid( ServerName ) );
  858. ASSERT (STRICMP(&ServerName[2], Network->DomainInfo->DomUnicodeComputerName) != 0);
  859. BrPrint(( BR_BACKUP,
  860. "%ws: %ws: New master name is %ws\n",
  861. Network->DomainInfo->DomUnicodeDomainName,
  862. Network->NetworkName.Buffer,
  863. ServerName));
  864. } else {
  865. try_return(Status);
  866. }
  867. }
  868. }
  869. try_exit:NOTHING;
  870. } finally {
  871. if (!NetworkLocked) {
  872. if (!LOCK_NETWORK(Network)) {
  873. Status = NERR_InternalError;
  874. }
  875. ASSERT (Network->LockCount == 1);
  876. }
  877. }
  878. return Status;
  879. }
  880. NET_API_STATUS
  881. PostBecomeBackup(
  882. PNETWORK Network
  883. )
  884. /*++
  885. Routine Description:
  886. This function is the worker routine called to actually issue a BecomeBackup
  887. FsControl to the bowser driver on all the bound transports. It will
  888. complete when the machine becomes a backup browser server.
  889. Please note that this might never complete.
  890. Arguments:
  891. None.
  892. Return Value:
  893. Status - The status of the operation.
  894. --*/
  895. {
  896. NET_API_STATUS Status;
  897. if (!LOCK_NETWORK(Network)) {
  898. return NERR_InternalError;
  899. }
  900. Network->Role |= ROLE_POTENTIAL_BACKUP;
  901. Status = BrIssueAsyncBrowserIoControl(Network,
  902. IOCTL_LMDR_BECOME_BACKUP,
  903. BecomeBackupCompletion,
  904. NULL );
  905. UNLOCK_NETWORK(Network);
  906. return Status;
  907. }
  908. VOID
  909. BecomeBackupCompletion (
  910. IN PVOID Ctx
  911. )
  912. {
  913. NET_API_STATUS Status;
  914. PBROWSERASYNCCONTEXT Context = Ctx;
  915. PNETWORK Network = Context->Network;
  916. if (NT_SUCCESS(Context->IoStatusBlock.Status)) {
  917. //
  918. // Ensure the network wasn't deleted from under us.
  919. //
  920. if ( BrReferenceNetwork( Network ) != NULL ) {
  921. if (LOCK_NETWORK(Network)) {
  922. BrPrint(( BR_BACKUP,
  923. "%ws: %ws: BecomeBackupCompletion. We are now a backup server\n",
  924. Network->DomainInfo->DomUnicodeDomainName,
  925. Network->NetworkName.Buffer ));
  926. Status = BecomeBackup(Context->Network, NULL);
  927. UNLOCK_NETWORK(Network);
  928. }
  929. BrDereferenceNetwork( Network );
  930. }
  931. }
  932. MIDL_user_free(Context);
  933. }
  934. VOID
  935. BrBrowseTableInsertRoutine(
  936. IN PINTERIM_SERVER_LIST InterimTable,
  937. IN PINTERIM_ELEMENT InterimElement
  938. )
  939. {
  940. //
  941. // We need to miss 3 retrievals of the browse list for us to toss the
  942. // server.
  943. //
  944. InterimElement->Periodicity = BrInfo.BackupPeriodicity * 3;
  945. if (InterimElement->TimeLastSeen != 0xffffffff) {
  946. InterimElement->TimeLastSeen = BrCurrentSystemTime();
  947. }
  948. }
  949. VOID
  950. BrBrowseTableDeleteRoutine(
  951. IN PINTERIM_SERVER_LIST InterimTable,
  952. IN PINTERIM_ELEMENT InterimElement
  953. )
  954. {
  955. // BrPrint(( BR_CRITICAL, "Deleting element for server %ws\n", InterimElement->Name));
  956. }
  957. VOID
  958. BrBrowseTableUpdateRoutine(
  959. IN PINTERIM_SERVER_LIST InterimTable,
  960. IN PINTERIM_ELEMENT InterimElement
  961. )
  962. {
  963. if (InterimElement->TimeLastSeen != 0xffffffff) {
  964. InterimElement->TimeLastSeen = BrCurrentSystemTime();
  965. }
  966. }
  967. BOOLEAN
  968. BrBrowseTableAgeRoutine(
  969. IN PINTERIM_SERVER_LIST InterimTable,
  970. IN PINTERIM_ELEMENT InterimElement
  971. )
  972. /*++
  973. Routine Description:
  974. This routine is called when we are scanning an interim server list trying
  975. to age the elements in the list. It returns TRUE if the entry is too
  976. old.
  977. Arguments:
  978. PINTERIM_SERVER_LIST InterimTable - A pointer to the interim server list.
  979. PINTERIM_ELEMENT InterimElement - A pointer to the element to check.
  980. Return Value:
  981. TRUE if the element should be deleted.
  982. --*/
  983. {
  984. if (InterimElement->TimeLastSeen == 0xffffffff) {
  985. return FALSE;
  986. }
  987. if ((InterimElement->TimeLastSeen + InterimElement->Periodicity) < BrCurrentSystemTime()) {
  988. // BrPrint(( BR_CRITICAL, "Aging out element for server %ws\n", InterimElement->Name));
  989. return TRUE;
  990. } else {
  991. return FALSE;
  992. }
  993. }
  994. VOID
  995. BrDomainTableInsertRoutine(
  996. IN PINTERIM_SERVER_LIST InterimTable,
  997. IN PINTERIM_ELEMENT InterimElement
  998. )
  999. {
  1000. InterimElement->Periodicity = BrInfo.BackupPeriodicity * 3;
  1001. InterimElement->TimeLastSeen = BrCurrentSystemTime();
  1002. }
  1003. VOID
  1004. BrDomainTableDeleteRoutine(
  1005. IN PINTERIM_SERVER_LIST InterimTable,
  1006. IN PINTERIM_ELEMENT InterimElement
  1007. )
  1008. {
  1009. // BrPrint(( BR_CRITICAL, "Deleting element for domain %ws\n", InterimElement->Name));
  1010. }
  1011. VOID
  1012. BrDomainTableUpdateRoutine(
  1013. IN PINTERIM_SERVER_LIST InterimTable,
  1014. IN PINTERIM_ELEMENT InterimElement
  1015. )
  1016. {
  1017. InterimElement->TimeLastSeen = BrCurrentSystemTime();
  1018. }
  1019. BOOLEAN
  1020. BrDomainTableAgeRoutine(
  1021. IN PINTERIM_SERVER_LIST InterimTable,
  1022. IN PINTERIM_ELEMENT InterimElement
  1023. )
  1024. /*++
  1025. Routine Description:
  1026. This routine is called when we are scanning an interim server list trying
  1027. to age the elements in the list. It returns TRUE if the entry is too
  1028. old.
  1029. Arguments:
  1030. PINTERIM_SERVER_LIST InterimTable - A pointer to the interim server list.
  1031. PINTERIM_ELEMENT InterimElement - A pointer to the element to check.
  1032. Return Value:
  1033. TRUE if the element should be deleted.
  1034. --*/
  1035. {
  1036. if ((InterimElement->TimeLastSeen + InterimElement->Periodicity) < BrCurrentSystemTime()) {
  1037. // BrPrint(( BR_CRITICAL, "Aging out element for domain %ws\n", InterimElement->Name));
  1038. return TRUE;
  1039. } else {
  1040. return FALSE;
  1041. }
  1042. }
  1043. NET_API_STATUS
  1044. PostWaitForRoleChange (
  1045. PNETWORK Network
  1046. )
  1047. /*++
  1048. Routine Description:
  1049. This function is the worker routine called to actually issue a WaitForRoleChange
  1050. FsControl to the bowser driver on all the bound transports. It will
  1051. complete when the machine becomes a backup browser server.
  1052. Please note that this might never complete.
  1053. Arguments:
  1054. None.
  1055. Return Value:
  1056. Status - The status of the operation.
  1057. --*/
  1058. {
  1059. NET_API_STATUS Status;
  1060. if (!LOCK_NETWORK(Network)) {
  1061. return NERR_InternalError;
  1062. }
  1063. Status = BrIssueAsyncBrowserIoControl(Network,
  1064. IOCTL_LMDR_CHANGE_ROLE,
  1065. ChangeBrowserRole,
  1066. NULL );
  1067. UNLOCK_NETWORK(Network);
  1068. return Status;
  1069. }
  1070. VOID
  1071. ChangeBrowserRole (
  1072. IN PVOID Ctx
  1073. )
  1074. {
  1075. PBROWSERASYNCCONTEXT Context = Ctx;
  1076. PNETWORK Network = Context->Network;
  1077. if (NT_SUCCESS(Context->IoStatusBlock.Status)) {
  1078. PWSTR MasterName = NULL;
  1079. PLMDR_REQUEST_PACKET Packet = Context->RequestPacket;
  1080. //
  1081. // Ensure the network wasn't deleted from under us.
  1082. //
  1083. if ( BrReferenceNetwork( Network ) != NULL ) {
  1084. if (LOCK_NETWORK(Network)) {
  1085. PostWaitForRoleChange(Network);
  1086. if (Packet->Parameters.ChangeRole.RoleModification & RESET_STATE_CLEAR_ALL) {
  1087. BrPrint(( BR_MASTER,
  1088. "%ws: %ws: Reset state request to clear all\n",
  1089. Network->DomainInfo->DomUnicodeDomainName,
  1090. Network->NetworkName.Buffer ));
  1091. if (Network->Role & ROLE_MASTER) {
  1092. BrStopMaster(Network);
  1093. }
  1094. //
  1095. // Stop being a backup as well.
  1096. //
  1097. BrStopBackup(Network);
  1098. }
  1099. if ((Network->Role & ROLE_MASTER) &&
  1100. (Packet->Parameters.ChangeRole.RoleModification & RESET_STATE_STOP_MASTER)) {
  1101. BrPrint(( BR_MASTER,
  1102. "%ws: %ws: Reset state request to stop master\n",
  1103. Network->DomainInfo->DomUnicodeDomainName,
  1104. Network->NetworkName.Buffer ));
  1105. BrStopMaster(Network);
  1106. //
  1107. // If we are configured to be a backup, then become a backup
  1108. // again.
  1109. //
  1110. if (BrInfo.MaintainServerList == 1) {
  1111. BecomeBackup(Network, NULL);
  1112. }
  1113. }
  1114. //
  1115. // Make sure there's a become master oustanding.
  1116. //
  1117. PostBecomeMaster(Network);
  1118. UNLOCK_NETWORK(Network);
  1119. }
  1120. BrDereferenceNetwork( Network );
  1121. }
  1122. }
  1123. MIDL_user_free(Context);
  1124. }
  1125. NET_API_STATUS
  1126. PostWaitForNewMasterName(
  1127. PNETWORK Network,
  1128. LPWSTR MasterName OPTIONAL
  1129. )
  1130. {
  1131. //
  1132. // Can't wait for new master on direct host IPC
  1133. //
  1134. if (Network->Flags & NETWORK_IPX) {
  1135. return STATUS_SUCCESS;
  1136. }
  1137. return BrIssueAsyncBrowserIoControl(
  1138. Network,
  1139. IOCTL_LMDR_NEW_MASTER_NAME,
  1140. NewMasterCompletionRoutine,
  1141. MasterName );
  1142. }
  1143. VOID
  1144. NewMasterCompletionRoutine(
  1145. IN PVOID Ctx
  1146. )
  1147. {
  1148. PBROWSERASYNCCONTEXT Context = Ctx;
  1149. PNETWORK Network = Context->Network;
  1150. BOOLEAN NetLocked = FALSE;
  1151. BOOLEAN NetReferenced = FALSE;
  1152. try {
  1153. UNICODE_STRING NewMasterName;
  1154. //
  1155. // Ensure the network wasn't deleted from under us.
  1156. //
  1157. if ( BrReferenceNetwork( Network ) == NULL ) {
  1158. try_return(NOTHING);
  1159. }
  1160. NetReferenced = TRUE;
  1161. BrPrint(( BR_MASTER,
  1162. "%ws: %ws: NewMasterCompletionRoutine: Got master changed\n",
  1163. Network->DomainInfo->DomUnicodeDomainName,
  1164. Network->NetworkName.Buffer ));
  1165. if (!LOCK_NETWORK(Network)){
  1166. try_return(NOTHING);
  1167. }
  1168. NetLocked = TRUE;
  1169. //
  1170. // The request failed for some other reason - just return immediately.
  1171. //
  1172. if (!NT_SUCCESS(Context->IoStatusBlock.Status)) {
  1173. try_return(NOTHING);
  1174. }
  1175. // Remove new master name & put in transport
  1176. if ( Network->Role & ROLE_MASTER ) {
  1177. try_return(NOTHING);
  1178. }
  1179. BrPrint(( BR_BACKUP,
  1180. "%ws: %ws: NewMasterCompletionRoutin: New:%ws Old %ws\n",
  1181. Network->DomainInfo->DomUnicodeDomainName,
  1182. Network->NetworkName.Buffer,
  1183. Context->RequestPacket->Parameters.GetMasterName.Name,
  1184. Network->UncMasterBrowserName ));
  1185. //
  1186. // Copy the master browser name into the network structure
  1187. //
  1188. wcsncpy( Network->UncMasterBrowserName,
  1189. Context->RequestPacket->Parameters.GetMasterName.Name,
  1190. UNCLEN+1 );
  1191. Network->UncMasterBrowserName[UNCLEN] = L'\0';
  1192. ASSERT ( NetpIsUncComputerNameValid ( Network->UncMasterBrowserName ) );
  1193. PostWaitForNewMasterName( Network, Network->UncMasterBrowserName );
  1194. try_exit:NOTHING;
  1195. } finally {
  1196. if (NetLocked) {
  1197. UNLOCK_NETWORK(Network);
  1198. }
  1199. if ( NetReferenced ) {
  1200. BrDereferenceNetwork( Network );
  1201. }
  1202. MIDL_user_free(Context);
  1203. }
  1204. return;
  1205. }
  1206. #ifdef ENABLE_PSEUDO_BROWSER
  1207. //
  1208. // Pseudo Server
  1209. // Phase out black hole Helper routines
  1210. //
  1211. VOID
  1212. BrFreeNetworkTables(
  1213. IN PNETWORK Network
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. Free network tables
  1218. Arguments:
  1219. Network to operate upon
  1220. Return Value:
  1221. None.
  1222. Remarks:
  1223. Acquire & release network locks
  1224. --*/
  1225. {
  1226. BOOL NetLocked = FALSE;
  1227. //
  1228. // Prevent the network from being deleted while we're in this timer routine.
  1229. //
  1230. if ( BrReferenceNetwork( Network ) == NULL ) {
  1231. return;
  1232. }
  1233. try{
  1234. // lock network
  1235. if (!LOCK_NETWORK(Network)) {
  1236. try_return(NOTHING);
  1237. }
  1238. NetLocked = TRUE;
  1239. //
  1240. // Delete tables
  1241. //
  1242. UninitializeInterimServerList(&Network->BrowseTable);
  1243. UninitializeInterimServerList(&Network->DomainList);
  1244. if (Network->BackupServerList != NULL) {
  1245. MIDL_user_free(Network->BackupServerList);
  1246. Network->BackupServerList = NULL;
  1247. Network->TotalBackupServerListEntries = 0;
  1248. }
  1249. if (Network->BackupDomainList != NULL) {
  1250. MIDL_user_free(Network->BackupDomainList);
  1251. Network->BackupDomainList = NULL;
  1252. Network->TotalBackupDomainListEntries = 0;
  1253. }
  1254. BrDestroyResponseCache(Network);
  1255. try_exit:NOTHING;
  1256. } finally {
  1257. //
  1258. // Release network
  1259. //
  1260. if (NetLocked) {
  1261. UNLOCK_NETWORK(Network);
  1262. }
  1263. BrDereferenceNetwork( Network );
  1264. }
  1265. }
  1266. #endif