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.

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