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.

744 lines
21 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. bowmastr.c
  5. Abstract:
  6. This module implements all of the master browser related routines for the
  7. NT browser
  8. Author:
  9. Larry Osterman (LarryO) 21-Jun-1990
  10. Revision History:
  11. 21-Jun-1990 LarryO
  12. Created
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #define INCLUDE_SMB_TRANSACTION
  17. NTSTATUS
  18. StartProcessingAnnouncements(
  19. IN PTRANSPORT_NAME TransportName,
  20. IN PVOID Context
  21. );
  22. VOID
  23. BowserMasterAnnouncementWorker(
  24. IN PVOID Ctx
  25. );
  26. NTSTATUS
  27. TimeoutFindMasterRequests(
  28. IN PTRANSPORT Transport,
  29. IN PVOID Context
  30. );
  31. NTSTATUS
  32. BowserPrimeDomainTableWithOtherDomains(
  33. IN PTRANSPORT_NAME TransportName,
  34. IN PVOID Context
  35. );
  36. #ifdef ALLOC_PRAGMA
  37. #pragma alloc_text(PAGE, BowserBecomeMaster)
  38. #pragma alloc_text(PAGE, StartProcessingAnnouncements)
  39. #pragma alloc_text(PAGE, BowserPrimeDomainTableWithOtherDomains)
  40. #pragma alloc_text(PAGE, BowserNewMaster)
  41. #pragma alloc_text(PAGE, BowserCompleteFindMasterRequests)
  42. #pragma alloc_text(PAGE, BowserTimeoutFindMasterRequests)
  43. #pragma alloc_text(PAGE, TimeoutFindMasterRequests)
  44. #pragma alloc_text(PAGE, BowserMasterAnnouncementWorker)
  45. #endif
  46. NTSTATUS
  47. BowserBecomeMaster(
  48. IN PTRANSPORT Transport
  49. )
  50. /*++
  51. Routine Description:
  52. Make this machine a master browser.
  53. This routine is called when we are changing the state of a machine from
  54. backup to master browser.
  55. Arguments:
  56. Transport - The transport on which to become a master.
  57. Return Value
  58. NTSTATUS - The status of the upgrade operation.
  59. --*/
  60. {
  61. NTSTATUS Status;
  62. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  63. PAGED_CODE();
  64. try {
  65. LOCK_TRANSPORT(Transport);
  66. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  67. //
  68. // Post the addname on this transport for the master name..
  69. //
  70. Status = BowserAllocateName(
  71. &Transport->DomainInfo->DomUnicodeDomainName,
  72. MasterBrowser,
  73. Transport,
  74. Transport->DomainInfo );
  75. if (NT_SUCCESS(Status)) {
  76. //
  77. // Post the addname on this transport for the domain announcement.
  78. //
  79. Status = BowserAllocateName(&Transport->DomainInfo->DomUnicodeDomainName,
  80. DomainAnnouncement,
  81. Transport,
  82. Transport->DomainInfo );
  83. }
  84. //
  85. // The addition of the name failed - we can't be a master any
  86. // more.
  87. //
  88. if (!NT_SUCCESS(Status)) {
  89. try_return(Status);
  90. }
  91. PagedTransport->Role = Master;
  92. //
  93. // Start processing host announcements on each of
  94. // the names associated with the server.
  95. //
  96. BowserForEachTransportName(Transport, StartProcessingAnnouncements, NULL);
  97. //
  98. // If we don't have any elements in our announcement table,
  99. // send a request announcement packet to all the servers to
  100. // allow ourselves to populate the table as quickly as possible.
  101. //
  102. #ifdef ENABLE_PSEUDO_BROWSER
  103. if ((RtlNumberGenericTableElements(&PagedTransport->AnnouncementTable) == 0) &&
  104. PagedTransport->NumberOfServersInTable == 0 &&
  105. BowserData.PseudoServerLevel != BROWSER_PSEUDO) {
  106. #else
  107. if ((RtlNumberGenericTableElements(&PagedTransport->AnnouncementTable) == 0) &&
  108. PagedTransport->NumberOfServersInTable == 0) {
  109. #endif
  110. BowserSendRequestAnnouncement(&Transport->DomainInfo->DomUnicodeDomainName,
  111. PrimaryDomain,
  112. Transport);
  113. }
  114. //
  115. // If we don't have any elements in our domain table,
  116. // send a request announcement packet to all the servers to
  117. // allow ourselves to populate the table as quickly as possible.
  118. //
  119. #ifdef ENABLE_PSEUDO_BROWSER
  120. if ((RtlNumberGenericTableElements(&PagedTransport->DomainTable) == 0) &&
  121. PagedTransport->NumberOfServersInTable == 0 &&
  122. BowserData.PseudoServerLevel != BROWSER_PSEUDO) {
  123. #else
  124. if ((RtlNumberGenericTableElements(&PagedTransport->DomainTable) == 0) &&
  125. PagedTransport->NumberOfServersInTable == 0) {
  126. #endif
  127. BowserSendRequestAnnouncement(&Transport->DomainInfo->DomUnicodeDomainName,
  128. DomainAnnouncement,
  129. Transport);
  130. }
  131. PagedTransport->TimeMaster = BowserTimeUp();
  132. //
  133. // Now walk the transport names associated with this transport and
  134. // seed all the "otherdomains" into the browse list.
  135. //
  136. BowserForEachTransportName(
  137. Transport,
  138. BowserPrimeDomainTableWithOtherDomains,
  139. NULL);
  140. //
  141. // Now complete any and all find master requests outstanding on this
  142. // transport.
  143. //
  144. BowserCompleteFindMasterRequests(Transport, &Transport->DomainInfo->DomUnicodeComputerName, STATUS_REQUEST_NOT_ACCEPTED);
  145. try_return(Status = STATUS_SUCCESS);
  146. try_exit:NOTHING;
  147. } finally {
  148. if (!NT_SUCCESS(Status)) {
  149. dlog(DPRT_ELECT|DPRT_MASTER,
  150. ("%s: %ws: There's already a master on this net - we need to find who it is",
  151. Transport->DomainInfo->DomOemDomainName,
  152. PagedTransport->TransportName.Buffer ));
  153. //
  154. // We couldn't become a master. Reset our state and fail the
  155. // promotion request.
  156. //
  157. PagedTransport->Role = PotentialBackup;
  158. PagedTransport->ElectionCount = ELECTION_COUNT;
  159. PagedTransport->Uptime = BowserTimeUp();
  160. Transport->ElectionState = Idle;
  161. //
  162. // Stop processing host announcements on each of
  163. // the names associated with the server.
  164. //
  165. BowserForEachTransportName(Transport, BowserStopProcessingAnnouncements, NULL);
  166. //
  167. // Stop any timers that are running (ie. if there's an election
  168. // in progress)
  169. //
  170. BowserStopTimer(&Transport->ElectionTimer);
  171. //
  172. // Delete the names we added above.
  173. //
  174. BowserDeleteTransportNameByName(Transport,
  175. NULL,
  176. MasterBrowser);
  177. BowserDeleteTransportNameByName(Transport,
  178. NULL,
  179. DomainAnnouncement);
  180. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  181. }
  182. UNLOCK_TRANSPORT(Transport);
  183. }
  184. return Status;
  185. }
  186. NTSTATUS
  187. StartProcessingAnnouncements(
  188. IN PTRANSPORT_NAME TransportName,
  189. IN PVOID Context
  190. )
  191. {
  192. PAGED_CODE();
  193. ASSERT (TransportName->Signature == STRUCTURE_SIGNATURE_TRANSPORTNAME);
  194. ASSERT (TransportName->NameType == TransportName->PagedTransportName->Name->NameType);
  195. if ((TransportName->NameType == OtherDomain) ||
  196. (TransportName->NameType == MasterBrowser) ||
  197. (TransportName->NameType == PrimaryDomain) ||
  198. (TransportName->NameType == BrowserElection) ||
  199. (TransportName->NameType == DomainAnnouncement)) {
  200. if (!TransportName->ProcessHostAnnouncements) {
  201. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  202. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  203. TransportName->ProcessHostAnnouncements = TRUE;
  204. }
  205. }
  206. return(STATUS_SUCCESS);
  207. UNREFERENCED_PARAMETER(Context);
  208. }
  209. NTSTATUS
  210. BowserPrimeDomainTableWithOtherDomains(
  211. IN PTRANSPORT_NAME TransportName,
  212. IN PVOID Context
  213. )
  214. {
  215. PAGED_CODE();
  216. if (TransportName->NameType == OtherDomain) {
  217. PPAGED_TRANSPORT PagedTransport = TransportName->Transport->PagedTransport;
  218. PTRANSPORT Transport = TransportName->Transport;
  219. ANNOUNCE_ENTRY OtherDomainPrototype;
  220. PANNOUNCE_ENTRY Announcement;
  221. BOOLEAN NewElement;
  222. RtlZeroMemory( &OtherDomainPrototype, sizeof(OtherDomainPrototype) );
  223. OtherDomainPrototype.Signature = STRUCTURE_SIGNATURE_ANNOUNCE_ENTRY;
  224. OtherDomainPrototype.Size = sizeof(OtherDomainPrototype) -
  225. sizeof(OtherDomainPrototype.ServerComment) +
  226. Transport->DomainInfo->DomUnicodeComputerName.Length + sizeof(WCHAR);
  227. RtlCopyMemory(OtherDomainPrototype.ServerName, TransportName->PagedTransportName->Name->Name.Buffer, TransportName->PagedTransportName->Name->Name.Length);
  228. OtherDomainPrototype.ServerName[TransportName->PagedTransportName->Name->Name.Length / sizeof(WCHAR)] = UNICODE_NULL;
  229. RtlCopyMemory(OtherDomainPrototype.ServerComment, Transport->DomainInfo->DomUnicodeComputerName.Buffer, Transport->DomainInfo->DomUnicodeComputerName.Length);
  230. OtherDomainPrototype.ServerComment[Transport->DomainInfo->DomUnicodeComputerName.Length / sizeof(WCHAR)] = UNICODE_NULL;
  231. OtherDomainPrototype.ServerType = SV_TYPE_DOMAIN_ENUM;
  232. OtherDomainPrototype.ServerVersionMajor = 2;
  233. OtherDomainPrototype.ServerVersionMinor = 0;
  234. OtherDomainPrototype.ServerPeriodicity = 0xffff;
  235. OtherDomainPrototype.ExpirationTime = 0xffffffff;
  236. OtherDomainPrototype.SerialId = 0;
  237. OtherDomainPrototype.Name = TransportName->PagedTransportName->Name;
  238. //
  239. // Make sure that no-one else is messing with the domain list.
  240. //
  241. LOCK_ANNOUNCE_DATABASE(Transport);
  242. Announcement = RtlInsertElementGenericTable(&PagedTransport->DomainTable,
  243. &OtherDomainPrototype, OtherDomainPrototype.Size, &NewElement);
  244. if (Announcement != NULL && NewElement ) {
  245. // Indicate the name is referenced by the announce entry we just inserted.
  246. BowserReferenceName( OtherDomainPrototype.Name );
  247. }
  248. UNLOCK_ANNOUNCE_DATABASE(Transport);
  249. }
  250. return(STATUS_SUCCESS);
  251. }
  252. VOID
  253. BowserNewMaster(
  254. IN PTRANSPORT Transport,
  255. IN PUCHAR MasterName
  256. )
  257. /*++
  258. Routine Description:
  259. Flag that a machine is the new master browser server.
  260. This routine is called to register a new master browser server.
  261. Arguments:
  262. IN PTRANSPORT Transport - The transport for the net we're on.
  263. IN PUCHAR MasterName - The name of the new master browser server.
  264. Return Value
  265. None.
  266. --*/
  267. {
  268. PIRP Irp = NULL;
  269. WCHAR MasterNameBuffer[LM20_CNLEN+1];
  270. UNICODE_STRING UMasterName;
  271. OEM_STRING OMasterName;
  272. NTSTATUS Status;
  273. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  274. PAGED_CODE();
  275. UMasterName.Buffer = MasterNameBuffer;
  276. UMasterName.MaximumLength = (LM20_CNLEN+1)*sizeof(WCHAR);
  277. RtlInitAnsiString(&OMasterName, MasterName);
  278. Status = RtlOemStringToUnicodeString(&UMasterName, &OMasterName, FALSE);
  279. if (!NT_SUCCESS(Status)) {
  280. BowserLogIllegalName( Status, OMasterName.Buffer, OMasterName.Length );
  281. return;
  282. }
  283. LOCK_TRANSPORT(Transport);
  284. try {
  285. //
  286. // There's a new master, we can stop our election timers.
  287. //
  288. PagedTransport->ElectionCount = 0;
  289. Transport->ElectionState = Idle;
  290. BowserStopTimer(&Transport->ElectionTimer);
  291. //
  292. // Check to see if we are the winner of the election. If we are
  293. // we want to complete any BecomeMaster requests that are outstanding.
  294. //
  295. if (RtlEqualUnicodeString(&UMasterName, &Transport->DomainInfo->DomUnicodeComputerName, TRUE)) {
  296. //
  297. // We're the new master for this domain. Complete any BecomeMaster
  298. // requests.
  299. //
  300. Irp = BowserDequeueQueuedIrp(&Transport->BecomeMasterQueue);
  301. if (Irp != NULL) {
  302. //
  303. // Don't copy anything into the users buffer.
  304. //
  305. Irp->IoStatus.Information = 0;
  306. BowserCompleteRequest(Irp, STATUS_SUCCESS);
  307. } else {
  308. //
  309. // Go deaf to elections until we can become a master.
  310. //
  311. Transport->ElectionState = DeafToElections;
  312. //
  313. // If we're the master browser, stop being a master browser.
  314. //
  315. //
  316. if (PagedTransport->Role == MasterBrowser) {
  317. //
  318. // Delete the names that make us a master.
  319. //
  320. BowserDeleteTransportNameByName(Transport,
  321. NULL,
  322. MasterBrowser);
  323. BowserDeleteTransportNameByName(Transport,
  324. NULL,
  325. DomainAnnouncement);
  326. }
  327. dlog(DPRT_MASTER,
  328. ("%s: %ws: Unable to find a BecomeMasterIrp\n",
  329. Transport->DomainInfo->DomOemDomainName,
  330. PagedTransport->TransportName.Buffer ));
  331. }
  332. //
  333. // Complete any outstanding find master requests with the special error MORE_PROCESSING_REQUIRED.
  334. //
  335. // This will cause the browser service to promote itself.
  336. //
  337. BowserCompleteFindMasterRequests(Transport, &UMasterName, STATUS_MORE_PROCESSING_REQUIRED);
  338. } else {
  339. BowserCompleteFindMasterRequests(Transport, &UMasterName, STATUS_SUCCESS);
  340. }
  341. } finally {
  342. UNLOCK_TRANSPORT(Transport);
  343. }
  344. }
  345. VOID
  346. BowserCompleteFindMasterRequests(
  347. IN PTRANSPORT Transport,
  348. IN PUNICODE_STRING MasterName,
  349. IN NTSTATUS Status
  350. )
  351. {
  352. PIO_STACK_LOCATION IrpSp;
  353. PIRP Irp = NULL;
  354. BOOLEAN MasterNameChanged;
  355. WCHAR MasterNameBuffer[CNLEN+1];
  356. UNICODE_STRING MasterNameCopy;
  357. NTSTATUS UcaseStatus;
  358. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  359. PAGED_CODE();
  360. MasterNameCopy.Buffer = MasterNameBuffer;
  361. MasterNameCopy.MaximumLength = sizeof(MasterNameBuffer);
  362. UcaseStatus = RtlUpcaseUnicodeString(&MasterNameCopy, MasterName, FALSE);
  363. if (!NT_SUCCESS(UcaseStatus)) {
  364. BowserLogIllegalName( UcaseStatus, MasterName->Buffer, MasterName->Length );
  365. return;
  366. }
  367. LOCK_TRANSPORT(Transport);
  368. MasterNameChanged = !RtlEqualUnicodeString(&MasterNameCopy, &PagedTransport->MasterName, FALSE);
  369. if (MasterNameChanged) {
  370. //
  371. // If the master name changed, update the masters name in
  372. // the transport structure.
  373. //
  374. RtlCopyUnicodeString(&PagedTransport->MasterName, &MasterNameCopy);
  375. }
  376. UNLOCK_TRANSPORT(Transport);
  377. do {
  378. //
  379. // Complete any the find master requests outstanding against this
  380. // workstation.
  381. //
  382. Irp = BowserDequeueQueuedIrp(&Transport->FindMasterQueue);
  383. if (MasterNameChanged &&
  384. (Irp == NULL)) {
  385. Irp = BowserDequeueQueuedIrp(&Transport->WaitForNewMasterNameQueue);
  386. }
  387. if (Irp != NULL) {
  388. PLMDR_REQUEST_PACKET RequestPacket = Irp->AssociatedIrp.SystemBuffer;
  389. if (NT_SUCCESS(Status)) {
  390. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  391. if (MasterName->Length > (USHORT)(IrpSp->Parameters.DeviceIoControl.OutputBufferLength-
  392. (FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.GetMasterName.Name))+3*sizeof(WCHAR)) ) {
  393. Status = STATUS_BUFFER_TOO_SMALL;
  394. } else {
  395. RequestPacket->Parameters.GetMasterName.Name[0] = L'\\';
  396. RequestPacket->Parameters.GetMasterName.Name[1] = L'\\';
  397. RtlCopyMemory(&RequestPacket->Parameters.GetMasterName.Name[2], MasterName->Buffer, MasterName->Length);
  398. RequestPacket->Parameters.GetMasterName.Name[2+(MasterName->Length/sizeof(WCHAR))] = UNICODE_NULL;
  399. }
  400. dlog(DPRT_MASTER,
  401. ("%s: %ws: Completing a find master request with new master %ws\n",
  402. Transport->DomainInfo->DomOemDomainName,
  403. PagedTransport->TransportName.Buffer,
  404. RequestPacket->Parameters.GetMasterName.Name));
  405. RequestPacket->Parameters.GetMasterName.MasterNameLength = MasterName->Length+2*sizeof(WCHAR);
  406. Irp->IoStatus.Information = FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.GetMasterName.Name)+MasterName->Length+3*sizeof(WCHAR);
  407. }
  408. BowserCompleteRequest(Irp, Status);
  409. }
  410. } while ( Irp != NULL );
  411. }
  412. DATAGRAM_HANDLER(BowserMasterAnnouncement)
  413. {
  414. PUCHAR MasterName = ((PMASTER_ANNOUNCEMENT_1)Buffer)->MasterName;
  415. ULONG i;
  416. //
  417. // We need to make sure that the incoming packet contains a properly
  418. // terminated ASCII string.
  419. //
  420. for (i = 0; i < BytesAvailable; i++) {
  421. if (MasterName[i] == '\0') {
  422. break;
  423. }
  424. }
  425. if (i == BytesAvailable) {
  426. return(STATUS_REQUEST_NOT_ACCEPTED);
  427. }
  428. return BowserPostDatagramToWorkerThread(
  429. TransportName,
  430. Buffer,
  431. BytesAvailable,
  432. BytesTaken,
  433. SourceAddress,
  434. SourceAddressLength,
  435. SourceName,
  436. SourceNameLength,
  437. BowserMasterAnnouncementWorker,
  438. NonPagedPool,
  439. DelayedWorkQueue,
  440. ReceiveFlags,
  441. FALSE // No response will be sent.
  442. );
  443. }
  444. VOID
  445. BowserMasterAnnouncementWorker(
  446. IN PVOID Ctx
  447. )
  448. {
  449. PPOST_DATAGRAM_CONTEXT Context = Ctx;
  450. PTRANSPORT Transport = Context->TransportName->Transport;
  451. PCHAR LocalMasterName = (PCHAR)((PMASTER_ANNOUNCEMENT_1)Context->Buffer)->MasterName;
  452. size_t cbLocalMasterName;
  453. PIRP Irp;
  454. NTSTATUS Status;
  455. PAGED_CODE();
  456. Irp = BowserDequeueQueuedIrp(&Transport->WaitForMasterAnnounceQueue);
  457. if (Irp != NULL) {
  458. PIO_STACK_LOCATION IrpSp;
  459. PLMDR_REQUEST_PACKET RequestPacket = Irp->AssociatedIrp.SystemBuffer;
  460. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  461. cbLocalMasterName = strlen(LocalMasterName);
  462. if (0 == cbLocalMasterName) {
  463. // ensure we didn't get an invalid NULL announcement
  464. // see bug 440813
  465. // The request completed successfully, but the data is trash.
  466. // - we won't fail the IRP (another one is posted immediately
  467. // upon completion anyway), but not process further this one.
  468. Irp->IoStatus.Information = 0;
  469. Status = STATUS_SUCCESS;
  470. }
  471. else if ((cbLocalMasterName + 1) * sizeof(WCHAR) >
  472. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength -
  473. FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.WaitForMasterAnnouncement.Name))) {
  474. //
  475. // ensure there's enough buffer space to return name. If not,
  476. // return error.
  477. //
  478. Irp->IoStatus.Information = 0;
  479. Status = STATUS_BUFFER_TOO_SMALL;
  480. } else {
  481. //
  482. // All is well. Fill info.
  483. //
  484. OEM_STRING MasterName;
  485. UNICODE_STRING MasterNameU;
  486. RtlInitString(&MasterName, LocalMasterName);
  487. Status = RtlOemStringToUnicodeString(&MasterNameU, &MasterName, TRUE);
  488. if ( NT_SUCCESS(Status) ) {
  489. RequestPacket->Parameters.WaitForMasterAnnouncement.MasterNameLength = MasterNameU.Length;
  490. RtlCopyMemory(RequestPacket->Parameters.WaitForMasterAnnouncement.Name, MasterNameU.Buffer, MasterNameU.Length);
  491. RequestPacket->Parameters.WaitForMasterAnnouncement.Name[MasterNameU.Length/sizeof(WCHAR)] = UNICODE_NULL;
  492. Irp->IoStatus.Information = FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.WaitForMasterAnnouncement.Name)+MasterNameU.Length + sizeof(UNICODE_NULL);
  493. RtlFreeUnicodeString(&MasterNameU);
  494. Status = STATUS_SUCCESS;
  495. }
  496. }
  497. BowserCompleteRequest(Irp, Status);
  498. }
  499. BowserDereferenceTransportName(Context->TransportName);
  500. BowserDereferenceTransport(Transport);
  501. InterlockedDecrement( &BowserPostedDatagramCount );
  502. FREE_POOL(Context);
  503. }
  504. NTSTATUS
  505. TimeoutFindMasterRequests(
  506. IN PTRANSPORT Transport,
  507. IN PVOID Context
  508. )
  509. {
  510. PAGED_CODE();
  511. //
  512. // Perform an unprotected early out to prevent our calling into
  513. // discardable code section during the scavenger. Since the discardable
  514. // code section is <4K, touching the code would have the effect of
  515. // bringing the entire page into memory, which is a waste - since the
  516. // scavenger runs every 30 seconds, this would cause the discardable
  517. // code section to be a part of the browsers working set.
  518. //
  519. if (BowserIsIrpQueueEmpty(&Transport->FindMasterQueue)) {
  520. return STATUS_SUCCESS;
  521. }
  522. BowserTimeoutQueuedIrp(&Transport->FindMasterQueue, BowserFindMasterTimeout);
  523. return STATUS_SUCCESS;
  524. }
  525. VOID
  526. BowserTimeoutFindMasterRequests(
  527. VOID
  528. )
  529. {
  530. PAGED_CODE();
  531. BowserForEachTransport(TimeoutFindMasterRequests, NULL);
  532. }