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.

1228 lines
27 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. bowname.c
  5. Abstract:
  6. This module implements all of the routines to manage the NT bowser name
  7. manipulation routines
  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. typedef struct _ENUM_NAMES_CONTEXT {
  17. PDGRECEIVE_NAMES OutputBuffer;
  18. PDGRECEIVE_NAMES NextOutputBuffer;
  19. PVOID OutputBufferEnd;
  20. ULONG OutputBufferSize;
  21. ULONG EntriesRead;
  22. ULONG TotalEntries;
  23. ULONG TotalBytesNeeded;
  24. ULONG_PTR OutputBufferDisplacement;
  25. } ENUM_NAMES_CONTEXT, *PENUM_NAMES_CONTEXT;
  26. typedef struct _ADD_TRANSPORT_NAME_CONTEXT {
  27. LIST_ENTRY ListHead;
  28. UNICODE_STRING NameToAdd;
  29. DGRECEIVER_NAME_TYPE NameType;
  30. } ADD_TRANSPORT_NAME_CONTEXT, *PADD_TRANSPORT_NAME_CONTEXT;
  31. typedef struct _ADD_TRANSPORT_NAME_STRUCTURE {
  32. LIST_ENTRY Link;
  33. HANDLE ThreadHandle;
  34. PTRANSPORT Transport;
  35. UNICODE_STRING NameToAdd;
  36. DGRECEIVER_NAME_TYPE NameType;
  37. NTSTATUS Status;
  38. } ADD_TRANSPORT_NAME_STRUCTURE, *PADD_TRANSPORT_NAME_STRUCTURE;
  39. NTSTATUS
  40. AddTransportName(
  41. IN PTRANSPORT Transport,
  42. IN PVOID Context
  43. );
  44. VOID
  45. AsyncCreateTransportName(
  46. IN PVOID Ctx
  47. );
  48. NTSTATUS
  49. WaitForAddNameOperation(
  50. IN PADD_TRANSPORT_NAME_CONTEXT Context
  51. );
  52. NTSTATUS
  53. BowserDeleteNamesInDomain(
  54. IN PDOMAIN_INFO DomainInfo,
  55. IN PUNICODE_STRING Name OPTIONAL,
  56. IN DGRECEIVER_NAME_TYPE NameType
  57. );
  58. NTSTATUS
  59. BowserDeleteNamesWorker(
  60. IN PTRANSPORT Transport,
  61. IN OUT PVOID Ctx
  62. );
  63. NTSTATUS
  64. EnumerateNamesTransportWorker(
  65. IN PTRANSPORT Transport,
  66. IN OUT PVOID Ctx
  67. );
  68. NTSTATUS
  69. EnumerateNamesTransportNameWorker(
  70. IN PTRANSPORT_NAME TransportName,
  71. IN OUT PVOID Ctx
  72. );
  73. #ifdef ALLOC_PRAGMA
  74. #pragma alloc_text(PAGE, BowserAllocateName)
  75. #pragma alloc_text(PAGE, BowserAddDefaultNames)
  76. #pragma alloc_text(PAGE, BowserDeleteDefaultDomainNames)
  77. #pragma alloc_text(PAGE, AddTransportName)
  78. #pragma alloc_text(PAGE, AsyncCreateTransportName)
  79. #pragma alloc_text(PAGE, WaitForAddNameOperation)
  80. #pragma alloc_text(PAGE, BowserDeleteNameByName)
  81. #pragma alloc_text(PAGE, BowserDereferenceName)
  82. #pragma alloc_text(PAGE, BowserReferenceName)
  83. #pragma alloc_text(PAGE, BowserForEachName)
  84. #pragma alloc_text(PAGE, BowserDeleteName)
  85. #pragma alloc_text(PAGE, BowserDeleteNamesInDomain)
  86. #pragma alloc_text(PAGE, BowserDeleteNamesWorker)
  87. #pragma alloc_text(PAGE, BowserFindName)
  88. #pragma alloc_text(PAGE, BowserEnumerateNamesInDomain)
  89. #pragma alloc_text(PAGE, EnumerateNamesTransportWorker)
  90. #pragma alloc_text(PAGE, EnumerateNamesTransportNameWorker)
  91. #pragma alloc_text(INIT, BowserpInitializeNames)
  92. #pragma alloc_text(PAGE, BowserpUninitializeNames)
  93. #endif
  94. NTSTATUS
  95. BowserAllocateName(
  96. IN PUNICODE_STRING NameToAdd,
  97. IN DGRECEIVER_NAME_TYPE NameType,
  98. IN PTRANSPORT Transport OPTIONAL,
  99. IN PDOMAIN_INFO DomainInfo OPTIONAL
  100. )
  101. /*++
  102. Routine Description:
  103. This routine creates a browser name
  104. Arguments:
  105. NameToAdd - Netbios name to add to one or more transports
  106. NameType - Type of the added name
  107. Transport - if specified, the name is added to this transport.
  108. If not specified, the name is added to all transports in the domain.
  109. DomainInfo - Specifies the emulated domain to add the name to.
  110. If not specified, the name is added to the specified transport.
  111. Return Value:
  112. NTSTATUS - Status of resulting operation.
  113. --*/
  114. {
  115. PBOWSER_NAME NewName;
  116. NTSTATUS Status = STATUS_SUCCESS;
  117. OEM_STRING OemName;
  118. BOOLEAN ResourceLocked = FALSE;
  119. PAGED_CODE();
  120. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  121. ResourceLocked = TRUE;
  122. //
  123. // If the name doesn't already exist,
  124. // allocate one and fill it in.
  125. //
  126. NewName = BowserFindName(NameToAdd, NameType);
  127. if (NewName == NULL) {
  128. NewName = ALLOCATE_POOL( PagedPool,
  129. sizeof(BOWSER_NAME) +
  130. NameToAdd->Length+sizeof(WCHAR),
  131. POOL_BOWSERNAME);
  132. if (NewName == NULL) {
  133. Status = STATUS_INSUFFICIENT_RESOURCES;
  134. goto ReturnStatus;
  135. }
  136. NewName->Signature = STRUCTURE_SIGNATURE_BOWSER_NAME;
  137. NewName->Size = sizeof(BOWSER_NAME);
  138. // This reference matches the one FindName would have done
  139. // above had it succeeded.
  140. NewName->ReferenceCount = 1;
  141. InitializeListHead(&NewName->NameChain);
  142. NewName->NameType = NameType;
  143. InsertHeadList(&BowserNameHead, &NewName->GlobalNext);
  144. NewName->Name.Buffer = (LPWSTR)(NewName+1);
  145. NewName->Name.MaximumLength = NameToAdd->Length + sizeof(WCHAR);
  146. RtlCopyUnicodeString(&NewName->Name, NameToAdd);
  147. //
  148. // Null terminate the name in the buffer just in case.
  149. //
  150. NewName->Name.Buffer[NewName->Name.Length/sizeof(WCHAR)] = L'\0';
  151. //
  152. // Uppercase the name.
  153. //
  154. Status = RtlUpcaseUnicodeStringToOemString(&OemName, &NewName->Name, TRUE);
  155. if (!NT_SUCCESS(Status)) {
  156. goto ReturnStatus;
  157. }
  158. Status = RtlOemStringToUnicodeString(&NewName->Name, &OemName, FALSE);
  159. RtlFreeOemString(&OemName);
  160. if (!NT_SUCCESS(Status)) {
  161. goto ReturnStatus;
  162. }
  163. }
  164. if (ARGUMENT_PRESENT(Transport)) {
  165. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  166. ResourceLocked = FALSE;
  167. Status = BowserCreateTransportName(Transport, NewName);
  168. } else {
  169. ADD_TRANSPORT_NAME_CONTEXT context;
  170. context.NameToAdd = *NameToAdd;
  171. context.NameType = NameType;
  172. InitializeListHead(&context.ListHead);
  173. Status = BowserForEachTransportInDomain( DomainInfo, AddTransportName, &context);
  174. //
  175. // Since we will reference this name and transport while we
  176. // are processing the list, we want to release the database resource
  177. // now.
  178. //
  179. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  180. ResourceLocked = FALSE;
  181. if (!NT_SUCCESS(Status)) {
  182. WaitForAddNameOperation(&context);
  183. goto ReturnStatus;
  184. }
  185. Status = WaitForAddNameOperation(&context);
  186. }
  187. ReturnStatus:
  188. if (ResourceLocked) {
  189. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  190. }
  191. if (!NT_SUCCESS(Status)) {
  192. //
  193. // Delete this transport.
  194. //
  195. if (NewName != NULL) {
  196. if (!ARGUMENT_PRESENT(Transport)) {
  197. //
  198. // Clean out any names that we may have added already.
  199. //
  200. BowserDeleteNamesInDomain( DomainInfo, &NewName->Name, NewName->NameType );
  201. }
  202. }
  203. }
  204. if (NewName != NULL) {
  205. BowserDereferenceName(NewName);
  206. }
  207. return Status;
  208. }
  209. NTSTATUS
  210. BowserAddDefaultNames(
  211. IN PTRANSPORT Transport,
  212. IN PVOID Context
  213. )
  214. /*++
  215. Routine Description:
  216. Add the default names for a newly created transport.
  217. Add the ComputerName<00>, Domain<00>, Domain<1C>, and other domains.
  218. All of the newly added names are added in parallel to increase performance.
  219. Arguments:
  220. Transport - The names are added to this transport.
  221. Context - If specified, a pointer to the UNICODE_STRING structure specifying
  222. the domain name to register.
  223. Return Value:
  224. NTSTATUS - Status of resulting operation.
  225. --*/
  226. {
  227. NTSTATUS Status;
  228. NTSTATUS TempStatus;
  229. PLIST_ENTRY NameEntry;
  230. ADD_TRANSPORT_NAME_CONTEXT AddNameContext;
  231. PDOMAIN_INFO DomainInfo = Transport->DomainInfo;
  232. UNICODE_STRING EmulatedComputerName;
  233. UNICODE_STRING EmulatedDomainName;
  234. PAGED_CODE();
  235. //
  236. // Build the domain name and computer name to add.
  237. //
  238. EmulatedComputerName = DomainInfo->DomUnicodeComputerName;
  239. if ( Context == NULL ) {
  240. EmulatedDomainName = DomainInfo->DomUnicodeDomainName;
  241. } else {
  242. EmulatedDomainName = *((PUNICODE_STRING)Context);
  243. }
  244. //
  245. // Initialize the queue of threads
  246. //
  247. InitializeListHead(&AddNameContext.ListHead);
  248. //
  249. // Add the computer<00> name
  250. //
  251. AddNameContext.NameToAdd = EmulatedComputerName;
  252. AddNameContext.NameType = ComputerName;
  253. Status = AddTransportName( Transport, &AddNameContext);
  254. if ( !NT_SUCCESS(Status) ) {
  255. goto ReturnStatus;
  256. }
  257. //
  258. // Add the domain<00> name
  259. //
  260. AddNameContext.NameToAdd = EmulatedDomainName;
  261. AddNameContext.NameType = PrimaryDomain;
  262. Status = AddTransportName( Transport, &AddNameContext);
  263. if ( !NT_SUCCESS(Status) ) {
  264. goto ReturnStatus;
  265. }
  266. //
  267. // Add the domain<1C> name
  268. //
  269. if (BowserData.IsLanmanNt) {
  270. AddNameContext.NameToAdd = EmulatedDomainName;
  271. AddNameContext.NameType = DomainName;
  272. Status = AddTransportName( Transport, &AddNameContext);
  273. if ( !NT_SUCCESS(Status) ) {
  274. goto ReturnStatus;
  275. }
  276. }
  277. //
  278. // Add each of the OtherDomain<00> names
  279. //
  280. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  281. for (NameEntry = BowserNameHead.Flink;
  282. NameEntry != &BowserNameHead ;
  283. NameEntry = NameEntry->Flink) {
  284. PBOWSER_NAME Name = CONTAINING_RECORD(NameEntry, BOWSER_NAME, GlobalNext);
  285. //
  286. // Only add the OtherDomains
  287. //
  288. if ( Name->NameType == OtherDomain ) {
  289. AddNameContext.NameToAdd = Name->Name;
  290. AddNameContext.NameType = OtherDomain;
  291. Status = AddTransportName( Transport, &AddNameContext);
  292. if ( !NT_SUCCESS(Status) ) {
  293. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  294. goto ReturnStatus;
  295. }
  296. }
  297. }
  298. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  299. Status = STATUS_SUCCESS;
  300. ReturnStatus:
  301. //
  302. // Wait for any started threads to complete.
  303. //
  304. TempStatus = WaitForAddNameOperation(&AddNameContext);
  305. if ( NT_SUCCESS(Status) ) {
  306. Status = TempStatus;
  307. }
  308. return Status;
  309. }
  310. NTSTATUS
  311. BowserDeleteDefaultDomainNames(
  312. IN PTRANSPORT Transport,
  313. IN PVOID Context
  314. )
  315. /*++
  316. Routine Description:
  317. Worker routine to re-add all of the default names for the transport.
  318. This routine will be called when the domain is renamed. All of the previous
  319. default names should be removed and the new default names should be added.
  320. Arguments:
  321. Transport - Transport to add the names on.
  322. Context - Pointer to UNICODE_STRING identifying the domain name to remove
  323. Return Value:
  324. NTSTATUS - Status of resulting operation.
  325. --*/
  326. {
  327. NTSTATUS Status;
  328. PUNICODE_STRING NameToRemove = (PUNICODE_STRING) Context;
  329. PAGED_CODE();
  330. //
  331. // This is a cleanup operation. Don't fail if we can't remove the name.
  332. //
  333. (VOID) BowserDeleteTransportNameByName( Transport, NameToRemove, PrimaryDomain );
  334. (VOID) BowserDeleteTransportNameByName( Transport, NameToRemove, DomainName );
  335. return STATUS_SUCCESS;
  336. }
  337. NTSTATUS
  338. WaitForAddNameOperation(
  339. IN PADD_TRANSPORT_NAME_CONTEXT Context
  340. )
  341. {
  342. NTSTATUS status = STATUS_SUCCESS;
  343. NTSTATUS LocalStatus;
  344. PAGED_CODE();
  345. while (!IsListEmpty(&Context->ListHead)) {
  346. PLIST_ENTRY Entry;
  347. PADD_TRANSPORT_NAME_STRUCTURE addNameStruct;
  348. Entry = RemoveHeadList(&Context->ListHead);
  349. addNameStruct = CONTAINING_RECORD(Entry, ADD_TRANSPORT_NAME_STRUCTURE, Link);
  350. //
  351. // We need to call the Nt version of this API, since we only have
  352. // the handle to the thread.
  353. //
  354. // Also note that we call the Nt version of the API. This works
  355. // because we are running in the FSP, and thus PreviousMode is Kernel.
  356. //
  357. LocalStatus = ZwWaitForSingleObject(addNameStruct->ThreadHandle,
  358. FALSE,
  359. NULL);
  360. ASSERT (NT_SUCCESS(LocalStatus));
  361. LocalStatus = ZwClose(addNameStruct->ThreadHandle);
  362. ASSERT (NT_SUCCESS(LocalStatus));
  363. //
  364. // We've waited for this name to be added, now check its status.
  365. //
  366. if (!NT_SUCCESS(addNameStruct->Status)) {
  367. status = addNameStruct->Status;
  368. }
  369. FREE_POOL(addNameStruct);
  370. }
  371. //
  372. // If we were able to successfully add all the names, then Status will
  373. // still be STATUS_SUCCESS, however if any of the addnames failed,
  374. // Status will be set to the status of whichever one of them failed.
  375. //
  376. return status;
  377. }
  378. NTSTATUS
  379. AddTransportName(
  380. IN PTRANSPORT Transport,
  381. IN PVOID Ctx
  382. )
  383. {
  384. PADD_TRANSPORT_NAME_CONTEXT context = Ctx;
  385. PADD_TRANSPORT_NAME_STRUCTURE addNameStructure;
  386. NTSTATUS status;
  387. PAGED_CODE();
  388. addNameStructure = ALLOCATE_POOL(PagedPool, sizeof(ADD_TRANSPORT_NAME_STRUCTURE), POOL_ADDNAME_STRUCT);
  389. if (addNameStructure == NULL) {
  390. return STATUS_INSUFFICIENT_RESOURCES;
  391. }
  392. addNameStructure->ThreadHandle = NULL;
  393. addNameStructure->Transport = Transport;
  394. if ( Transport )
  395. {
  396. // reference transport so it doesn't get deleted under us.
  397. BowserReferenceTransport(Transport);
  398. }
  399. addNameStructure->NameToAdd = context->NameToAdd;
  400. addNameStructure->NameType = context->NameType;
  401. status = PsCreateSystemThread(&addNameStructure->ThreadHandle,
  402. THREAD_ALL_ACCESS,
  403. NULL,
  404. NULL,
  405. NULL,
  406. AsyncCreateTransportName,
  407. addNameStructure);
  408. if (!NT_SUCCESS(status)) {
  409. if ( Transport )
  410. {
  411. // dereference transport upon failure
  412. BowserDereferenceTransport(Transport);
  413. }
  414. FREE_POOL(addNameStructure);
  415. return status;
  416. }
  417. InsertTailList(&context->ListHead, &addNameStructure->Link);
  418. return STATUS_SUCCESS;
  419. }
  420. VOID
  421. AsyncCreateTransportName(
  422. IN PVOID Ctx
  423. )
  424. {
  425. PADD_TRANSPORT_NAME_STRUCTURE context = Ctx;
  426. PAGED_CODE();
  427. context->Status = BowserAllocateName(
  428. &context->NameToAdd,
  429. context->NameType,
  430. context->Transport,
  431. NULL );
  432. if ( context->Transport )
  433. {
  434. // referenced in calling AddTransportName()
  435. BowserDereferenceTransport(context->Transport);
  436. }
  437. //
  438. // We're all done with this thread, terminate now.
  439. //
  440. PsTerminateSystemThread(STATUS_SUCCESS);
  441. }
  442. NTSTATUS
  443. BowserDeleteNameByName(
  444. IN PDOMAIN_INFO DomainInfo,
  445. IN PUNICODE_STRING NameToDelete,
  446. IN DGRECEIVER_NAME_TYPE NameType
  447. )
  448. /*++
  449. Routine Description:
  450. This routine deletes a browser name
  451. Arguments:
  452. IN PBOWSER_NAME Name - Supplies a transport structure describing the
  453. transport address object to be created.
  454. Return Value:
  455. NTSTATUS - Status of resulting operation.
  456. --*/
  457. {
  458. PBOWSER_NAME Name = NULL;
  459. NTSTATUS Status;
  460. PAGED_CODE();
  461. // DbgBreakPoint();
  462. //
  463. // If the caller is deleting a specific name,
  464. // ensure it exists.
  465. //
  466. if ( NameToDelete != NULL && NameToDelete->Length != 0 ) {
  467. Name = BowserFindName(NameToDelete, NameType);
  468. if (Name == NULL) {
  469. return STATUS_OBJECT_NAME_NOT_FOUND;
  470. }
  471. }
  472. //
  473. // If there are still any names associated with this name,
  474. // delete them.
  475. //
  476. Status = BowserDeleteNamesInDomain( DomainInfo, NameToDelete, NameType );
  477. //
  478. // Remove the reference from the FindName.
  479. //
  480. if ( Name != NULL ) {
  481. BowserDereferenceName(Name);
  482. }
  483. return(Status);
  484. }
  485. VOID
  486. BowserDereferenceName (
  487. IN PBOWSER_NAME Name
  488. )
  489. {
  490. PAGED_CODE();
  491. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  492. Name->ReferenceCount -= 1;
  493. if (Name->ReferenceCount == 0) {
  494. BowserDeleteName(Name);
  495. }
  496. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  497. }
  498. VOID
  499. BowserReferenceName (
  500. IN PBOWSER_NAME Name
  501. )
  502. {
  503. PAGED_CODE();
  504. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  505. Name->ReferenceCount += 1;
  506. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  507. }
  508. NTSTATUS
  509. BowserForEachName (
  510. IN PNAME_ENUM_ROUTINE Routine,
  511. IN OUT PVOID Context
  512. )
  513. /*++
  514. Routine Description:
  515. This routine will enumerate the names and call back the enum
  516. routine provided with each names.
  517. Arguments:
  518. Return Value:
  519. NTSTATUS - Final status of request.
  520. --*/
  521. {
  522. PLIST_ENTRY NameEntry, NextEntry;
  523. PBOWSER_NAME Name = NULL;
  524. NTSTATUS Status = STATUS_SUCCESS;
  525. PAGED_CODE();
  526. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  527. for (NameEntry = BowserNameHead.Flink ;
  528. NameEntry != &BowserNameHead ;
  529. NameEntry = NextEntry) {
  530. Name = CONTAINING_RECORD(NameEntry, BOWSER_NAME, GlobalNext);
  531. BowserReferenceName(Name);
  532. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  533. Status = (Routine)(Name, Context);
  534. if (!NT_SUCCESS(Status)) {
  535. BowserDereferenceName(Name);
  536. return Status;
  537. }
  538. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  539. NextEntry = Name->GlobalNext.Flink;
  540. BowserDereferenceName(Name);
  541. }
  542. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  543. return Status;
  544. }
  545. NTSTATUS
  546. BowserDeleteName(
  547. IN PBOWSER_NAME Name
  548. )
  549. /*++
  550. Routine Description:
  551. This routine deletes a browser name
  552. Arguments:
  553. IN PBOWSER_NAME Name - Supplies a transport structure describing the
  554. transport address object to be created.
  555. Return Value:
  556. NTSTATUS - Status of resulting operation.
  557. --*/
  558. {
  559. PAGED_CODE();
  560. RemoveEntryList(&Name->GlobalNext);
  561. FREE_POOL(Name);
  562. return STATUS_SUCCESS;
  563. }
  564. NTSTATUS
  565. BowserDeleteNamesInDomain(
  566. IN PDOMAIN_INFO DomainInfo,
  567. IN PUNICODE_STRING Name OPTIONAL,
  568. IN DGRECEIVER_NAME_TYPE NameType
  569. )
  570. /*++
  571. Routine Description:
  572. This routine deletes all the transport names associated with a browser name
  573. Arguments:
  574. DomainInfo - Identifies the emulated domain to have the specified names removed.
  575. Name - Specifies the transport name to delete.
  576. If not specified, all names of the specified name type are deleted.
  577. NameType - Specifies the name type of the name.
  578. Return Value:
  579. NTSTATUS - Status of resulting operation.
  580. --*/
  581. {
  582. NTSTATUS Status;
  583. BOWSER_NAME BowserName;
  584. PAGED_CODE();
  585. BowserName.Name = *Name;
  586. BowserName.NameType = NameType;
  587. Status = BowserForEachTransportInDomain( DomainInfo, BowserDeleteNamesWorker, &BowserName );
  588. return(Status);
  589. }
  590. NTSTATUS
  591. BowserDeleteNamesWorker(
  592. IN PTRANSPORT Transport,
  593. IN OUT PVOID Ctx
  594. )
  595. /*++
  596. Routine Description:
  597. This routine is the worker routine for BowserDeleteNamesInDomain.
  598. Delete all the specified name for the specified transport.
  599. Arguments:
  600. None.
  601. Return Value:
  602. None.
  603. --*/
  604. {
  605. NTSTATUS Status;
  606. PBOWSER_NAME Name = (PBOWSER_NAME) Ctx;
  607. // Note the caller doesn't pass a real PBOWSER_NAME.
  608. PAGED_CODE();
  609. //
  610. // Delete all the specified names for the specified transport.
  611. //
  612. Status = BowserDeleteTransportNameByName( Transport, &Name->Name, Name->NameType );
  613. return Status;
  614. }
  615. PBOWSER_NAME
  616. BowserFindName (
  617. IN PUNICODE_STRING NameToFind,
  618. IN DGRECEIVER_NAME_TYPE NameType
  619. )
  620. /*++
  621. Routine Description:
  622. This routine scans the bowser name database to find a particular bowser name
  623. Arguments:
  624. NameToFind - Supplies the name to find.
  625. NameType - Type of name to find
  626. Return Value:
  627. PBOWSER_NAME - Returns the name found.
  628. --*/
  629. {
  630. PLIST_ENTRY NameEntry;
  631. PBOWSER_NAME Name;
  632. NTSTATUS Status;
  633. OEM_STRING OemName;
  634. UNICODE_STRING UpcasedName;
  635. PAGED_CODE();
  636. //
  637. // Uppercase the name.
  638. //
  639. Status = RtlUpcaseUnicodeStringToOemString(&OemName, NameToFind, TRUE);
  640. if (!NT_SUCCESS(Status)) {
  641. return NULL;
  642. }
  643. Status = RtlOemStringToUnicodeString(&UpcasedName, &OemName, TRUE);
  644. RtlFreeOemString(&OemName);
  645. if (!NT_SUCCESS(Status)) {
  646. return NULL;
  647. }
  648. //
  649. // Loop through the list of names finding this one.
  650. //
  651. ExAcquireResourceExclusiveLite(&BowserTransportDatabaseResource, TRUE);
  652. Name = NULL;
  653. for (NameEntry = BowserNameHead.Flink ;
  654. NameEntry != &BowserNameHead ;
  655. NameEntry = NameEntry->Flink) {
  656. Name = CONTAINING_RECORD(NameEntry, BOWSER_NAME, GlobalNext);
  657. if ( Name->NameType == NameType &&
  658. RtlEqualUnicodeString( &Name->Name, &UpcasedName, FALSE ) ) {
  659. Name->ReferenceCount += 1;
  660. break;
  661. }
  662. Name = NULL;
  663. }
  664. RtlFreeUnicodeString( &UpcasedName );
  665. ExReleaseResourceLite(&BowserTransportDatabaseResource);
  666. return Name;
  667. }
  668. NTSTATUS
  669. BowserEnumerateNamesInDomain (
  670. IN PDOMAIN_INFO DomainInfo,
  671. IN PTRANSPORT Transport,
  672. OUT PVOID OutputBuffer,
  673. OUT ULONG OutputBufferLength,
  674. IN OUT PULONG EntriesRead,
  675. IN OUT PULONG TotalEntries,
  676. IN OUT PULONG TotalBytesNeeded,
  677. IN ULONG_PTR OutputBufferDisplacement
  678. )
  679. /*++
  680. Routine Description:
  681. This routine will enumerate all the names currently registered by any
  682. transport.
  683. Arguments:
  684. DomainInfo - Emulated domain the names are to be enumerated for.
  685. Transport - Transport names are registered on
  686. NULL - Any transport.
  687. OutputBuffer - Buffer to fill with name info.
  688. OutputBufferSize - Filled in with size of buffer.
  689. EntriesRead - Filled in with the # of entries returned.
  690. TotalEntries - Filled in with the total # of entries.
  691. TotalBytesNeeded - Filled in with the # of bytes needed.
  692. Return Value:
  693. None.
  694. --*/
  695. {
  696. PVOID OutputBufferEnd;
  697. NTSTATUS Status;
  698. ENUM_NAMES_CONTEXT Context;
  699. PVOID TempOutputBuffer;
  700. PAGED_CODE();
  701. TempOutputBuffer = ALLOCATE_POOL(PagedPool,OutputBufferLength,POOL_NAME_ENUM_BUFFER);
  702. if (TempOutputBuffer == NULL) {
  703. return(STATUS_INSUFFICIENT_RESOURCES);
  704. }
  705. OutputBufferEnd = (PCHAR)TempOutputBuffer+OutputBufferLength;
  706. Context.EntriesRead = 0;
  707. Context.TotalEntries = 0;
  708. Context.TotalBytesNeeded = 0;
  709. try {
  710. Context.OutputBufferSize = OutputBufferLength;
  711. Context.NextOutputBuffer = Context.OutputBuffer = (PDGRECEIVE_NAMES) TempOutputBuffer;
  712. Context.OutputBufferDisplacement = (ULONG_PTR)((PCHAR)TempOutputBuffer - ((PCHAR)OutputBuffer - OutputBufferDisplacement));
  713. Context.OutputBufferEnd = OutputBufferEnd;
  714. // DbgPrint("Enumerate Names: Buffer: %lx, BufferSize: %lx, BufferEnd: %lx\n",
  715. // TempOutputBuffer, OutputBufferLength, OutputBufferEnd);
  716. if ( Transport == NULL ) {
  717. Status = BowserForEachTransportInDomain(DomainInfo, EnumerateNamesTransportWorker, &Context);
  718. } else {
  719. Status = EnumerateNamesTransportWorker( Transport, &Context);
  720. }
  721. *EntriesRead = Context.EntriesRead;
  722. *TotalEntries = Context.TotalEntries;
  723. *TotalBytesNeeded = Context.TotalBytesNeeded;
  724. // Copy the fixed data
  725. RtlCopyMemory( OutputBuffer,
  726. TempOutputBuffer,
  727. (ULONG)(((LPBYTE)Context.NextOutputBuffer)-((LPBYTE)Context.OutputBuffer)) );
  728. // Copy the strings
  729. RtlCopyMemory( ((LPBYTE)OutputBuffer)+(ULONG)(((LPBYTE)Context.OutputBufferEnd)-((LPBYTE)Context.OutputBuffer)),
  730. Context.OutputBufferEnd,
  731. (ULONG)(((LPBYTE)OutputBufferEnd)-((LPBYTE)Context.OutputBufferEnd)) );
  732. if (*EntriesRead == *TotalEntries) {
  733. try_return(Status = STATUS_SUCCESS);
  734. } else {
  735. try_return(Status = STATUS_MORE_ENTRIES);
  736. }
  737. try_exit:NOTHING;
  738. } except (BR_EXCEPTION) {
  739. Status = GetExceptionCode();
  740. }
  741. if (TempOutputBuffer != NULL ) {
  742. FREE_POOL(TempOutputBuffer);
  743. }
  744. return Status;
  745. }
  746. NTSTATUS
  747. EnumerateNamesTransportWorker(
  748. IN PTRANSPORT Transport,
  749. IN OUT PVOID Ctx
  750. )
  751. /*++
  752. Routine Description:
  753. This routine is the worker routine for BowserEnumerateNamesInDomain.
  754. This routine is executed for each transport in the domain.
  755. It simply calls EnumerateNamesTransportNameWorker for each transport name on the
  756. transport.
  757. Arguments:
  758. Transport - Transport whose names are to be added to the context.
  759. Ctx - Cumulative list of names.
  760. Return Value:
  761. Status of the operation.
  762. --*/
  763. {
  764. NTSTATUS Status;
  765. Status = BowserForEachTransportName( Transport, EnumerateNamesTransportNameWorker, Ctx);
  766. return Status;
  767. }
  768. NTSTATUS
  769. EnumerateNamesTransportNameWorker(
  770. IN PTRANSPORT_NAME TransportName,
  771. IN OUT PVOID Ctx
  772. )
  773. /*++
  774. Routine Description:
  775. This routine is the worker routine for EnumerateNamesTransportWorker.
  776. It is called for each of the transport name for each transport in the domain.
  777. It returns that name (supressing duplicates) in the buffer described in the context.
  778. Arguments:
  779. TransportName - Transport name to be added to the context.
  780. Ctx - Cumulative list of names.
  781. Return Value:
  782. Status of the operation.
  783. --*/
  784. {
  785. PENUM_NAMES_CONTEXT Context = Ctx;
  786. PBOWSER_NAME Name = TransportName->PagedTransportName->Name;
  787. ULONG i;
  788. PAGED_CODE();
  789. //
  790. // Skip Nameless transports
  791. //
  792. if ( Name->Name.Length == 0) {
  793. // Adding an empty name to the list can result w/ AV
  794. // on client end (see bug 377078).
  795. return ( STATUS_SUCCESS );
  796. }
  797. //
  798. // Check to see if this name has been packed yet.
  799. //
  800. //
  801. for ( i=0; i<Context->EntriesRead; i++ ) {
  802. if ( Name->NameType == Context->OutputBuffer[i].Type ) {
  803. UNICODE_STRING RelocatedString = Context->OutputBuffer[i].DGReceiverName;
  804. RelocatedString.Buffer = (LPWSTR)
  805. ((LPBYTE)RelocatedString.Buffer + Context->OutputBufferDisplacement);
  806. if ( RtlEqualUnicodeString( &RelocatedString, &Name->Name, FALSE ) ) {
  807. return(STATUS_SUCCESS);
  808. }
  809. }
  810. }
  811. //
  812. // This names hasn;t been packed yet,
  813. // pack it.
  814. //
  815. Context->TotalEntries += 1;
  816. if ((ULONG_PTR)Context->OutputBufferEnd - (ULONG_PTR)Context->NextOutputBuffer >
  817. sizeof(DGRECEIVE_NAMES)+Name->Name.Length) {
  818. PDGRECEIVE_NAMES NameEntry = Context->NextOutputBuffer;
  819. Context->NextOutputBuffer += 1;
  820. Context->EntriesRead += 1;
  821. NameEntry->DGReceiverName = Name->Name;
  822. BowserPackNtString( &NameEntry->DGReceiverName,
  823. Context->OutputBufferDisplacement,
  824. (PCHAR)Context->NextOutputBuffer,
  825. (PCHAR *)&Context->OutputBufferEnd
  826. );
  827. NameEntry->Type = Name->NameType;
  828. }
  829. Context->TotalBytesNeeded += sizeof(DGRECEIVE_NAMES)+Name->Name.Length;
  830. return(STATUS_SUCCESS);
  831. }
  832. NTSTATUS
  833. BowserpInitializeNames(
  834. VOID
  835. )
  836. {
  837. PAGED_CODE();
  838. InitializeListHead(&BowserNameHead);
  839. return STATUS_SUCCESS;
  840. }
  841. VOID
  842. BowserpUninitializeNames(
  843. VOID
  844. )
  845. {
  846. PAGED_CODE();
  847. ASSERT (IsListEmpty(&BowserNameHead));
  848. return;
  849. }