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.

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