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.

3090 lines
90 KiB

  1. /*--
  2. Copyright (c) 1987-1996 Microsoft Corporation
  3. Module Name:
  4. mailslot.c
  5. Abstract:
  6. Routines for doing I/O on the netlogon service's mailslots.
  7. Author:
  8. 03-Nov-1993 (cliffv)
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. //
  16. // Common include files.
  17. //
  18. #include "logonsrv.h" // Include files common to entire service
  19. #pragma hdrstop
  20. //
  21. // Include files specific to this .c file
  22. //
  23. #include <lmbrowsr.h> // I_BrowserSetNetlogonState
  24. #include <srvann.h> // Service announcement
  25. #include <nbtioctl.h> // IOCTL_NETBT_REMOVE_FROM_REMOTE_TABLE
  26. //
  27. // Define maximum buffer size returned from the browser.
  28. //
  29. // Header returned by browser + actual mailslot message size + name of
  30. // mailslot + name of transport.
  31. //
  32. #define MAILSLOT_MESSAGE_SIZE \
  33. (sizeof(NETLOGON_MAILSLOT)+ \
  34. NETLOGON_MAX_MS_SIZE + \
  35. (NETLOGON_LM_MAILSLOT_LEN+1) * sizeof(WCHAR) + \
  36. (MAXIMUM_FILENAME_LENGTH+1) * sizeof(WCHAR))
  37. /////////////////////////////////////////////////////////////////////////////
  38. //
  39. // Structure describing one of the primary mailslots the netlogon service
  40. // will read messages from.
  41. //
  42. // This structure is used only by netlogon's main thread and therefore needs
  43. // no synchronization.
  44. //
  45. /////////////////////////////////////////////////////////////////////////////
  46. typedef struct _NETLOGON_MAILSLOT_DESC {
  47. HANDLE BrowserHandle; // Handle to the browser device driver
  48. HANDLE BrowserReadEvent;// Handle to wait on for overlapped I/O
  49. OVERLAPPED Overlapped; // Governs overlapped I/O
  50. BOOL ReadPending; // True if a read operation is pending
  51. LPBYTE CurrentMessage; // Pointer to Message1 or Message2 below
  52. LPBYTE PreviousMessage; // Previous value of CurrentMessage
  53. //
  54. // Buffer containing message from browser
  55. //
  56. // The buffers are alternated allowing us to compare if an incoming
  57. // message is identical to the previous message.
  58. //
  59. // Leave room so the actual used portion of each buffer is properly aligned.
  60. // The NETLOGON_MAILSLOT struct begins with a LARGE_INTEGER which must be
  61. // aligned.
  62. BYTE Message1[ MAILSLOT_MESSAGE_SIZE + ALIGN_WORST ];
  63. BYTE Message2[ MAILSLOT_MESSAGE_SIZE + ALIGN_WORST ];
  64. } NETLOGON_MAILSLOT_DESC, *PNETLOGON_MAILSLOT_DESC;
  65. PNETLOGON_MAILSLOT_DESC NlGlobalMailslotDesc;
  66. HANDLE
  67. NlBrowserCreateEvent(
  68. VOID
  69. )
  70. /*++
  71. Routine Description:
  72. Creates an event to be used in a DeviceIoControl to the browser.
  73. ??: Consider caching one or two events to reduce the number of create
  74. events
  75. Arguments:
  76. None
  77. Return Value:
  78. Handle to an event or NULL if the event couldn't be allocated.
  79. --*/
  80. {
  81. HANDLE EventHandle;
  82. //
  83. // Create a completion event
  84. //
  85. EventHandle = CreateEvent(
  86. NULL, // No security ettibutes
  87. TRUE, // Manual reset
  88. FALSE, // Initially not signaled
  89. NULL); // No Name
  90. if ( EventHandle == NULL ) {
  91. NlPrint((NL_CRITICAL, "Cannot create Browser read event %ld\n", GetLastError() ));
  92. }
  93. return EventHandle;
  94. }
  95. VOID
  96. NlBrowserCloseEvent(
  97. IN HANDLE EventHandle
  98. )
  99. /*++
  100. Routine Description:
  101. Closes an event used in a DeviceIoControl to the browser.
  102. Arguments:
  103. EventHandle - Handle of the event to close
  104. Return Value:
  105. None.
  106. --*/
  107. {
  108. (VOID) CloseHandle( EventHandle );
  109. }
  110. VOID
  111. NlBrowserClose(
  112. VOID
  113. );
  114. NTSTATUS
  115. NlBrowserDeviceIoControl(
  116. IN HANDLE BrowserHandle,
  117. IN DWORD FunctionCode,
  118. IN PLMDR_REQUEST_PACKET RequestPacket,
  119. IN DWORD RequestPacketSize,
  120. IN LPBYTE Buffer,
  121. IN DWORD BufferSize
  122. )
  123. /*++
  124. Routine Description:
  125. Send a DeviceIoControl syncrhonously to the browser.
  126. Arguments:
  127. FunctionCode - DeviceIoControl function code
  128. RequestPacket - The request packet to send.
  129. RequestPacketSize - Size (in bytes) of the request packet.
  130. Buffer - Additional buffer to pass to the browser
  131. BufferSize - Size (in bytes) of Buffer
  132. Return Value:
  133. Status of the operation.
  134. STATUS_NETWORK_UNREACHABLE: Cannot write to network.
  135. STATUS_BAD_NETWORK_PATH: The name the datagram is destined for isn't
  136. registered
  137. --*/
  138. {
  139. NTSTATUS Status;
  140. DWORD WinStatus;
  141. OVERLAPPED Overlapped;
  142. DWORD BytesReturned;
  143. //
  144. // Initialization
  145. //
  146. RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  147. //
  148. // Get a completion event
  149. //
  150. Overlapped.hEvent = NlBrowserCreateEvent();
  151. if ( Overlapped.hEvent == NULL ) {
  152. return NetpApiStatusToNtStatus( GetLastError() );
  153. }
  154. //
  155. // Send the request to the Datagram Receiver device driver.
  156. //
  157. if ( !DeviceIoControl(
  158. BrowserHandle,
  159. FunctionCode,
  160. RequestPacket,
  161. RequestPacketSize,
  162. Buffer,
  163. BufferSize,
  164. &BytesReturned,
  165. &Overlapped )) {
  166. WinStatus = GetLastError();
  167. if ( WinStatus == ERROR_IO_PENDING ) {
  168. if ( !GetOverlappedResult( BrowserHandle,
  169. &Overlapped,
  170. &BytesReturned,
  171. TRUE )) {
  172. WinStatus = GetLastError();
  173. } else {
  174. WinStatus = NO_ERROR;
  175. }
  176. }
  177. } else {
  178. WinStatus = NO_ERROR;
  179. }
  180. //
  181. // Delete the completion event
  182. //
  183. NlBrowserCloseEvent( Overlapped.hEvent );
  184. if ( WinStatus ) {
  185. //
  186. // Some transports return an error if the name cannot be resolved:
  187. // Nbf returns ERROR_NOT_READY
  188. // NetBt returns ERROR_BAD_NETPATH
  189. //
  190. if ( WinStatus == ERROR_BAD_NETPATH || WinStatus == ERROR_NOT_READY ) {
  191. Status = STATUS_BAD_NETWORK_PATH;
  192. } else {
  193. NlPrint((NL_CRITICAL,"Ioctl %lx to Browser returns %ld\n", FunctionCode, WinStatus));
  194. Status = NetpApiStatusToNtStatus( WinStatus );
  195. }
  196. } else {
  197. Status = STATUS_SUCCESS;
  198. }
  199. return Status;
  200. }
  201. NTSTATUS
  202. NlBrowserOpenDriver(
  203. PHANDLE BrowserHandle
  204. )
  205. /*++
  206. Routine Description:
  207. This routine opens the NT LAN Man Datagram Receiver driver.
  208. Arguments:
  209. BrowserHandle - Upon success, returns a handle to the browser driver
  210. Close it using NtClose
  211. Return Value:
  212. Status of the operation
  213. --*/
  214. {
  215. NTSTATUS Status;
  216. BOOL ReturnValue;
  217. UNICODE_STRING DeviceName;
  218. IO_STATUS_BLOCK IoStatusBlock;
  219. OBJECT_ATTRIBUTES ObjectAttributes;
  220. //
  221. // Open the browser device.
  222. //
  223. RtlInitUnicodeString(&DeviceName, DD_BROWSER_DEVICE_NAME_U);
  224. InitializeObjectAttributes(
  225. &ObjectAttributes,
  226. &DeviceName,
  227. OBJ_CASE_INSENSITIVE,
  228. NULL,
  229. NULL
  230. );
  231. Status = NtOpenFile(
  232. BrowserHandle,
  233. SYNCHRONIZE,
  234. &ObjectAttributes,
  235. &IoStatusBlock,
  236. 0,
  237. 0
  238. );
  239. if (NT_SUCCESS(Status)) {
  240. Status = IoStatusBlock.Status;
  241. }
  242. return Status;
  243. }
  244. NTSTATUS
  245. NlBrowserRenameDomain(
  246. IN LPWSTR OldDomainName OPTIONAL,
  247. IN LPWSTR NewDomainName
  248. )
  249. /*++
  250. Routine Description:
  251. Tell the browser to rename the domain.
  252. Arguments:
  253. OldDomainName - previous name of the domain.
  254. If not specified, the primary domain is implied.
  255. NewDomainName - new name of the domain.
  256. Return Value:
  257. Status of the operation.
  258. --*/
  259. {
  260. NTSTATUS Status;
  261. HANDLE BrowserHandle = NULL;
  262. LPBYTE Where;
  263. UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+2*(DNLEN+1)*sizeof(WCHAR)];
  264. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
  265. //
  266. // Open the browser driver.
  267. //
  268. Status = NlBrowserOpenDriver( &BrowserHandle );
  269. if (Status != NERR_Success) {
  270. return(Status);
  271. }
  272. //
  273. // Build the request packet.
  274. //
  275. RtlInitUnicodeString( &RequestPacket->TransportName, NULL );
  276. RequestPacket->Parameters.DomainRename.ValidateOnly = FALSE;
  277. //
  278. // Copy the new domain name into the packet.
  279. //
  280. Where = (LPBYTE) RequestPacket->Parameters.DomainRename.DomainName;
  281. RequestPacket->Parameters.DomainRename.DomainNameLength = wcslen( NewDomainName ) * sizeof(WCHAR);
  282. wcscpy( (LPWSTR)Where, NewDomainName );
  283. Where += RequestPacket->Parameters.DomainRename.DomainNameLength + sizeof(WCHAR);
  284. //
  285. // Copy the old domain name to the request packet.
  286. //
  287. if ( OldDomainName == NULL ) {
  288. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, NULL );
  289. } else {
  290. wcscpy( (LPWSTR)Where, OldDomainName );
  291. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName,
  292. (LPWSTR)Where );
  293. Where += RequestPacket->EmulatedDomainName.Length + sizeof(WCHAR);
  294. }
  295. //
  296. // Pass the reeqest to the browser.
  297. //
  298. Status = NlBrowserDeviceIoControl(
  299. BrowserHandle,
  300. IOCTL_LMDR_RENAME_DOMAIN,
  301. RequestPacket,
  302. (ULONG)(Where - (LPBYTE)RequestPacket),
  303. NULL,
  304. 0 );
  305. if (Status != NERR_Success) {
  306. NlPrint((NL_CRITICAL,
  307. "NlBrowserRenameDomain: Unable rename domain from %ws to %ws: %lx\n",
  308. OldDomainName,
  309. NewDomainName,
  310. Status ));
  311. }
  312. if ( BrowserHandle != NULL ) {
  313. NtClose( BrowserHandle );
  314. }
  315. return Status;
  316. }
  317. NET_API_STATUS
  318. NlBrowserDeviceControlGetInfo(
  319. IN DWORD FunctionCode,
  320. IN PLMDR_REQUEST_PACKET RequestPacket,
  321. IN DWORD RequestPacketSize,
  322. OUT LPVOID *OutputBuffer,
  323. IN ULONG PreferedMaximumLength,
  324. IN ULONG BufferHintSize
  325. )
  326. /*++
  327. Routine Description:
  328. This function allocates the buffer and fill it with the information
  329. that is retrieved from the datagram receiver.
  330. Arguments:
  331. FunctionCode - DeviceIoControl function code
  332. RequestPacket - The request packet to send.
  333. RequestPacketSize - Size (in bytes) of the request packet.
  334. OutputBuffer - Returns a pointer to the buffer allocated by this routine
  335. which contains the use information requested. This buffer should
  336. be freed using MIDL_user_free.
  337. PreferedMaximumLength - Supplies the number of bytes of information to
  338. return in the buffer. If this value is MAXULONG, we will try to
  339. return all available information if there is enough memory resource.
  340. BufferHintSize - Supplies the hint size of the output buffer so that the
  341. memory allocated for the initial buffer will most likely be large
  342. enough to hold all requested data.
  343. Return Value:
  344. NET_API_STATUS - NERR_Success or reason for failure.
  345. --*/
  346. {
  347. //
  348. // Buffer allocation size for enumeration output buffer.
  349. //
  350. #define INITIAL_ALLOCATION_SIZE 48*1024 // First attempt size (48K)
  351. #define FUDGE_FACTOR_SIZE 1024 // Second try TotalBytesNeeded
  352. // plus this amount
  353. NET_API_STATUS NetStatus;
  354. NTSTATUS Status;
  355. DWORD OutputBufferLength;
  356. DWORD TotalBytesNeeded = 1;
  357. ULONG OriginalResumeKey;
  358. //
  359. // Initialization
  360. //
  361. if ( NlGlobalMailslotDesc == NULL ||
  362. NlGlobalMailslotDesc->BrowserHandle == NULL ) {
  363. return ERROR_NOT_SUPPORTED;
  364. }
  365. OriginalResumeKey = RequestPacket->Parameters.EnumerateNames.ResumeHandle;
  366. //
  367. // If PreferedMaximumLength is MAXULONG, then we are supposed to get all
  368. // the information, regardless of size. Allocate the output buffer of a
  369. // reasonable size and try to use it. If this fails, the Redirector FSD
  370. // will say how much we need to allocate.
  371. //
  372. if (PreferedMaximumLength == MAXULONG) {
  373. OutputBufferLength = (BufferHintSize) ?
  374. BufferHintSize :
  375. INITIAL_ALLOCATION_SIZE;
  376. } else {
  377. OutputBufferLength = PreferedMaximumLength;
  378. }
  379. OutputBufferLength = ROUND_UP_COUNT(OutputBufferLength, ALIGN_WCHAR);
  380. if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
  381. return ERROR_NOT_ENOUGH_MEMORY;
  382. }
  383. RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
  384. //
  385. // Make the request of the Datagram Receiver
  386. //
  387. RequestPacket->Parameters.EnumerateServers.EntriesRead = 0;
  388. Status = NlBrowserDeviceIoControl(
  389. NlGlobalMailslotDesc->BrowserHandle,
  390. FunctionCode,
  391. RequestPacket,
  392. RequestPacketSize,
  393. *OutputBuffer,
  394. OutputBufferLength );
  395. NetStatus = NetpNtStatusToApiStatus(Status);
  396. //
  397. // If we couldn't get all the data on the first call,
  398. // the datagram receiver returned the needed size of the buffer.
  399. //
  400. if ( RequestPacket->Parameters.EnumerateNames.EntriesRead !=
  401. RequestPacket->Parameters.EnumerateNames.TotalEntries ) {
  402. NetpAssert(
  403. FIELD_OFFSET(
  404. LMDR_REQUEST_PACKET,
  405. Parameters.EnumerateNames.TotalBytesNeeded
  406. ) ==
  407. FIELD_OFFSET(
  408. LMDR_REQUEST_PACKET,
  409. Parameters.EnumerateServers.TotalBytesNeeded
  410. )
  411. );
  412. NetpAssert(
  413. FIELD_OFFSET(
  414. LMDR_REQUEST_PACKET,
  415. Parameters.GetBrowserServerList.TotalBytesNeeded
  416. ) ==
  417. FIELD_OFFSET(
  418. LMDR_REQUEST_PACKET,
  419. Parameters.EnumerateServers.TotalBytesNeeded
  420. )
  421. );
  422. TotalBytesNeeded = RequestPacket->Parameters.EnumerateNames.TotalBytesNeeded;
  423. }
  424. if ((TotalBytesNeeded > OutputBufferLength) &&
  425. (PreferedMaximumLength == MAXULONG)) {
  426. //
  427. // Initial output buffer allocated was too small and we need to return
  428. // all data. First free the output buffer before allocating the
  429. // required size plus a fudge factor just in case the amount of data
  430. // grew.
  431. //
  432. MIDL_user_free(*OutputBuffer);
  433. OutputBufferLength =
  434. ROUND_UP_COUNT((TotalBytesNeeded + FUDGE_FACTOR_SIZE),
  435. ALIGN_WCHAR);
  436. if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
  437. return ERROR_NOT_ENOUGH_MEMORY;
  438. }
  439. RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
  440. NetpAssert(
  441. FIELD_OFFSET(
  442. LMDR_REQUEST_PACKET,
  443. Parameters.EnumerateNames.ResumeHandle
  444. ) ==
  445. FIELD_OFFSET(
  446. LMDR_REQUEST_PACKET,
  447. Parameters.EnumerateServers.ResumeHandle
  448. )
  449. );
  450. NetpAssert(
  451. FIELD_OFFSET(
  452. LMDR_REQUEST_PACKET,
  453. Parameters.EnumerateNames.ResumeHandle
  454. ) ==
  455. FIELD_OFFSET(
  456. LMDR_REQUEST_PACKET,
  457. Parameters.GetBrowserServerList.ResumeHandle
  458. )
  459. );
  460. RequestPacket->Parameters.EnumerateNames.ResumeHandle = OriginalResumeKey;
  461. RequestPacket->Parameters.EnumerateServers.EntriesRead = 0;
  462. //
  463. // Make the request of the Datagram Receiver
  464. //
  465. Status = NlBrowserDeviceIoControl(
  466. NlGlobalMailslotDesc->BrowserHandle,
  467. FunctionCode,
  468. RequestPacket,
  469. RequestPacketSize,
  470. *OutputBuffer,
  471. OutputBufferLength );
  472. NetStatus = NetpNtStatusToApiStatus(Status);
  473. }
  474. //
  475. // If not successful in getting any data, or if the caller asked for
  476. // all available data with PreferedMaximumLength == MAXULONG and
  477. // our buffer overflowed, free the output buffer and set its pointer
  478. // to NULL.
  479. //
  480. if ((NetStatus != NERR_Success && NetStatus != ERROR_MORE_DATA) ||
  481. (TotalBytesNeeded == 0) ||
  482. (PreferedMaximumLength == MAXULONG && NetStatus == ERROR_MORE_DATA) ||
  483. (RequestPacket->Parameters.EnumerateServers.EntriesRead == 0)) {
  484. MIDL_user_free(*OutputBuffer);
  485. *OutputBuffer = NULL;
  486. //
  487. // PreferedMaximumLength == MAXULONG and buffer overflowed means
  488. // we do not have enough memory to satisfy the request.
  489. //
  490. if (NetStatus == ERROR_MORE_DATA) {
  491. NetStatus = ERROR_NOT_ENOUGH_MEMORY;
  492. }
  493. }
  494. return NetStatus;
  495. }
  496. NET_API_STATUS
  497. NlBrowserGetTransportList(
  498. OUT PLMDR_TRANSPORT_LIST *TransportList
  499. )
  500. /*++
  501. Routine Description:
  502. This routine returns the list of transports bound into the browser.
  503. Arguments:
  504. TransportList - Transport list to return.
  505. This buffer should be freed using MIDL_user_free.
  506. Return Value:
  507. NERR_Success or reason for failure.
  508. --*/
  509. {
  510. NET_API_STATUS NetStatus;
  511. LMDR_REQUEST_PACKET RequestPacket;
  512. RequestPacket.Type = EnumerateXports;
  513. RtlInitUnicodeString(&RequestPacket.TransportName, NULL);
  514. RtlInitUnicodeString(&RequestPacket.EmulatedDomainName, NULL);
  515. NetStatus = NlBrowserDeviceControlGetInfo(
  516. IOCTL_LMDR_ENUMERATE_TRANSPORTS,
  517. &RequestPacket,
  518. sizeof(RequestPacket),
  519. TransportList,
  520. 0xffffffff,
  521. 4096 );
  522. return NetStatus;
  523. }
  524. NTSTATUS
  525. NlBrowserAddDelName(
  526. IN PDOMAIN_INFO DomainInfo,
  527. IN BOOLEAN AddName,
  528. IN DGRECEIVER_NAME_TYPE NameType,
  529. IN LPWSTR TransportName OPTIONAL,
  530. IN PUNICODE_STRING Name OPTIONAL
  531. )
  532. /*++
  533. Routine Description:
  534. Add or delete a name in the browser.
  535. Arguments:
  536. DomainInfo - Hosted domain the name is to be added/deleted for.
  537. AddName - TRUE to add the name. FALSE to delete the name.
  538. NameType - Type of name to be added/deleted
  539. TransportName -- Name of the transport to send on.
  540. Use NULL to send on all transports.
  541. Name - Name to be added
  542. If not specified, all names of NameType are deleted for this hosted domain.
  543. Return Value:
  544. Status of the operation.
  545. --*/
  546. {
  547. NTSTATUS Status;
  548. LPBYTE Where;
  549. PLMDR_REQUEST_PACKET RequestPacket = NULL;
  550. ULONG TransportNameSize;
  551. //
  552. // Build the request packet.
  553. //
  554. if ( TransportName != NULL ) {
  555. TransportNameSize = (wcslen(TransportName) + 1) * sizeof(WCHAR);
  556. } else {
  557. TransportNameSize = 0;
  558. }
  559. RequestPacket = NetpMemoryAllocate( sizeof(LMDR_REQUEST_PACKET) +
  560. (max(CNLEN, DNLEN) + 1) * sizeof(WCHAR) +
  561. (DNLEN + 1) * sizeof(WCHAR) +
  562. TransportNameSize );
  563. if (RequestPacket == NULL) {
  564. return STATUS_NO_MEMORY;
  565. }
  566. RequestPacket->Parameters.AddDelName.Type = NameType;
  567. //
  568. // Copy the name to be added to request packet.
  569. //
  570. Where = (LPBYTE) RequestPacket->Parameters.AddDelName.Name;
  571. if ( Name == NULL ) {
  572. NlAssert( !AddName );
  573. RequestPacket->Parameters.AddDelName.DgReceiverNameLength = 0;
  574. } else {
  575. RequestPacket->Parameters.AddDelName.DgReceiverNameLength =
  576. Name->Length;
  577. RtlCopyMemory( Where, Name->Buffer, Name->Length );
  578. Where += Name->Length;
  579. }
  580. //
  581. // Copy the hosted domain name to the request packet.
  582. //
  583. wcscpy( (LPWSTR)Where,
  584. DomainInfo->DomUnicodeDomainNameString.Buffer );
  585. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName,
  586. (LPWSTR)Where );
  587. Where += DomainInfo->DomUnicodeDomainNameString.Length + sizeof(WCHAR);
  588. //
  589. // Fill in the TransportName
  590. //
  591. if ( TransportName != NULL ) {
  592. wcscpy( (LPWSTR) Where, TransportName);
  593. RtlInitUnicodeString( &RequestPacket->TransportName, (LPWSTR) Where );
  594. Where += TransportNameSize;
  595. } else {
  596. RequestPacket->TransportName.Length = 0;
  597. RequestPacket->TransportName.Buffer = NULL;
  598. }
  599. //
  600. // Do the actual work
  601. //
  602. Status = NlBrowserDeviceIoControl(
  603. NlGlobalMailslotDesc->BrowserHandle,
  604. AddName ? IOCTL_LMDR_ADD_NAME_DOM : IOCTL_LMDR_DELETE_NAME_DOM,
  605. RequestPacket,
  606. (ULONG)(Where - (LPBYTE)RequestPacket),
  607. NULL,
  608. 0 );
  609. NetpMemoryFree( RequestPacket );
  610. return Status;
  611. }
  612. VOID
  613. NlBrowserAddName(
  614. IN PDOMAIN_INFO DomainInfo
  615. )
  616. /*++
  617. Routine Description:
  618. Add the Domain<1B> name. This is the name NetGetDcName uses to identify
  619. the PDC.
  620. Arguments:
  621. DomainInfo - Hosted domain the name is to be added for.
  622. Return Value:
  623. None.
  624. --*/
  625. {
  626. LPWSTR MsgStrings[3] = { NULL };
  627. BOOL AtLeastOneTransportEnabled = FALSE;
  628. BOOL NameAdded = FALSE;
  629. if ( NlGlobalMailslotDesc == NULL) {
  630. NlPrintDom((NL_CRITICAL, DomainInfo,
  631. "NlBrowserAddName: before browser initialized.\n" ));
  632. goto Cleanup;
  633. }
  634. //
  635. // If the domain has been renamed,
  636. // delete any old names lying around.
  637. //
  638. if ( DomainInfo->DomFlags & DOM_RENAMED_1B_NAME ) {
  639. NlBrowserDelName( DomainInfo );
  640. }
  641. //
  642. // Add the <domain>0x1B name.
  643. //
  644. // This is the name NetGetDcName uses to identify the PDC.
  645. //
  646. // Do this for each transport separately and log any error
  647. // indicating which transport failed.
  648. //
  649. if ( DomainInfo->DomRole == RolePrimary ) {
  650. PLIST_ENTRY ListEntry;
  651. PNL_TRANSPORT TransportEntry;
  652. NTSTATUS Status = STATUS_SUCCESS;
  653. //
  654. // Capture the domain name for event log output.
  655. // If we can't capture (i.e. no memory), we simply
  656. // won't output below.
  657. //
  658. EnterCriticalSection( &NlGlobalDomainCritSect );
  659. MsgStrings[0] = NetpAllocWStrFromWStr( DomainInfo->DomUnicodeDomainName );
  660. LeaveCriticalSection( &NlGlobalDomainCritSect );
  661. EnterCriticalSection( &NlGlobalTransportCritSect );
  662. for ( ListEntry = NlGlobalTransportList.Flink ;
  663. ListEntry != &NlGlobalTransportList ;
  664. ListEntry = ListEntry->Flink) {
  665. TransportEntry = CONTAINING_RECORD( ListEntry, NL_TRANSPORT, Next );
  666. //
  667. // Skip deleted transports.
  668. //
  669. if ( !TransportEntry->TransportEnabled ) {
  670. continue;
  671. }
  672. AtLeastOneTransportEnabled = TRUE;
  673. Status = NlBrowserAddDelName( DomainInfo,
  674. TRUE,
  675. PrimaryDomainBrowser,
  676. TransportEntry->TransportName,
  677. &DomainInfo->DomUnicodeDomainNameString );
  678. if ( NT_SUCCESS(Status) ) {
  679. NameAdded = TRUE;
  680. NlPrintDom(( NL_MISC, DomainInfo,
  681. "Added the 0x1B name on transport %ws\n",
  682. TransportEntry->TransportName ));
  683. //
  684. // Output the event log indicating the name of the failed transport
  685. //
  686. } else if ( MsgStrings[0] != NULL ) {
  687. NlPrintDom(( NL_CRITICAL, DomainInfo,
  688. "Failed to add the 0x1B name on transport %ws\n",
  689. TransportEntry->TransportName ));
  690. MsgStrings[1] = TransportEntry->TransportName;
  691. MsgStrings[2] = (LPWSTR) LongToPtr( Status );
  692. NlpWriteEventlog(
  693. NELOG_NetlogonAddNameFailure,
  694. EVENTLOG_ERROR_TYPE,
  695. (LPBYTE)&Status,
  696. sizeof(Status),
  697. MsgStrings,
  698. 3 | NETP_LAST_MESSAGE_IS_NTSTATUS );
  699. }
  700. }
  701. LeaveCriticalSection( &NlGlobalTransportCritSect );
  702. //
  703. // Indicate that the name was added (at least on one transport)
  704. //
  705. if ( NameAdded ) {
  706. EnterCriticalSection( &NlGlobalDomainCritSect );
  707. DomainInfo->DomFlags |= DOM_ADDED_1B_NAME;
  708. LeaveCriticalSection( &NlGlobalDomainCritSect );
  709. }
  710. if ( !AtLeastOneTransportEnabled ) {
  711. NlPrintDom(( NL_CRITICAL, DomainInfo,
  712. "Can't add the 0x1B name because all transports are disabled\n" ));
  713. }
  714. }
  715. Cleanup:
  716. if ( MsgStrings[0] != NULL ) {
  717. NetApiBufferFree( MsgStrings[0] );
  718. }
  719. }
  720. VOID
  721. NlBrowserDelName(
  722. IN PDOMAIN_INFO DomainInfo
  723. )
  724. /*++
  725. Routine Description:
  726. Delete the Domain<1B> name. This is the name NetGetDcName uses to identify
  727. the PDC.
  728. Arguments:
  729. DomainInfo - Hosted domain the name is to be deleted for.
  730. Return Value:
  731. Success (Not used)
  732. --*/
  733. {
  734. NTSTATUS Status;
  735. if ( NlGlobalMailslotDesc == NULL) {
  736. NlPrintDom((NL_CRITICAL, DomainInfo,
  737. "NlBrowserDelName: before browser initialized.\n" ));
  738. return;
  739. }
  740. //
  741. // Delete the <domain>0x1B name.
  742. //
  743. EnterCriticalSection(&NlGlobalDomainCritSect);
  744. if ( NlGlobalMailslotDesc->BrowserHandle != NULL &&
  745. (DomainInfo->DomFlags & (DOM_ADDED_1B_NAME|DOM_RENAMED_1B_NAME)) != 0 ) {
  746. LeaveCriticalSection(&NlGlobalDomainCritSect);
  747. Status = NlBrowserAddDelName( DomainInfo,
  748. FALSE,
  749. PrimaryDomainBrowser,
  750. NULL, // Delete on all transports
  751. NULL ); // Delete all such names to handle the rename case
  752. if (! NT_SUCCESS(Status)) {
  753. NlPrintDom((NL_CRITICAL, DomainInfo,
  754. "Can't remove the 0x1B name: 0x%lx\n",
  755. Status));
  756. }
  757. EnterCriticalSection(&NlGlobalDomainCritSect);
  758. DomainInfo->DomFlags &= ~(DOM_ADDED_1B_NAME|DOM_RENAMED_1B_NAME);
  759. }
  760. LeaveCriticalSection(&NlGlobalDomainCritSect);
  761. return;
  762. }
  763. NET_API_STATUS
  764. NlBrowserFixAllNames(
  765. IN PDOMAIN_INFO DomainInfo,
  766. IN PVOID Context
  767. )
  768. /*++
  769. Routine Description:
  770. Scavenge the DomainName<1B> name.
  771. Arguments:
  772. DomainInfo - The domain being scavenged.
  773. Context - Not Used
  774. Return Value:
  775. Success (not used).
  776. --*/
  777. {
  778. //
  779. // Ensure our Domain<1B> name is registered.
  780. //
  781. if ( NlGlobalTerminate ) {
  782. return NERR_Success;
  783. }
  784. if ( DomainInfo->DomRole == RolePrimary ) {
  785. NlBrowserAddName( DomainInfo );
  786. } else {
  787. NlBrowserDelName( DomainInfo );
  788. }
  789. return NERR_Success;
  790. UNREFERENCED_PARAMETER( Context );
  791. }
  792. ULONG
  793. NlServerType(
  794. IN DWORD Role
  795. )
  796. /*++
  797. Routine Description:
  798. Determines server type, that is used to set in service table.
  799. Arguments:
  800. Role - Role to be translated
  801. Return Value:
  802. SV_TYPE_DOMAIN_CTRL if role is primary domain controller
  803. SV_TYPE_DOMAIN_BAKCTRL if backup
  804. 0 if none of the above
  805. --*/
  806. {
  807. switch (Role) {
  808. case RolePrimary:
  809. return SV_TYPE_DOMAIN_CTRL;
  810. case RoleBackup:
  811. return SV_TYPE_DOMAIN_BAKCTRL;
  812. default:
  813. return 0;
  814. }
  815. }
  816. VOID
  817. NlBrowserSyncHostedDomains(
  818. VOID
  819. )
  820. /*++
  821. Routine Description:
  822. Tell the browser and SMB server to delete any hosted domains it has
  823. that we don't have.
  824. Arguments:
  825. None.
  826. Return Value:
  827. None.
  828. --*/
  829. {
  830. NET_API_STATUS NetStatus;
  831. LPWSTR HostedDomainName;
  832. LPWSTR HostedComputerName;
  833. DWORD RoleBits;
  834. PBROWSER_EMULATED_DOMAIN Domains;
  835. DWORD EntriesRead;
  836. DWORD TotalEntries;
  837. DWORD i;
  838. PSERVER_TRANSPORT_INFO_1 TransportInfo1;
  839. #ifdef notdef
  840. //
  841. // Enumerate the Hosted domains.
  842. // ?? Don't call this function. This function requires the browser be
  843. // running. Rather, invent an Ioctl to the bowser to enumerate domains
  844. // and use that ioctl here.
  845. //
  846. // ?? Note: Role no longer comes back from this API. Role in the browser
  847. // is now maintained on a per "network" basis.
  848. NetStatus = I_BrowserQueryEmulatedDomains(
  849. NULL,
  850. &Domains,
  851. &EntriesRead );
  852. if ( NetStatus != NERR_Success ) {
  853. NlPrint((NL_CRITICAL,"NlBrowserSyncHostedDomains: Couldn't I_BrowserQueryEmulatedDomains %ld 0x%lx.\n",
  854. NetStatus, NetStatus ));
  855. //
  856. // Handle each enumerated domain
  857. //
  858. } else if ( EntriesRead != 0 ) {
  859. for ( i=0 ; i<EntriesRead; i++ ) {
  860. PDOMAIN_INFO DomainInfo;
  861. //
  862. // If we know the specified domain,
  863. // all is well.
  864. //
  865. DomainInfo = NlFindNetbiosDomain( Domains[i].DomainName, FALSE );
  866. if ( DomainInfo != NULL ) {
  867. //
  868. // Ensure the hosted server name is identical.
  869. //
  870. if ( NlNameCompare( Domains[i].EmulatedServerName,
  871. DomainInfo->DomUnicodeComputerNameString.Buffer,
  872. NAMETYPE_COMPUTER) != 0 ) {
  873. NlPrintDom((NL_CRITICAL, DomainInfo,
  874. "NlBrowserSyncHostedDomains: hosted computer name missmatch: %ws %ws.\n",
  875. Domains[i].EmulatedServerName,
  876. DomainInfo->DomUnicodeComputerNameString.Buffer ));
  877. // Tell the browser the name we have by deleting and re-adding
  878. NlBrowserUpdate( DomainInfo, RoleInvalid );
  879. NlBrowserUpdate( DomainInfo, DomainInfo->DomRole );
  880. }
  881. NlDereferenceDomain( DomainInfo );
  882. //
  883. // If we don't have the specified domain,
  884. // delete it from the browser.
  885. //
  886. } else {
  887. NlPrint((NL_CRITICAL,"%ws: NlBrowserSyncHostedDomains: Browser had an hosted domain we didn't (deleting)\n",
  888. Domains[i].DomainName ));
  889. // ?? Don't call this function. This function requires the browser be
  890. // running. Rather, invent an Ioctl to the bowser to enumerate domains
  891. // and use that ioctl here.
  892. //
  893. NetStatus = I_BrowserSetNetlogonState(
  894. NULL,
  895. Domains[i].DomainName,
  896. NULL,
  897. 0 );
  898. if ( NetStatus != NERR_Success ) {
  899. NlPrint((NL_CRITICAL,"%ws: NlBrowserSyncHostedDomains: Couldn't I_BrowserSetNetlogonState %ld 0x%lx.\n",
  900. Domains[i].DomainName,
  901. NetStatus, NetStatus ));
  902. // This isn't fatal
  903. }
  904. }
  905. }
  906. NetApiBufferFree( Domains );
  907. }
  908. #endif // notdef
  909. //
  910. // Enumerate the transports supported by the server.
  911. //
  912. NetStatus = NetServerTransportEnum(
  913. NULL, // local
  914. 1, // level 1
  915. (LPBYTE *) &TransportInfo1,
  916. 0xFFFFFFFF, // PrefMaxLength
  917. &EntriesRead,
  918. &TotalEntries,
  919. NULL ); // No resume handle
  920. if ( NetStatus != NERR_Success && NetStatus != ERROR_MORE_DATA ) {
  921. NlPrint(( NL_CRITICAL,
  922. "NlBrowserSyncEnulatedDomains: Cannot NetServerTransportEnum %ld\n",
  923. NetStatus ));
  924. //
  925. // Handle each enumerated transport.
  926. } else if ( EntriesRead != 0 ) {
  927. //
  928. // Weed out duplicates.
  929. //
  930. // It'd be really inefficient to process duplicate entries. Especially,
  931. // in the cases where corrective action needed to be taken.
  932. //
  933. for ( i=0; i<EntriesRead; i++ ) {
  934. DWORD j;
  935. for ( j=i+1; j<EntriesRead; j++ ) {
  936. if ( TransportInfo1[i].svti1_domain != NULL &&
  937. TransportInfo1[i].svti1_transportaddresslength ==
  938. TransportInfo1[j].svti1_transportaddresslength &&
  939. RtlEqualMemory( TransportInfo1[i].svti1_transportaddress,
  940. TransportInfo1[j].svti1_transportaddress,
  941. TransportInfo1[i].svti1_transportaddresslength ) &&
  942. NlNameCompare( TransportInfo1[i].svti1_domain,
  943. TransportInfo1[j].svti1_domain,
  944. NAMETYPE_DOMAIN ) == 0 ) {
  945. #ifdef notdef
  946. NlPrint((NL_CRITICAL,
  947. "%ws: NlBrowserSyncHostedDomains: Duplicate SMB server entry ignored.\n",
  948. TransportInfo1[i].svti1_domain ));
  949. #endif // notdef
  950. TransportInfo1[j].svti1_domain = NULL;
  951. }
  952. }
  953. }
  954. //
  955. // Process each enumerated domain.
  956. //
  957. for ( i=0 ; i<EntriesRead; i++ ) {
  958. PDOMAIN_INFO DomainInfo;
  959. WCHAR UnicodeComputerName[CNLEN+1];
  960. ULONG UnicodeComputerNameSize;
  961. NTSTATUS TempStatus;
  962. //
  963. // ignore duplicates
  964. //
  965. if ( TransportInfo1[i].svti1_domain == NULL ) {
  966. continue;
  967. }
  968. #ifdef notdef
  969. NlPrint((NL_CRITICAL,
  970. "%ws: NlBrowserSyncHostedDomains: processing SMB entry.\n",
  971. TransportInfo1[i].svti1_domain ));
  972. #endif // notdef
  973. //
  974. // If we know the specified domain,
  975. // all is well.
  976. //
  977. DomainInfo = NlFindNetbiosDomain( TransportInfo1[i].svti1_domain, FALSE );
  978. if ( DomainInfo != NULL ) {
  979. //
  980. // Ensure the Hosted server name is identical.
  981. //
  982. if ( TransportInfo1[i].svti1_transportaddresslength !=
  983. DomainInfo->DomOemComputerNameLength ||
  984. !RtlEqualMemory( TransportInfo1[i].svti1_transportaddress,
  985. DomainInfo->DomOemComputerName,
  986. DomainInfo->DomOemComputerNameLength ) ) {
  987. TempStatus = RtlOemToUnicodeN(
  988. UnicodeComputerName,
  989. CNLEN*sizeof(WCHAR),
  990. &UnicodeComputerNameSize,
  991. TransportInfo1[i].svti1_transportaddress,
  992. TransportInfo1[i].svti1_transportaddresslength );
  993. if ( NT_SUCCESS(TempStatus) ) {
  994. UnicodeComputerName[UnicodeComputerNameSize/sizeof(WCHAR)] = L'\0';
  995. NlPrintDom((NL_CRITICAL, DomainInfo,
  996. "NlBrowserSyncHostedDomains: hosted computer name mismatch (SMB server): %ws %ws.\n",
  997. UnicodeComputerName,
  998. DomainInfo->DomUnicodeComputerNameString.Buffer ));
  999. //
  1000. // Tell the SMB server the name we have by deleting and re-adding
  1001. //
  1002. NetStatus = NetServerComputerNameDel(
  1003. NULL,
  1004. UnicodeComputerName );
  1005. if ( NetStatus != NERR_Success ) {
  1006. NlPrintDom((NL_CRITICAL, DomainInfo,
  1007. "NlBrowserSyncHostedDomains: can't NetServerComputerNameDel: %ws.\n",
  1008. UnicodeComputerName ));
  1009. // This isn't fatal
  1010. }
  1011. NetStatus = NlServerComputerNameAdd(
  1012. DomainInfo->DomUnicodeDomainName,
  1013. DomainInfo->DomUnicodeComputerNameString.Buffer );
  1014. if ( NetStatus != NERR_Success ) {
  1015. NlPrintDom((NL_CRITICAL, DomainInfo,
  1016. "NlBrowserSyncHostedDomains: can't NetServerComputerNameAdd: %ws.\n",
  1017. DomainInfo->DomUnicodeComputerNameString.Buffer ));
  1018. // This isn't fatal
  1019. }
  1020. }
  1021. }
  1022. NlDereferenceDomain( DomainInfo );
  1023. //
  1024. // If we don't have the specified domain,
  1025. // delete it from the SMB server.
  1026. //
  1027. } else {
  1028. NlPrint((NL_CRITICAL,"%ws: NlBrowserSyncHostedDomains: SMB server had a hosted domain we didn't (deleting)\n",
  1029. TransportInfo1[i].svti1_domain ));
  1030. TempStatus = RtlOemToUnicodeN(
  1031. UnicodeComputerName,
  1032. CNLEN*sizeof(WCHAR),
  1033. &UnicodeComputerNameSize,
  1034. TransportInfo1[i].svti1_transportaddress,
  1035. TransportInfo1[i].svti1_transportaddresslength );
  1036. if ( !NT_SUCCESS(TempStatus) ) {
  1037. NlPrint((NL_CRITICAL,
  1038. "%ws: NlBrowserSyncHostedDomains: can't RtlOemToUnicode: %lx.\n",
  1039. TransportInfo1[i].svti1_domain,
  1040. TempStatus ));
  1041. // This isn't fatal
  1042. } else {
  1043. UnicodeComputerName[UnicodeComputerNameSize/sizeof(WCHAR)] = L'\0';
  1044. // When we really do hosted domains,
  1045. // we have to work out a mechanism where the SMB server and
  1046. // Netlogon has the same set of hosted domains.
  1047. //
  1048. // I ran into a case where netlogon had processed a rename
  1049. // of the domain and the SMB server hadn't. In that case,
  1050. // the code below would delete the primary domain of the SMB
  1051. // server.
  1052. //
  1053. #ifdef notdef
  1054. NetStatus = NetServerComputerNameDel(
  1055. NULL,
  1056. UnicodeComputerName );
  1057. if ( NetStatus != NERR_Success ) {
  1058. NlPrint((NL_CRITICAL,
  1059. "%ws: NlBrowserSyncHostedDomains: can't NetServerComputerNameDel: %ws.\n",
  1060. TransportInfo1[i].svti1_domain,
  1061. UnicodeComputerName ));
  1062. // This isn't fatal
  1063. }
  1064. #endif // notdef
  1065. }
  1066. }
  1067. }
  1068. (VOID) NetApiBufferFree( TransportInfo1 );
  1069. }
  1070. return;
  1071. }
  1072. VOID
  1073. NlBrowserUpdate(
  1074. IN PDOMAIN_INFO DomainInfo,
  1075. IN DWORD Role
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. Tell the browser and SMB server about our new role.
  1080. Arguments:
  1081. DomainInfo - Hosted domain the name is to be deleted for.
  1082. Role - Our new Role.
  1083. RoleInvalid implies the domain is being deleted.
  1084. Return Value:
  1085. None.
  1086. --*/
  1087. {
  1088. NET_API_STATUS NetStatus;
  1089. DWORD BrowserRole;
  1090. //
  1091. // Initialization.
  1092. //
  1093. switch (Role) {
  1094. case RolePrimary:
  1095. BrowserRole = BROWSER_ROLE_PDC ; break;
  1096. case RoleBackup:
  1097. BrowserRole = BROWSER_ROLE_BDC ; break;
  1098. default:
  1099. // Default to telling the browser to delete the Hosted domain.
  1100. BrowserRole = 0 ; break;
  1101. }
  1102. //
  1103. // Tell the server what role to announce
  1104. //
  1105. if ( DomainInfo->DomFlags & DOM_PRIMARY_DOMAIN ) {
  1106. BOOL Ok;
  1107. //
  1108. // Since the service controller doesn't have a mechanism to set some
  1109. // bits and turn others off, turn all of the bits off then set the right
  1110. // ones.
  1111. //
  1112. Ok = I_ScSetServiceBits( NlGlobalServiceHandle,
  1113. SV_TYPE_DOMAIN_CTRL |
  1114. SV_TYPE_DOMAIN_BAKCTRL, // Bits of interest
  1115. FALSE, // Set bits off
  1116. FALSE, // Don't force immediate announcement
  1117. NULL); // All transports
  1118. if ( !Ok ) {
  1119. NetStatus = GetLastError();
  1120. NlPrint((NL_CRITICAL,"Couldn't I_ScSetServiceBits off %ld 0x%lx.\n",
  1121. NetStatus, NetStatus ));
  1122. // This isn't fatal
  1123. }
  1124. //
  1125. // For the primary domain,
  1126. // Tell the service controller and let it tell the server service after it
  1127. // merges the bits from the other services.
  1128. //
  1129. if ( BrowserRole != 0 ) {
  1130. Ok = I_ScSetServiceBits( NlGlobalServiceHandle,
  1131. NlServerType(Role),
  1132. TRUE, // Set bits on
  1133. TRUE, // Force immediate announcement
  1134. NULL); // All transports
  1135. }
  1136. if ( !Ok ) {
  1137. NetStatus = GetLastError();
  1138. NlPrint((NL_CRITICAL,"Couldn't I_ScSetServiceBits %ld 0x%lx.\n",
  1139. NetStatus, NetStatus ));
  1140. // This isn't fatal
  1141. }
  1142. } else {
  1143. //
  1144. // For domains that aren't the primary domain,
  1145. // tell the Lanman server directly
  1146. // (since the service controller doesn't care about those doamins).
  1147. //
  1148. NetStatus = I_NetServerSetServiceBitsEx(
  1149. NULL, // Local server service
  1150. DomainInfo->DomUnicodeComputerNameString.Buffer,
  1151. NULL, // All transports
  1152. SV_TYPE_DOMAIN_CTRL |
  1153. SV_TYPE_DOMAIN_BAKCTRL, // Bits of interest
  1154. NlServerType(Role), // New Role
  1155. TRUE ); // Update immediately
  1156. if ( NetStatus != NERR_Success ) {
  1157. NlPrintDom(( NL_CRITICAL, DomainInfo,
  1158. "NlBrowserUpdate: Couldn't I_NetServerSetServiceBitsEx %ld 0x%lx.\n",
  1159. NetStatus, NetStatus ));
  1160. // This isn't fatal
  1161. }
  1162. }
  1163. #ifdef notdef
  1164. //
  1165. // Tell the browser our role has changed.
  1166. //
  1167. // Avoid deleting the primary domain
  1168. if ( BrowserRole != 0 || !IsPrimaryDomain(DomainInfo) ) {
  1169. // ?? Don't call this function. This function requires the browser be
  1170. // running. Rather, invent an Ioctl to the bowser to enumerate domains
  1171. // and use that ioctl here.
  1172. //
  1173. // This function serves two purposes: Adding/deleting the hosted domain
  1174. // in the browser and setting the role. The first might very well be
  1175. // a function of the bowser. The later is naturally a function of
  1176. // the browser service (but should be indirected through the bowser to
  1177. // avoid domain rename issues).
  1178. //
  1179. // When we really do multiple hosted domains, create an emulated domain
  1180. // via one IOCTL to the bowser. Change it's role via another ioctl
  1181. // to the bowser. Both calls will result in notifications to the browser
  1182. // service via normal PNP notifications.
  1183. //
  1184. // One might even think that the ioctl to change its role is the one
  1185. // below that adds the 1B name. That is, if the 1B name is added, then
  1186. // this machine is the PDC. If not, then it is not the PDC.
  1187. //
  1188. // In the mean time, hack the interface to the browser service indicating
  1189. // that it should NEVER create an emulated domain based on this call.
  1190. // Otherwise, on a domain rename, we may end up creating an emulated domain
  1191. // because our notification and the browser's are asynchronous.
  1192. //
  1193. // Actually, I've updated the bowser to do the 1B trick mentioned above.
  1194. // So this code merely has to do the right thing for the hosted domain.
  1195. //
  1196. NetStatus = I_BrowserSetNetlogonState(
  1197. NULL,
  1198. DomainInfo->DomUnicodeDomainName,
  1199. DomainInfo->DomUnicodeComputerNameString.Buffer,
  1200. BrowserRole | BROWSER_ROLE_AVOID_CREATING_DOMAIN );
  1201. if ( NetStatus != NERR_Success ) {
  1202. if ( BrowserRole != 0 || NetStatus != ERROR_NO_SUCH_DOMAIN ) {
  1203. NlPrintDom((NL_CRITICAL, DomainInfo,
  1204. "NlBrowserUpdate: Couldn't I_BrowserSetNetlogonState %ld 0x%lx.\n",
  1205. NetStatus, NetStatus ));
  1206. }
  1207. // This isn't fatal
  1208. }
  1209. }
  1210. #endif // notdef
  1211. //
  1212. // Register or deregister the Domain<1B> name depending on the new role
  1213. //
  1214. if ( Role == RolePrimary ) {
  1215. NlBrowserAddName( DomainInfo );
  1216. } else {
  1217. NlBrowserDelName( DomainInfo );
  1218. }
  1219. //
  1220. // Tell the SMB server to delete a removed Hosted domain.
  1221. //
  1222. if ( Role == RoleInvalid && !IsPrimaryDomain(DomainInfo) ) {
  1223. NetStatus = NetServerComputerNameDel(
  1224. NULL,
  1225. DomainInfo->DomUnicodeComputerNameString.Buffer );
  1226. if ( NetStatus != NERR_Success ) {
  1227. NlPrintDom(( NL_CRITICAL, DomainInfo,
  1228. "NlBrowserUpdate: Couldn't NetServerComputerNameDel %ld 0x%lx.\n",
  1229. NetStatus, NetStatus ));
  1230. // This isn't fatal
  1231. }
  1232. }
  1233. return;
  1234. }
  1235. BOOL
  1236. NlBrowserOpen(
  1237. VOID
  1238. )
  1239. /*++
  1240. Routine Description:
  1241. This routine opens the NT LAN Man Datagram Receiver driver and prepares
  1242. for reading mailslot messages from it.
  1243. Arguments:
  1244. None.
  1245. Return Value:
  1246. TRUE -- iff initialization is successful.
  1247. if false, NlExit will already have been called.
  1248. --*/
  1249. {
  1250. NTSTATUS Status;
  1251. BOOL ReturnValue;
  1252. BYTE Buffer[sizeof(LMDR_REQUEST_PACKET) +
  1253. (max(CNLEN, DNLEN) + 1) * sizeof(WCHAR)];
  1254. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET) Buffer;
  1255. //
  1256. // Allocate the mailslot descriptor for this mailslot
  1257. //
  1258. NlGlobalMailslotDesc = NetpMemoryAllocate( sizeof(NETLOGON_MAILSLOT_DESC) );
  1259. if ( NlGlobalMailslotDesc == NULL ) {
  1260. NlExit( SERVICE_UIC_RESOURCE, ERROR_NOT_ENOUGH_MEMORY, LogError, NULL);
  1261. return FALSE;
  1262. }
  1263. RtlZeroMemory( NlGlobalMailslotDesc, sizeof(NETLOGON_MAILSLOT_DESC) );
  1264. NlGlobalMailslotDesc->CurrentMessage =
  1265. ROUND_UP_POINTER( NlGlobalMailslotDesc->Message1, ALIGN_WORST);
  1266. //
  1267. // Open the browser device.
  1268. //
  1269. Status = NlBrowserOpenDriver( &NlGlobalMailslotDesc->BrowserHandle );
  1270. if (! NT_SUCCESS(Status)) {
  1271. NlPrint((NL_CRITICAL,
  1272. "NtOpenFile browser driver failed: 0x%lx\n",
  1273. Status));
  1274. ReturnValue = FALSE;
  1275. goto Cleanup;
  1276. }
  1277. //
  1278. // Create a completion event
  1279. //
  1280. NlGlobalMailslotHandle =
  1281. NlGlobalMailslotDesc->BrowserReadEvent = NlBrowserCreateEvent();
  1282. if ( NlGlobalMailslotDesc->BrowserReadEvent == NULL ) {
  1283. Status = NetpApiStatusToNtStatus( GetLastError() );
  1284. ReturnValue = FALSE;
  1285. goto Cleanup;
  1286. }
  1287. //
  1288. // Set the maximum number of messages to be queued
  1289. //
  1290. RequestPacket->TransportName.Length = 0;
  1291. RequestPacket->TransportName.Buffer = NULL;
  1292. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, NULL );
  1293. RequestPacket->Parameters.NetlogonMailslotEnable.MaxMessageCount =
  1294. NlGlobalMemberWorkstation ?
  1295. 1 :
  1296. NlGlobalParameters.MaximumMailslotMessages;
  1297. Status = NlBrowserDeviceIoControl(
  1298. NlGlobalMailslotDesc->BrowserHandle,
  1299. IOCTL_LMDR_NETLOGON_MAILSLOT_ENABLE,
  1300. RequestPacket,
  1301. sizeof(LMDR_REQUEST_PACKET),
  1302. NULL,
  1303. 0 );
  1304. if (! NT_SUCCESS(Status)) {
  1305. NlPrint((NL_CRITICAL,"Can't set browser max message count: 0x%lx\n",
  1306. Status));
  1307. ReturnValue = FALSE;
  1308. goto Cleanup;
  1309. }
  1310. ReturnValue = TRUE;
  1311. Cleanup:
  1312. if ( !ReturnValue ) {
  1313. NET_API_STATUS NetStatus = NetpNtStatusToApiStatus(Status);
  1314. NlExit( NELOG_NetlogonBrowserDriver, NetStatus, LogErrorAndNtStatus, NULL);
  1315. NlBrowserClose();
  1316. }
  1317. return ReturnValue;
  1318. }
  1319. VOID
  1320. NlBrowserClose(
  1321. VOID
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. This routine cleans up after a NlBrowserInitialize()
  1326. Arguments:
  1327. None.
  1328. Return Value:
  1329. None.
  1330. --*/
  1331. {
  1332. IO_STATUS_BLOCK IoSb;
  1333. NTSTATUS Status;
  1334. BYTE Buffer[sizeof(LMDR_REQUEST_PACKET) +
  1335. (max(CNLEN, DNLEN) + 1) * sizeof(WCHAR)];
  1336. PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET) Buffer;
  1337. if ( NlGlobalMailslotDesc == NULL) {
  1338. return;
  1339. }
  1340. //
  1341. // If we've opened the browser, clean up.
  1342. //
  1343. if ( NlGlobalMailslotDesc->BrowserHandle != NULL ) {
  1344. //
  1345. // Tell the browser to stop queueing messages
  1346. //
  1347. RequestPacket->TransportName.Length = 0;
  1348. RequestPacket->TransportName.Buffer = NULL;
  1349. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName, NULL );
  1350. RequestPacket->Parameters.NetlogonMailslotEnable.MaxMessageCount = 0;
  1351. Status = NlBrowserDeviceIoControl(
  1352. NlGlobalMailslotDesc->BrowserHandle,
  1353. IOCTL_LMDR_NETLOGON_MAILSLOT_ENABLE,
  1354. RequestPacket,
  1355. sizeof(LMDR_REQUEST_PACKET),
  1356. NULL,
  1357. 0 );
  1358. if (! NT_SUCCESS(Status)) {
  1359. NlPrint((NL_CRITICAL,"Can't reset browser max message count: 0x%lx\n",
  1360. Status));
  1361. }
  1362. //
  1363. // Cancel the I/O operations outstanding on the browser.
  1364. //
  1365. NtCancelIoFile(NlGlobalMailslotDesc->BrowserHandle, &IoSb);
  1366. //
  1367. // Close the handle to the browser
  1368. //
  1369. NtClose(NlGlobalMailslotDesc->BrowserHandle);
  1370. NlGlobalMailslotDesc->BrowserHandle = NULL;
  1371. }
  1372. //
  1373. // Close the global browser read event
  1374. //
  1375. if ( NlGlobalMailslotDesc->BrowserReadEvent != NULL ) {
  1376. NlBrowserCloseEvent(NlGlobalMailslotDesc->BrowserReadEvent);
  1377. }
  1378. NlGlobalMailslotHandle = NULL;
  1379. //
  1380. // Free the descriptor describing the browser
  1381. //
  1382. NetpMemoryFree( NlGlobalMailslotDesc );
  1383. NlGlobalMailslotDesc = NULL;
  1384. }
  1385. NTSTATUS
  1386. NlpWriteMailslot(
  1387. IN LPWSTR MailslotName,
  1388. IN LPVOID Buffer,
  1389. IN DWORD BufferSize
  1390. )
  1391. /*++
  1392. Routine Description:
  1393. Write a message to a named mailslot
  1394. Arguments:
  1395. MailslotName - Unicode name of the mailslot to write to.
  1396. Buffer - Data to write to the mailslot.
  1397. BufferSize - Number of bytes to write to the mailslot.
  1398. Return Value:
  1399. NT status code for the operation
  1400. --*/
  1401. {
  1402. NTSTATUS Status;
  1403. NET_API_STATUS NetStatus;
  1404. //
  1405. // Write the mailslot message.
  1406. //
  1407. NetStatus = NetpLogonWriteMailslot( MailslotName, Buffer, BufferSize );
  1408. if ( NetStatus != NERR_Success ) {
  1409. Status = NetpApiStatusToNtStatus( NetStatus );
  1410. NlPrint((NL_CRITICAL, "NetpLogonWriteMailslot failed %lx\n", Status));
  1411. return Status;
  1412. }
  1413. #if NETLOGONDBG
  1414. NlPrint(( NL_MAILSLOT,
  1415. "Sent '%s' message to %ws on all transports.\n",
  1416. NlMailslotOpcode(((PNETLOGON_LOGON_QUERY)Buffer)->Opcode),
  1417. MailslotName));
  1418. NlpDumpBuffer( NL_MAILSLOT_TEXT, Buffer, BufferSize );
  1419. #endif // NETLOGONDBG
  1420. return STATUS_SUCCESS;
  1421. }
  1422. NTSTATUS
  1423. NlFlushNetbiosCacheName(
  1424. IN LPCWSTR NetbiosDomainName,
  1425. IN CHAR Extention,
  1426. IN PNL_TRANSPORT Transport
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. This routine flushes the specified name from the Netbios
  1431. remote cache table.
  1432. Arguments:
  1433. NetbiosDomainName - The name to be flushed.
  1434. Extention - the type of the name (extention added as the
  1435. 16th character of the name to flush): 0x00, 0x1C, 0x1B, etc.
  1436. Transport - The transport (device) on which the name is to
  1437. be flushed.
  1438. Return Value:
  1439. STATUS_SUCCESS: The name has been successfully flushed
  1440. STATUS_RESOURCE_NAME_NOT_FOUND: The name was not found in the cache
  1441. Otherwise, an error returned by NtCreateFile or NtDeviceIoControlFile
  1442. --*/
  1443. {
  1444. NTSTATUS NtStatus = STATUS_SUCCESS;
  1445. IO_STATUS_BLOCK IoStatusBlock;
  1446. CHAR NameToBeFlushed[NETBIOS_NAMESIZE];
  1447. //
  1448. // First open the Netbios device if it hasn't been done already
  1449. //
  1450. EnterCriticalSection( &NlGlobalTransportCritSect );
  1451. if ( Transport->DeviceHandle == INVALID_HANDLE_VALUE ) {
  1452. OBJECT_ATTRIBUTES Attributes;
  1453. UNICODE_STRING UnicodeString;
  1454. HANDLE LocalHandle;
  1455. RtlInitUnicodeString( &UnicodeString, Transport->TransportName );
  1456. InitializeObjectAttributes( &Attributes,
  1457. &UnicodeString,
  1458. OBJ_CASE_INSENSITIVE,
  1459. NULL,
  1460. NULL );
  1461. NtStatus = NtCreateFile( &LocalHandle,
  1462. MAXIMUM_ALLOWED,
  1463. &Attributes,
  1464. &IoStatusBlock,
  1465. NULL, // allocation size
  1466. FILE_ATTRIBUTE_NORMAL,
  1467. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1468. FILE_OPEN_IF,
  1469. 0,
  1470. NULL, // no EAs
  1471. 0 );
  1472. if( !NT_SUCCESS(NtStatus) ) {
  1473. LeaveCriticalSection( &NlGlobalTransportCritSect );
  1474. NlPrint(( NL_CRITICAL, "NlFlushNetbiosCacheName: NtCreateFile failed 0x%lx\n",
  1475. NtStatus ));
  1476. return NtStatus;
  1477. }
  1478. Transport->DeviceHandle = LocalHandle;
  1479. }
  1480. LeaveCriticalSection( &NlGlobalTransportCritSect );
  1481. //
  1482. // Now form the name to flush
  1483. //
  1484. // Convert to upper case, blank pad to the right
  1485. // and put the appropriate Extension at the end
  1486. //
  1487. RtlFillMemory( &NameToBeFlushed, NETBIOS_NAMESIZE, ' ' );
  1488. NtStatus = RtlUpcaseUnicodeToOemN( NameToBeFlushed,
  1489. NETBIOS_NAMESIZE - 1, // Maximum for resulting string size
  1490. NULL, // Don't care about the resulting string size
  1491. (LPWSTR)NetbiosDomainName,
  1492. wcslen(NetbiosDomainName)*sizeof(WCHAR) );
  1493. if ( !NT_SUCCESS(NtStatus) ) {
  1494. NlPrint(( NL_CRITICAL, "NlFlushNetbiosCacheName: RtlUpcaseUnicodeToOemN failed 0x%lx\n",
  1495. NtStatus ));
  1496. return NtStatus;
  1497. }
  1498. //
  1499. // Set the appropriate extention
  1500. //
  1501. NameToBeFlushed[NETBIOS_NAMESIZE-1] = Extention;
  1502. //
  1503. // Finally flush the name from the cache
  1504. //
  1505. NtStatus = NtDeviceIoControlFile(
  1506. Transport->DeviceHandle, // Handle
  1507. NULL, // Event
  1508. NULL, // ApcRoutine
  1509. NULL, // ApcContext
  1510. &IoStatusBlock, // IoStatusBlock
  1511. IOCTL_NETBT_REMOVE_FROM_REMOTE_TABLE, // IoControlCode
  1512. NameToBeFlushed, // InputBuffer
  1513. sizeof(NameToBeFlushed), // InputBufferSize
  1514. NULL, // OutputBuffer
  1515. 0 ); // OutputBufferSize
  1516. //
  1517. // STATUS_RESOURCE_NAME_NOT_FOUND just means that the name was not in the cache
  1518. //
  1519. if ( !NT_SUCCESS(NtStatus) && NtStatus != STATUS_RESOURCE_NAME_NOT_FOUND ) {
  1520. NlPrint(( NL_CRITICAL, "NlFlushNetbiosCacheName: NtDeviceIoControlFile failed 0x%lx\n",
  1521. NtStatus ));
  1522. }
  1523. return NtStatus;
  1524. }
  1525. NTSTATUS
  1526. NlBrowserSendDatagram(
  1527. IN PVOID ContextDomainInfo,
  1528. IN ULONG IpAddress,
  1529. IN LPWSTR UnicodeDestinationName,
  1530. IN DGRECEIVER_NAME_TYPE NameType,
  1531. IN LPWSTR TransportName,
  1532. IN LPSTR OemMailslotName,
  1533. IN PVOID Buffer,
  1534. IN ULONG BufferSize,
  1535. IN BOOL SendSynchronously,
  1536. IN OUT PBOOL FlushNameOnOneIpTransport OPTIONAL
  1537. )
  1538. /*++
  1539. Routine Description:
  1540. Send the specified mailslot message to the specified mailslot on the
  1541. specified server on the specified transport..
  1542. Arguments:
  1543. DomainInfo - Hosted domain sending the datagram
  1544. IpAddress - IpAddress of the machine to send the message to.
  1545. If zero, UnicodeDestinationName must be specified.
  1546. If ALL_IP_TRANSPORTS, UnicodeDestination must be specified but the datagram
  1547. will only be sent on IP transports.
  1548. UnicodeDestinationName -- Name of the server to send to.
  1549. NameType -- Type of name represented by UnicodeDestinationName.
  1550. TransportName -- Name of the transport to send on.
  1551. Use NULL to send on all transports.
  1552. OemMailslotName -- Name of the mailslot to send to.
  1553. Buffer -- Specifies a pointer to the mailslot message to send.
  1554. BufferSize -- Size in bytes of the mailslot message
  1555. SendSynchronously -- If TRUE, the send will happen syncronously (i.e. the
  1556. send will not return until the network I/O completes). Otherwise, the
  1557. send will happen asynchronously (i.e. it will be queued for processing).
  1558. FlushNameOnOneIpTransport -- Used only if we send on all transports (i.e.
  1559. TransportName is NULL), otherwise ignored. If TRUE, the name specified
  1560. by UnicodeDestinationName will be flushed on one of the available IP
  1561. enabled transports prior to sending the datagram. On return, set to
  1562. FALSE if the name has been successfully flushed or the name was not
  1563. found in the cache.
  1564. Return Value:
  1565. Status of the operation.
  1566. STATUS_NETWORK_UNREACHABLE: Cannot write to network.
  1567. --*/
  1568. {
  1569. PLMDR_REQUEST_PACKET RequestPacket = NULL;
  1570. PDOMAIN_INFO DomainInfo = (PDOMAIN_INFO) ContextDomainInfo;
  1571. DWORD OemMailslotNameSize;
  1572. DWORD TransportNameSize;
  1573. DWORD DestinationNameSize;
  1574. NTSTATUS Status;
  1575. LPBYTE Where;
  1576. //
  1577. // If the transport isn't specified,
  1578. // send on all transports.
  1579. //
  1580. if ( TransportName == NULL ) {
  1581. ULONG i;
  1582. PLIST_ENTRY ListEntry;
  1583. NTSTATUS SavedStatus = STATUS_NETWORK_UNREACHABLE;
  1584. ULONG TransportCount = 0;
  1585. ULONG BadNetPathCount = 0;
  1586. //
  1587. // Send on all transports.
  1588. //
  1589. EnterCriticalSection( &NlGlobalTransportCritSect );
  1590. for ( ListEntry = NlGlobalTransportList.Flink ;
  1591. ListEntry != &NlGlobalTransportList ;
  1592. ListEntry = ListEntry->Flink) {
  1593. PNL_TRANSPORT TransportEntry;
  1594. TransportEntry = CONTAINING_RECORD( ListEntry, NL_TRANSPORT, Next );
  1595. //
  1596. // Skip deleted transports.
  1597. //
  1598. if ( !TransportEntry->TransportEnabled ) {
  1599. continue;
  1600. }
  1601. //
  1602. // Skip direct host IPX transport unless sending to a particular
  1603. // machine.
  1604. //
  1605. if ( TransportEntry->DirectHostIpx &&
  1606. NameType != ComputerName ) {
  1607. continue;
  1608. }
  1609. //
  1610. // Skip non-IP transports if sending to an IP address.
  1611. //
  1612. if ( IpAddress != 0 &&
  1613. TransportEntry->IpAddress == 0 ) {
  1614. continue;
  1615. }
  1616. //
  1617. // Leave the critical section before sending the datagram
  1618. // because NetBt now doesn't return from the datagram send
  1619. // until after the name lookup completes. So, it can take
  1620. // a considerable amount of time for the datagram send to
  1621. // return to us.
  1622. //
  1623. LeaveCriticalSection( &NlGlobalTransportCritSect );
  1624. //
  1625. // If this is IP transport, flush the name if requested
  1626. //
  1627. if ( FlushNameOnOneIpTransport != NULL &&
  1628. *FlushNameOnOneIpTransport &&
  1629. TransportEntry->IsIpTransport ) {
  1630. NTSTATUS TmpStatus;
  1631. CHAR Extention;
  1632. if ( NameType == ComputerName ) {
  1633. Extention = 0x00;
  1634. } else if ( NameType == DomainName ) {
  1635. Extention = 0x1C;
  1636. } else if ( NameType == PrimaryDomainBrowser ) {
  1637. Extention = 0x1B;
  1638. } else {
  1639. NlAssert( !"[NETLOGON] Unexpected name type passed to NlBrowserSendDatagram" );
  1640. }
  1641. TmpStatus = NlFlushNetbiosCacheName( UnicodeDestinationName,
  1642. Extention,
  1643. TransportEntry );
  1644. //
  1645. // If we successfully flushed the name or the name is not in the cache,
  1646. // indicate that the name has been flushed
  1647. //
  1648. if ( NT_SUCCESS(TmpStatus) || TmpStatus == STATUS_RESOURCE_NAME_NOT_FOUND ) {
  1649. *FlushNameOnOneIpTransport = FALSE;
  1650. }
  1651. }
  1652. Status = NlBrowserSendDatagram(
  1653. DomainInfo,
  1654. IpAddress,
  1655. UnicodeDestinationName,
  1656. NameType,
  1657. TransportEntry->TransportName,
  1658. OemMailslotName,
  1659. Buffer,
  1660. BufferSize,
  1661. SendSynchronously,
  1662. FlushNameOnOneIpTransport );
  1663. EnterCriticalSection( &NlGlobalTransportCritSect );
  1664. //
  1665. // Since a TransportEntry is never removed from the global
  1666. // transport list (it can only become marked as disabled
  1667. // during the time when we had the crit sect released),
  1668. // we should be able to follow its link to the next entry in
  1669. // the global list on the next iteration of the loop. The
  1670. // only problem can occur when the service was said to terminate
  1671. // and NlTransportClose was called to free up the global list.
  1672. // In this case NlGlobalTerminate is set to TRUE so we can
  1673. // successfully return from this routine.
  1674. //
  1675. if ( NlGlobalTerminate ) {
  1676. LeaveCriticalSection( &NlGlobalTransportCritSect );
  1677. Status = STATUS_SUCCESS;
  1678. goto Cleanup;
  1679. }
  1680. TransportCount ++;
  1681. if ( NT_SUCCESS(Status) ) {
  1682. // If any transport works, we've been successful
  1683. SavedStatus = STATUS_SUCCESS;
  1684. } else if ( Status == STATUS_BAD_NETWORK_PATH ) {
  1685. // Count the number of transports that couldn't resolve the name
  1686. BadNetPathCount ++;
  1687. } else {
  1688. // Remember the real reason for the failure instead of the default failure status
  1689. // Remember only the first failure.
  1690. if ( SavedStatus == STATUS_NETWORK_UNREACHABLE ) {
  1691. SavedStatus = Status;
  1692. }
  1693. }
  1694. }
  1695. LeaveCriticalSection( &NlGlobalTransportCritSect );
  1696. //
  1697. // If we're returning the default status,
  1698. // and at least one transport couldn't resolved the name,
  1699. // and all transports couldn't resolve the name,
  1700. // tell the caller we couldn't resolve the name.
  1701. //
  1702. if ( SavedStatus == STATUS_NETWORK_UNREACHABLE &&
  1703. BadNetPathCount > 0 &&
  1704. TransportCount == BadNetPathCount ) {
  1705. SavedStatus = STATUS_BAD_NETWORK_PATH;
  1706. }
  1707. //
  1708. // If we have no transports available,
  1709. // tell the caller we couldn't resolve the name
  1710. //
  1711. if ( TransportCount == 0 ) {
  1712. NlPrint(( NL_CRITICAL, "NlBrowserSendDatagram: No transports available\n" ));
  1713. SavedStatus = STATUS_BAD_NETWORK_PATH;
  1714. }
  1715. return SavedStatus;
  1716. }
  1717. //
  1718. // Allocate a request packet.
  1719. //
  1720. OemMailslotNameSize = strlen(OemMailslotName) + 1;
  1721. TransportNameSize = (wcslen(TransportName) + 1) * sizeof(WCHAR);
  1722. if ( UnicodeDestinationName == NULL ) {
  1723. return STATUS_INTERNAL_ERROR;
  1724. }
  1725. DestinationNameSize = wcslen(UnicodeDestinationName) * sizeof(WCHAR);
  1726. RequestPacket = NetpMemoryAllocate(
  1727. sizeof(LMDR_REQUEST_PACKET) +
  1728. TransportNameSize +
  1729. OemMailslotNameSize +
  1730. DestinationNameSize + sizeof(WCHAR) +
  1731. DomainInfo->DomUnicodeDomainNameString.Length + sizeof(WCHAR) +
  1732. sizeof(WCHAR)) ; // For alignment
  1733. if (RequestPacket == NULL) {
  1734. Status = STATUS_NO_MEMORY;
  1735. goto Cleanup;
  1736. }
  1737. //
  1738. // Fill in the Request Packet.
  1739. //
  1740. RequestPacket->Type = Datagram;
  1741. RequestPacket->Parameters.SendDatagram.DestinationNameType = NameType;
  1742. //
  1743. // Fill in the name of the machine to send the mailslot message to.
  1744. //
  1745. RequestPacket->Parameters.SendDatagram.NameLength = DestinationNameSize;
  1746. Where = (LPBYTE) RequestPacket->Parameters.SendDatagram.Name;
  1747. RtlCopyMemory( Where, UnicodeDestinationName, DestinationNameSize );
  1748. Where += DestinationNameSize;
  1749. //
  1750. // Fill in the name of the mailslot to send to.
  1751. //
  1752. RequestPacket->Parameters.SendDatagram.MailslotNameLength =
  1753. OemMailslotNameSize;
  1754. strcpy( Where, OemMailslotName);
  1755. Where += OemMailslotNameSize;
  1756. Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
  1757. //
  1758. // Fill in the TransportName
  1759. //
  1760. wcscpy( (LPWSTR) Where, TransportName);
  1761. RtlInitUnicodeString( &RequestPacket->TransportName, (LPWSTR) Where );
  1762. Where += TransportNameSize;
  1763. //
  1764. // Copy the hosted domain name to the request packet.
  1765. //
  1766. wcscpy( (LPWSTR)Where,
  1767. DomainInfo->DomUnicodeDomainNameString.Buffer );
  1768. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName,
  1769. (LPWSTR)Where );
  1770. Where += DomainInfo->DomUnicodeDomainNameString.Length + sizeof(WCHAR);
  1771. //
  1772. // Send the request to the browser.
  1773. //
  1774. Status = NlBrowserDeviceIoControl(
  1775. NlGlobalMailslotDesc->BrowserHandle,
  1776. SendSynchronously ?
  1777. IOCTL_LMDR_WRITE_MAILSLOT :
  1778. IOCTL_LMDR_WRITE_MAILSLOT_ASYNC,
  1779. RequestPacket,
  1780. (ULONG)(Where - (LPBYTE)RequestPacket),
  1781. Buffer,
  1782. BufferSize );
  1783. //
  1784. // Free locally used resources.
  1785. //
  1786. Cleanup:
  1787. if ( RequestPacket != NULL ) {
  1788. NetpMemoryFree( RequestPacket );
  1789. }
  1790. NlpDumpBuffer( NL_MAILSLOT_TEXT, Buffer, BufferSize );
  1791. // NlPrint(( NL_MAILSLOT, "Transport %ws 0x%lx\n", TransportName, Status ));
  1792. return Status;
  1793. }
  1794. NTSTATUS
  1795. NlBrowserSendDatagramA(
  1796. IN PDOMAIN_INFO DomainInfo,
  1797. IN ULONG IpAddress,
  1798. IN LPSTR OemServerName,
  1799. IN DGRECEIVER_NAME_TYPE NameType,
  1800. IN LPWSTR TransportName,
  1801. IN LPSTR OemMailslotName,
  1802. IN PVOID Buffer,
  1803. IN ULONG BufferSize
  1804. )
  1805. /*++
  1806. Routine Description:
  1807. Send asynchronously the specified mailslot message to the specified
  1808. mailslot on the specified server on the specified transport.
  1809. Arguments:
  1810. DomainInfo - Hosted domain sending the datagram
  1811. IpAddress - IpAddress of the machine to send the message to.
  1812. If zero, OemServerName must be specified.
  1813. OemServerName -- Name of the server to send to.
  1814. NameType -- Type of name represented by OemServerName.
  1815. TransportName -- Name of the transport to send on.
  1816. Use NULL to send on all transports.
  1817. OemMailslotName -- Name of the mailslot to send to.
  1818. Buffer -- Specifies a pointer to the mailslot message to send.
  1819. BufferSize -- Size in bytes of the mailslot message
  1820. Return Value:
  1821. Status of the operation.
  1822. --*/
  1823. {
  1824. NET_API_STATUS NetStatus;
  1825. WCHAR UnicodeDestinationName[CNLEN+1];
  1826. //
  1827. // Convert DestinationName to unicode
  1828. //
  1829. NetStatus = NetpNCopyStrToWStr(
  1830. UnicodeDestinationName,
  1831. OemServerName,
  1832. CNLEN );
  1833. if ( NetStatus != NERR_Success ) {
  1834. return NetpApiStatusToNtStatus( NetStatus );
  1835. }
  1836. UnicodeDestinationName[CNLEN] = L'\0';
  1837. //
  1838. // Pass the request to the function taking unicode destination name.
  1839. //
  1840. return NlBrowserSendDatagram(
  1841. DomainInfo,
  1842. IpAddress,
  1843. UnicodeDestinationName,
  1844. NameType,
  1845. TransportName,
  1846. OemMailslotName,
  1847. Buffer,
  1848. BufferSize,
  1849. FALSE, // send synchronously ?
  1850. NULL ); // Don't flush Netbios cache
  1851. }
  1852. VOID
  1853. NlMailslotPostRead(
  1854. IN BOOLEAN IgnoreDuplicatesOfPreviousMessage
  1855. )
  1856. /*++
  1857. Routine Description:
  1858. Post a read on the mailslot if one isn't already posted.
  1859. Arguments:
  1860. IgnoreDuplicatesOfPreviousMessage - TRUE to indicate that the next
  1861. message read should be ignored if it is a duplicate of the previous
  1862. message.
  1863. Return Value:
  1864. TRUE -- iff successful.
  1865. --*/
  1866. {
  1867. NET_API_STATUS WinStatus;
  1868. ULONG LocalBytesRead;
  1869. //
  1870. // If a read is already pending,
  1871. // immediately return to caller.
  1872. //
  1873. if ( NlGlobalMailslotDesc->ReadPending ) {
  1874. return;
  1875. }
  1876. //
  1877. // Decide which buffer to read into.
  1878. //
  1879. // Switch back and forth so we always have the current buffer and the
  1880. // previous buffer.
  1881. //
  1882. if ( IgnoreDuplicatesOfPreviousMessage ) {
  1883. NlGlobalMailslotDesc->PreviousMessage = NlGlobalMailslotDesc->CurrentMessage;
  1884. if ( NlGlobalMailslotDesc->CurrentMessage >= NlGlobalMailslotDesc->Message2 ) {
  1885. NlGlobalMailslotDesc->CurrentMessage =
  1886. ROUND_UP_POINTER( NlGlobalMailslotDesc->Message1, ALIGN_WORST);
  1887. } else {
  1888. NlGlobalMailslotDesc->CurrentMessage =
  1889. ROUND_UP_POINTER( NlGlobalMailslotDesc->Message2, ALIGN_WORST);
  1890. }
  1891. //
  1892. // If duplicates of the previous message need not be ignored,
  1893. // indicate so.
  1894. // Don't bother switching the buffer pointers.
  1895. //
  1896. } else {
  1897. NlGlobalMailslotDesc->PreviousMessage = NULL;
  1898. }
  1899. //
  1900. // Post an overlapped read to the mailslot.
  1901. //
  1902. RtlZeroMemory( &NlGlobalMailslotDesc->Overlapped,
  1903. sizeof(NlGlobalMailslotDesc->Overlapped) );
  1904. NlGlobalMailslotDesc->Overlapped.hEvent = NlGlobalMailslotDesc->BrowserReadEvent;
  1905. if ( !DeviceIoControl(
  1906. NlGlobalMailslotDesc->BrowserHandle,
  1907. IOCTL_LMDR_NETLOGON_MAILSLOT_READ,
  1908. NULL,
  1909. 0,
  1910. NlGlobalMailslotDesc->CurrentMessage,
  1911. MAILSLOT_MESSAGE_SIZE,
  1912. &LocalBytesRead,
  1913. &NlGlobalMailslotDesc->Overlapped )) {
  1914. WinStatus = GetLastError();
  1915. //
  1916. // On error, wait a second before returning. This ensures we don't
  1917. // consume the system in an infinite loop. We don't shutdown netlogon
  1918. // because the error might be a temporary low memory condition.
  1919. //
  1920. if( WinStatus != ERROR_IO_PENDING ) {
  1921. LPWSTR MsgStrings[1];
  1922. NlPrint((NL_CRITICAL,
  1923. "Error in reading mailslot message from browser"
  1924. ". WinStatus = %ld\n",
  1925. WinStatus ));
  1926. MsgStrings[0] = (LPWSTR) ULongToPtr( WinStatus );
  1927. NlpWriteEventlog( NELOG_NetlogonFailedToReadMailslot,
  1928. EVENTLOG_WARNING_TYPE,
  1929. (LPBYTE)&WinStatus,
  1930. sizeof(WinStatus),
  1931. MsgStrings,
  1932. 1 | NETP_LAST_MESSAGE_IS_NETSTATUS );
  1933. Sleep( 1000 );
  1934. } else {
  1935. NlGlobalMailslotDesc->ReadPending = TRUE;
  1936. }
  1937. } else {
  1938. NlGlobalMailslotDesc->ReadPending = TRUE;
  1939. }
  1940. return;
  1941. }
  1942. BOOL
  1943. NlMailslotOverlappedResult(
  1944. OUT LPBYTE *Message,
  1945. OUT PULONG BytesRead,
  1946. OUT LPWSTR *TransportName,
  1947. OUT PNL_TRANSPORT *Transport,
  1948. OUT PSOCKADDR *ClientSockAddr,
  1949. OUT LPWSTR *DestinationName,
  1950. OUT PBOOLEAN IgnoreDuplicatesOfPreviousMessage,
  1951. OUT PNETLOGON_PNP_OPCODE NlPnpOpcode
  1952. )
  1953. /*++
  1954. Routine Description:
  1955. Get the overlapped result of a previous mailslot read.
  1956. Arguments:
  1957. Message - Returns a pointer to the buffer containing the message
  1958. BytesRead - Returns the number of bytes read into the buffer
  1959. TransportName - Returns a pointer to the name of the transport the message
  1960. was received on.
  1961. Transport - Returns a pointer to the Transport structure if this is a
  1962. mailslot message.
  1963. ClientSockAddr - Returns a pointer to the SockAddr of the client that
  1964. sent the message.
  1965. Returns NULL if transport isn't running IP.
  1966. DestinationName - Returns a pointer to the name of the server or domain
  1967. the message was sent to.
  1968. IgnoreDuplicatesOfPreviousMessage - Indicates that duplicates of the
  1969. previous message are to be ignored.
  1970. NpPnpOpcode - Returns the PNP opcode if this is a PNP operation.
  1971. Returns NlPnpMailslotMessage if this is a mailslot message.
  1972. Return Value:
  1973. TRUE -- iff successful.
  1974. --*/
  1975. {
  1976. NET_API_STATUS WinStatus;
  1977. ULONG LocalBytesRead;
  1978. PNETLOGON_MAILSLOT NetlogonMailslot;
  1979. //
  1980. // Default to not ignoring duplicate messages.
  1981. // (Only ignore duplicates if a message has been properly processed.)
  1982. *IgnoreDuplicatesOfPreviousMessage = FALSE;
  1983. //
  1984. // By default, assume a mailslot message is available.
  1985. *NlPnpOpcode = NlPnpMailslotMessage;
  1986. //
  1987. // Always post another read regardless of the success or failure of
  1988. // GetOverlappedResult.
  1989. // We don't know the failure mode of GetOverlappedResult, so we don't
  1990. // know in the failure case if we're discarding a mailslot message.
  1991. // But we do know that there is no read pending, so make sure we
  1992. // issue another one.
  1993. //
  1994. NlGlobalMailslotDesc->ReadPending = FALSE; // no read pending anymore
  1995. //
  1996. // Get the result of the last read
  1997. //
  1998. if( !GetOverlappedResult( NlGlobalMailslotDesc->BrowserHandle,
  1999. &NlGlobalMailslotDesc->Overlapped,
  2000. &LocalBytesRead,
  2001. TRUE) ) { // wait for the read to complete.
  2002. LPWSTR MsgStrings[1];
  2003. // On error, wait a second before returning. This ensures we don't
  2004. // consume the system in an infinite loop. We don't shutdown netlogon
  2005. // because the error might be a temporary low memory condition.
  2006. //
  2007. WinStatus = GetLastError();
  2008. NlPrint((NL_CRITICAL,
  2009. "Error in GetOverlappedResult on mailslot read"
  2010. ". WinStatus = %ld\n",
  2011. WinStatus ));
  2012. MsgStrings[0] = (LPWSTR) ULongToPtr( WinStatus );
  2013. NlpWriteEventlog( NELOG_NetlogonFailedToReadMailslot,
  2014. EVENTLOG_WARNING_TYPE,
  2015. (LPBYTE)&WinStatus,
  2016. sizeof(WinStatus),
  2017. MsgStrings,
  2018. 1 | NETP_LAST_MESSAGE_IS_NETSTATUS );
  2019. Sleep( 1000 );
  2020. return FALSE;
  2021. }
  2022. //
  2023. // On success,
  2024. // Return the mailslot message to the caller.
  2025. NetlogonMailslot = (PNETLOGON_MAILSLOT) NlGlobalMailslotDesc->CurrentMessage;
  2026. //
  2027. // Return pointers into the buffer returned by the browser
  2028. //
  2029. *Message = &NlGlobalMailslotDesc->CurrentMessage[
  2030. NetlogonMailslot->MailslotMessageOffset];
  2031. *TransportName = (LPWSTR) &NlGlobalMailslotDesc->CurrentMessage[
  2032. NetlogonMailslot->TransportNameOffset];
  2033. if ( NetlogonMailslot->ClientSockAddrSize == 0 ) {
  2034. *ClientSockAddr = NULL;
  2035. } else {
  2036. *ClientSockAddr = (PSOCKADDR) &NlGlobalMailslotDesc->CurrentMessage[
  2037. NetlogonMailslot->ClientSockAddrOffset];
  2038. }
  2039. //
  2040. // If this is a PNP notification,
  2041. // simply return the opcode and the transport name.
  2042. //
  2043. if ( NetlogonMailslot->MailslotNameSize == 0 ) {
  2044. *NlPnpOpcode = NetlogonMailslot->MailslotNameOffset;
  2045. *Message = NULL;
  2046. *BytesRead = 0;
  2047. *DestinationName = NULL;
  2048. *Transport = NULL;
  2049. NlPrint(( NL_MAILSLOT_TEXT,
  2050. "Received PNP opcode 0x%x on transport: %ws\n",
  2051. *NlPnpOpcode,
  2052. *TransportName ));
  2053. //
  2054. // If this is a mailslot message,
  2055. // return the message to the caller.
  2056. //
  2057. } else {
  2058. *BytesRead = NetlogonMailslot->MailslotMessageSize;
  2059. *DestinationName = (LPWSTR) &NlGlobalMailslotDesc->CurrentMessage[
  2060. NetlogonMailslot->DestinationNameOffset];
  2061. //
  2062. // Determine the transport the request came in on.
  2063. //
  2064. *Transport = NlTransportLookupTransportName( *TransportName );
  2065. if ( *Transport == NULL ) {
  2066. NlPrint((NL_CRITICAL,
  2067. "%ws: Received message for this unsupported transport\n",
  2068. *TransportName ));
  2069. return FALSE;
  2070. }
  2071. //
  2072. // Determine if we can discard an ancient or duplicate message
  2073. //
  2074. // Only discard messages that are either expensive to process on this
  2075. // machine or generate excessive traffic to respond to. Don't discard
  2076. // messages that we've worked hard to get (e.g., discovery responses).
  2077. //
  2078. switch ( ((PNETLOGON_LOGON_QUERY)*Message)->Opcode) {
  2079. case LOGON_REQUEST:
  2080. case LOGON_SAM_LOGON_REQUEST:
  2081. case LOGON_PRIMARY_QUERY:
  2082. //
  2083. // If the message is too old,
  2084. // discard it.
  2085. //
  2086. if ( NlTimeHasElapsedEx( &NetlogonMailslot->TimeReceived,
  2087. &NlGlobalParameters.MailslotMessageTimeout_100ns,
  2088. NULL )) {
  2089. #if NETLOGONDBG
  2090. NlPrint(( NL_MAILSLOT,
  2091. "%ws: Received '%s' message on %ws:"
  2092. " (Discarded as too old.)\n",
  2093. *DestinationName,
  2094. NlMailslotOpcode(((PNETLOGON_LOGON_QUERY)*Message)->Opcode),
  2095. *TransportName ));
  2096. #endif // NETLOGONDBG
  2097. return FALSE;
  2098. }
  2099. //
  2100. // If the previous message was recent,
  2101. // and this message is identical to it,
  2102. // discard the current message.
  2103. //
  2104. #ifdef notdef
  2105. NlPrint(( NL_MAILSLOT, "%ws: test prev\n", *DestinationName ));
  2106. #endif // notdef
  2107. if ( NlGlobalMailslotDesc->PreviousMessage != NULL ) {
  2108. PNETLOGON_MAILSLOT PreviousNetlogonMailslot;
  2109. PreviousNetlogonMailslot = (PNETLOGON_MAILSLOT)
  2110. NlGlobalMailslotDesc->PreviousMessage;
  2111. #ifdef notdef
  2112. NlPrint(( NL_MAILSLOT, "%ws: test time\n", *DestinationName ));
  2113. #endif // notdef
  2114. // ??: Compare source netbios name?
  2115. if ( (PreviousNetlogonMailslot->TimeReceived.QuadPart +
  2116. NlGlobalParameters.MailslotDuplicateTimeout_100ns.QuadPart >
  2117. NetlogonMailslot->TimeReceived.QuadPart) ) {
  2118. #ifdef notdef
  2119. NlPrint(( NL_MAILSLOT, "%ws: test message\n", *DestinationName ));
  2120. #endif // notdef
  2121. if ( (PreviousNetlogonMailslot->MailslotMessageSize ==
  2122. NetlogonMailslot->MailslotMessageSize) &&
  2123. RtlEqualMemory(
  2124. &NlGlobalMailslotDesc->CurrentMessage[
  2125. NetlogonMailslot->MailslotMessageOffset],
  2126. &NlGlobalMailslotDesc->PreviousMessage[
  2127. PreviousNetlogonMailslot->MailslotMessageOffset],
  2128. NetlogonMailslot->MailslotMessageSize ) ) {
  2129. //
  2130. // Ensure the next comparison is to the timestamp of the
  2131. // message we actually responded to.
  2132. //
  2133. NetlogonMailslot->TimeReceived =
  2134. PreviousNetlogonMailslot->TimeReceived;
  2135. NlPrint(( NL_MAILSLOT,
  2136. "%ws: Received '%s' message on %ws:"
  2137. " (Discarded as duplicate of previous.)\n",
  2138. *DestinationName,
  2139. NlMailslotOpcode(((PNETLOGON_LOGON_QUERY)*Message)->Opcode),
  2140. *TransportName ));
  2141. *IgnoreDuplicatesOfPreviousMessage = TRUE;
  2142. return FALSE;
  2143. }
  2144. }
  2145. }
  2146. //
  2147. // If this isn't an IP transport,
  2148. // and if the caller explicitly wanted one,
  2149. // discard the message.
  2150. //
  2151. // NT 5 only sends the query on IP when netlogon is running.
  2152. // When Netlogon isn't running, the query is sent on all transports
  2153. // bound to the redir. Since this DC ignores duplicate messages,
  2154. // we want to avoid responding to the non-IP requests or we'll
  2155. // ignore the IP query as being a duplicate of this one.
  2156. //
  2157. // WIN 98 with the Active Directory service pack also sets this bit
  2158. // and sends on all transports.
  2159. //
  2160. if ( !(*Transport)->IsIpTransport ) {
  2161. DWORD Version;
  2162. DWORD VersionFlags;
  2163. DWORD LocalBytesRead;
  2164. LocalBytesRead = *BytesRead;
  2165. Version = NetpLogonGetMessageVersion( *Message,
  2166. &LocalBytesRead,
  2167. &VersionFlags );
  2168. if ( VersionFlags & NETLOGON_NT_VERSION_IP ) {
  2169. NlPrint(( NL_MAILSLOT,
  2170. "%ws: Received '%s' message on %ws:"
  2171. " (Caller wants response on IP transport.)\n",
  2172. *DestinationName,
  2173. NlMailslotOpcode(((PNETLOGON_LOGON_QUERY)*Message)->Opcode),
  2174. *TransportName ));
  2175. return FALSE;
  2176. }
  2177. }
  2178. }
  2179. NlPrint(( NL_MAILSLOT,
  2180. "%ws: Received '%s' message on %ws\n",
  2181. *DestinationName,
  2182. NlMailslotOpcode(((PNETLOGON_LOGON_QUERY)*Message)->Opcode),
  2183. *TransportName ));
  2184. NlpDumpBuffer(NL_MAILSLOT_TEXT, *Message, *BytesRead);
  2185. }
  2186. return TRUE;
  2187. }
  2188. NET_API_STATUS
  2189. NlServerComputerNameAdd(
  2190. IN LPWSTR HostedDomainName,
  2191. IN LPWSTR HostedServerName
  2192. )
  2193. /*++
  2194. Routine Description:
  2195. This routine causes the SMB server to respond to requests on HostedServerName
  2196. and to announce this servername as being a member of HostedDomainName.
  2197. This code was stolen from NetServerComputerNameAdd. It is different from that
  2198. API in the following ways:
  2199. 1) It only works locally.
  2200. 2) HostedDomainName is not optional.
  2201. 3) Failure to add the name on any transport fails the routine
  2202. Arguments:
  2203. HostedServerName --A pointer to the ASCIIZ string containing the
  2204. name which the server should stop supporting
  2205. HostedDomainName --A pointer to the ASCIIZ string containing the
  2206. domain name the server should use when announcing the presence of
  2207. 'HostedServerName'
  2208. Return Value:
  2209. NERR_Success, or reason for failure
  2210. --*/
  2211. {
  2212. DWORD resumehandle = 0;
  2213. NET_API_STATUS retval;
  2214. DWORD entriesread, totalentries;
  2215. DWORD i, j;
  2216. UCHAR NetBiosName[ MAX_PATH ];
  2217. OEM_STRING NetBiosNameString;
  2218. UNICODE_STRING UniName;
  2219. PSERVER_TRANSPORT_INFO_1 psti1;
  2220. //
  2221. // Ensure a valid HostedServerName was passed in
  2222. //
  2223. if( HostedServerName == NULL ) {
  2224. return ERROR_INVALID_PARAMETER;
  2225. }
  2226. //
  2227. // Convert the HostedServerName to an OEM string
  2228. //
  2229. RtlInitUnicodeString( &UniName, HostedServerName );
  2230. NetBiosNameString.Buffer = (PCHAR)NetBiosName;
  2231. NetBiosNameString.MaximumLength = sizeof( NetBiosName );
  2232. (VOID) RtlUpcaseUnicodeStringToOemString(
  2233. &NetBiosNameString,
  2234. &UniName,
  2235. FALSE
  2236. );
  2237. //
  2238. // Enumerate all the transports so we can add the name and domain
  2239. // to each one.
  2240. //
  2241. retval = NetServerTransportEnum ( NULL,
  2242. 1,
  2243. (LPBYTE *)&psti1,
  2244. (DWORD)-1,
  2245. &entriesread,
  2246. &totalentries,
  2247. &resumehandle );
  2248. if( retval == NERR_Success ) {
  2249. //
  2250. // Add the new name and domain to all of the transports
  2251. //
  2252. for( i=0; i < entriesread; i++ ) {
  2253. //
  2254. // Make sure we haven't already added to this transport
  2255. //
  2256. for( j = 0; j < i; j++ ) {
  2257. if( wcscmp( psti1[j].svti1_transportname, psti1[i].svti1_transportname ) == 0 ) {
  2258. break;
  2259. }
  2260. }
  2261. if( i != j ) {
  2262. psti1[i].svti1_transportname[0] = '\0';
  2263. continue;
  2264. }
  2265. psti1[i].svti1_transportaddress = NetBiosName;
  2266. psti1[i].svti1_transportaddresslength = strlen( NetBiosName );
  2267. psti1[i].svti1_domain = HostedDomainName;
  2268. retval = NetServerTransportAddEx( NULL, 1, (LPBYTE)&psti1[ i ] );
  2269. #ifndef NWLNKIPX_WORKS
  2270. //
  2271. // ??: The SMB server doesn't allow multiple names on NWLNK IPX.
  2272. //
  2273. if ( retval == ERROR_TOO_MANY_NAMES &&
  2274. _wcsicmp( psti1[i].svti1_transportname, L"\\Device\\NwlnkIpx" ) == 0 ) {
  2275. retval = NERR_Success;
  2276. }
  2277. #endif // NWLNKIPX_WORKS
  2278. if( retval != NERR_Success ) {
  2279. NlPrint((NL_CRITICAL,
  2280. "%ws: NlServerComputerNameAdd: Cannot add %ws to SMB server on transport %ws %ld\n",
  2281. HostedDomainName,
  2282. HostedServerName,
  2283. psti1[i].svti1_transportname,
  2284. retval ));
  2285. //
  2286. // Remove any names already added.
  2287. //
  2288. for( j=0; j < i; j++ ) {
  2289. NET_API_STATUS TempStatus;
  2290. if ( psti1[j].svti1_transportname[0] == '\0' ) {
  2291. continue;
  2292. }
  2293. TempStatus = NetServerTransportDel( NULL, 1, (LPBYTE)&psti1[ j ] );
  2294. NlPrint((NL_CRITICAL,
  2295. "%ws: NlServerComputerNameAdd: Cannot remove %ws to SMB server on transport %ws %ld\n",
  2296. HostedDomainName,
  2297. HostedServerName,
  2298. psti1[i].svti1_transportname,
  2299. TempStatus ));
  2300. }
  2301. break;
  2302. }
  2303. }
  2304. MIDL_user_free( psti1 );
  2305. }
  2306. return retval;
  2307. }