Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

981 lines
29 KiB

  1. //++
  2. //
  3. // Copyright (C) Microsoft Corporation, 1987 - 1999
  4. //
  5. // Module Name:
  6. //
  7. // browser.c
  8. //
  9. // Abstract:
  10. //
  11. // Queries into network drivers
  12. //
  13. // Author:
  14. //
  15. // Anilth - 4-20-1998
  16. //
  17. // Environment:
  18. //
  19. // User mode only.
  20. // Contains NT-specific code.
  21. //
  22. // Revision History:
  23. //
  24. //--
  25. #include "precomp.h"
  26. #include "malloc.h"
  27. #include "nbtutil.h"
  28. NET_API_STATUS GetBrowserTransportList(OUT PLMDR_TRANSPORT_LIST *TransportList);
  29. //$review (nsun) there is a recursive calling of this function
  30. NTSTATUS
  31. NettestBrowserSendDatagram(
  32. IN PLIST_ENTRY listNetbtTransports,
  33. IN PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo,
  34. IN PVOID ContextDomainInfo,
  35. IN ULONG IpAddress,
  36. IN LPWSTR UnicodeDestinationName,
  37. IN DGRECEIVER_NAME_TYPE NameType,
  38. IN LPWSTR pswzTransportName,
  39. IN LPSTR OemMailslotName,
  40. IN PVOID Buffer,
  41. IN ULONG BufferSize
  42. );
  43. BOOL MailslotTest(NETDIAG_PARAMS* pParams,
  44. IN LPWSTR DestinationName,
  45. NETDIAG_RESULT* pResults);
  46. BOOL
  47. BrowserTest(
  48. NETDIAG_PARAMS* pParams,
  49. NETDIAG_RESULT* pResults
  50. )
  51. /*++
  52. Routine Description:
  53. Determine the machines role and membership.
  54. Arguments:
  55. None.
  56. Return Value:
  57. TRUE: Test suceeded.
  58. FALSE: Test failed
  59. --*/
  60. {
  61. NET_API_STATUS NetStatus;
  62. HRESULT hrRetVal = S_OK;
  63. BOOL BrowserIsUp = TRUE;
  64. BOOL RedirIsUp = TRUE;
  65. PLMDR_TRANSPORT_LIST TransportList = NULL;
  66. PLMDR_TRANSPORT_LIST TransportEntry;
  67. LONG NetbtTransportCount;
  68. LONG RealNetbtTransportCount;
  69. PNETBT_TRANSPORT NetbtTransport;
  70. BOOL PrintIt;
  71. PWKSTA_TRANSPORT_INFO_0 pWti0 = NULL;
  72. DWORD EntriesRead;
  73. DWORD TotalEntries;
  74. DWORD i;
  75. WCHAR DestinationName[MAX_PATH+1];
  76. BOOL MailslotTested = FALSE;
  77. PTESTED_DOMAIN TestedDomain;
  78. PLIST_ENTRY ListEntry;
  79. USES_CONVERSION;
  80. PrintStatusMessage( pParams, 4, IDS_BROWSER_STATUS_MSG );
  81. pResults->Browser.fPerformed = TRUE;
  82. InitializeListHead( &pResults->Browser.lmsgOutput );
  83. //
  84. // Ensure the workstation service is running.
  85. //
  86. NetStatus = IsServiceStarted( _T("LanmanWorkstation") );
  87. if ( NetStatus != NO_ERROR )
  88. {
  89. //IDS_BROWSER_13001 " [FATAL] Workstation service is not running. [%s]\n"
  90. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet,
  91. IDS_BROWSER_13001, NetStatusToString(NetStatus) );
  92. hrRetVal = S_OK;
  93. goto Cleanup;
  94. }
  95. if (!pResults->Global.fHasNbtEnabledInterface)
  96. {
  97. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose,
  98. IDS_BROWSER_NETBT_DISABLED);
  99. pResults->Browser.fPerformed = FALSE;
  100. hrRetVal = S_OK;
  101. goto Cleanup;
  102. }
  103. //
  104. // Get the transports bound to the Redir
  105. //
  106. if ( pParams->fReallyVerbose )
  107. {
  108. //IDS_BROWSER_13002 " List of transports currently bound to the Redir\n"
  109. AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_ReallyVerbose, IDS_BROWSER_13002 );
  110. }
  111. else if ( pParams->fVerbose )
  112. {
  113. //IDS_BROWSER_13003 " List of NetBt transports currently bound to the Redir\n"
  114. AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13003 );
  115. }
  116. NetStatus = NetWkstaTransportEnum(
  117. NULL,
  118. 0,
  119. (LPBYTE *)&pWti0,
  120. 0xFFFFFFFF, // MaxPreferredLength
  121. &EntriesRead,
  122. &TotalEntries,
  123. NULL ); // Optional resume handle
  124. if (NetStatus != NERR_Success)
  125. {
  126. //IDS_BROWSER_13004 " [FATAL] Unable to retrieve transport list from Redir. [%s]\n"
  127. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13004, NetStatusToString(NetStatus) );
  128. hrRetVal = S_FALSE;
  129. RedirIsUp = FALSE;
  130. }
  131. else
  132. {
  133. NetbtTransportCount = 0;
  134. RealNetbtTransportCount = 0;
  135. for ( i = 0; i < EntriesRead; i++ )
  136. {
  137. UNICODE_STRING ustrTransportName;
  138. LPTSTR pszTransportName;
  139. RtlInitUnicodeString( &ustrTransportName, (LPWSTR)pWti0[i].wkti0_transport_name );
  140. // Strip off the "\Device\" off of the beginning of
  141. // the string
  142. pszTransportName = W2T(MapGuidToServiceNameW(ustrTransportName.Buffer + 8));
  143. PrintIt = FALSE;
  144. if ( ustrTransportName.Length >= sizeof(NETBT_DEVICE_PREFIX) &&
  145. _wcsnicmp( ustrTransportName.Buffer, NETBT_DEVICE_PREFIX, (sizeof(NETBT_DEVICE_PREFIX)/sizeof(WCHAR)-1)) == 0 )
  146. {
  147. //
  148. // Determine if this Netbt transport really exists.
  149. //
  150. NetbtTransport = FindNetbtTransport( pResults, ustrTransportName.Buffer );
  151. if ( NetbtTransport == NULL )
  152. {
  153. //IDS_BROWSER_13005 " [FATAL] Transport %s is bound to the redir but is not a configured NetbtTransport."
  154. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13005, pszTransportName );
  155. hrRetVal = S_FALSE;
  156. }
  157. else
  158. {
  159. if ( NetbtTransport->Flags & BOUND_TO_REDIR )
  160. {
  161. //IDS_BROWSER_13006 " [WARNING] Transport %s is bound to redir more than once."
  162. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13006, pszTransportName );
  163. }
  164. else
  165. {
  166. NetbtTransport->Flags |= BOUND_TO_REDIR;
  167. RealNetbtTransportCount ++;
  168. }
  169. }
  170. //
  171. // Count the found transports.
  172. //
  173. NetbtTransportCount ++;
  174. if ( pParams->fVerbose ) {
  175. PrintIt = TRUE;
  176. }
  177. }
  178. //IDS_BROWSER_13007 " %s\n"
  179. AddMessageToList( &pResults->Browser.lmsgOutput, PrintIt ? Nd_Verbose : Nd_ReallyVerbose, IDS_BROWSER_13007, pszTransportName);//&ustrTransportName );
  180. }
  181. //
  182. // Ensure the redir is bound to some Netbt transports.
  183. //
  184. if ( NetbtTransportCount == 0 )
  185. {
  186. //IDS_BROWSER_13008 " [FATAL] The redir isn't bound to any NetBt transports."
  187. AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13008);
  188. hrRetVal = S_FALSE;
  189. RedirIsUp = FALSE;
  190. }
  191. else
  192. {
  193. //IDS_BROWSER_13009 " The redir is bound to %ld NetBt transport%s.\n"
  194. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose,
  195. IDS_BROWSER_13009,
  196. NetbtTransportCount,
  197. NetbtTransportCount > 1 ? "s" : "" );
  198. }
  199. //
  200. // Ensure the redir is bound to all of the Netbt transports.
  201. //
  202. if ( RealNetbtTransportCount != pResults->NetBt.cTransportCount )
  203. {
  204. //IDS_BROWSER_13010 " [FATAL] The redir is only bound to %ld of the %ld NetBt transports."
  205. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet,
  206. IDS_BROWSER_13010,
  207. RealNetbtTransportCount,
  208. pResults->NetBt.cTransportCount );
  209. hrRetVal = S_FALSE;
  210. }
  211. }
  212. //
  213. // Get the transports bound to the browser.
  214. //
  215. //IDS_BROWSER_13011 "\n"
  216. AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13011);
  217. if ( pParams->fReallyVerbose )
  218. //IDS_BROWSER_13012 " List of transports currently bound to the browser\n"
  219. AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_ReallyVerbose, IDS_BROWSER_13012 );
  220. else if ( pParams->fVerbose )
  221. //IDS_BROWSER_13013 " List of NetBt transports currently bound to the browser\n"
  222. AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13013 );
  223. NetStatus = GetBrowserTransportList(&TransportList);
  224. if (NetStatus != NERR_Success)
  225. {
  226. //IDS_BROWSER_13014 " [FATAL] Unable to retrieve transport list from browser. [%s]\n"
  227. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13014, NetStatusToString(NetStatus) );
  228. hrRetVal = S_FALSE;
  229. BrowserIsUp = FALSE;
  230. }
  231. else
  232. {
  233. TransportEntry = TransportList;
  234. NetbtTransportCount = 0;
  235. RealNetbtTransportCount = 0;
  236. while (TransportEntry != NULL)
  237. {
  238. UNICODE_STRING ustrTransportName;
  239. LPTSTR pszTransportName;
  240. ustrTransportName.Buffer = TransportEntry->TransportName;
  241. ustrTransportName.Length = (USHORT)TransportEntry->TransportNameLength;
  242. ustrTransportName.MaximumLength = (USHORT)TransportEntry->TransportNameLength;
  243. pszTransportName = W2T(MapGuidToServiceNameW(ustrTransportName.Buffer + 8));
  244. PrintIt = FALSE;
  245. if ( ustrTransportName.Length >= sizeof(NETBT_DEVICE_PREFIX) &&
  246. _wcsnicmp( ustrTransportName.Buffer, NETBT_DEVICE_PREFIX, (sizeof(NETBT_DEVICE_PREFIX)/sizeof(WCHAR)-1)) == 0 )
  247. {
  248. //
  249. // Determine if this Netbt transport really exists.
  250. //
  251. NetbtTransport = FindNetbtTransport( pResults, ustrTransportName.Buffer );
  252. if ( NetbtTransport == NULL )
  253. {
  254. //IDS_BROWSER_13015 " [FATAL] Transport %s is bound to the browser but is not a configured NetbtTransport."
  255. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13015, pszTransportName );
  256. hrRetVal = S_FALSE;
  257. }
  258. else
  259. {
  260. if ( NetbtTransport->Flags & BOUND_TO_BOWSER )
  261. {
  262. //IDS_BROWSER_13016 " [FATAL] Transport %s is bound to browser more than once."
  263. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13016, pszTransportName );
  264. hrRetVal = S_FALSE;
  265. }
  266. else
  267. {
  268. NetbtTransport->Flags |= BOUND_TO_BOWSER;
  269. RealNetbtTransportCount ++;
  270. }
  271. }
  272. //
  273. // Count the found transports.
  274. //
  275. NetbtTransportCount ++;
  276. if ( pParams->fVerbose )
  277. PrintIt = TRUE;
  278. }
  279. //IDS_BROWSER_13017 " %s\n"
  280. AddMessageToList( &pResults->Browser.lmsgOutput,
  281. PrintIt ? Nd_Verbose : Nd_ReallyVerbose,
  282. IDS_BROWSER_13017, pszTransportName );
  283. if (TransportEntry->NextEntryOffset == 0)
  284. {
  285. TransportEntry = NULL;
  286. }
  287. else
  288. {
  289. TransportEntry = (PLMDR_TRANSPORT_LIST)((PCHAR)TransportEntry+TransportEntry->NextEntryOffset);
  290. }
  291. }
  292. if ( NetbtTransportCount == 0 )
  293. {
  294. //IDS_BROWSER_13018 " [FATAL] The browser isn't bound to any NetBt transports"
  295. AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Quiet,
  296. IDS_BROWSER_13018 );
  297. hrRetVal = S_FALSE;
  298. BrowserIsUp = FALSE;
  299. }
  300. else
  301. {
  302. //IDS_BROWSER_13019 " The browser is bound to %ld NetBt transport%s.\n"
  303. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose,
  304. IDS_BROWSER_13019,
  305. NetbtTransportCount,
  306. NetbtTransportCount > 1 ? "s" : "" );
  307. }
  308. //
  309. // Ensure the browser is bound to all of the Netbt transports.
  310. //
  311. if ( RealNetbtTransportCount != pResults->NetBt.cTransportCount )
  312. {
  313. //IDS_BROWSER_13020 " [FATAL] The browser is only bound to %ld of the %ld NetBt transports."
  314. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet,
  315. IDS_BROWSER_13020,
  316. RealNetbtTransportCount,
  317. pResults->NetBt.cTransportCount );
  318. hrRetVal = FALSE;
  319. }
  320. }
  321. //
  322. // Ensure we can send mailslot messages. (DsGetDcName uses them.)
  323. //
  324. // Try sending to each of the tested domains.
  325. //
  326. for ( ListEntry = pResults->Global.listTestedDomains.Flink ;
  327. ListEntry != &pResults->Global.listTestedDomains ;
  328. ListEntry = ListEntry->Flink )
  329. {
  330. //
  331. // Only test this domain if it is has a Netbios domain name
  332. //
  333. TestedDomain = CONTAINING_RECORD( ListEntry, TESTED_DOMAIN, Next );
  334. if ( TestedDomain->NetbiosDomainName != NULL )
  335. {
  336. //
  337. // Send the message to the <DomainName>[1C] name
  338. //
  339. wcscpy( DestinationName, TestedDomain->NetbiosDomainName );
  340. wcscat( DestinationName, L"*" );
  341. if ( !MailslotTest( pParams, DestinationName, pResults ) ) {
  342. hrRetVal = S_FALSE;
  343. }
  344. else
  345. {
  346. USES_CONVERSION;
  347. //IDS_BROWSER_13021 "Mailslot test for %s passed.\n"
  348. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_ReallyVerbose, IDS_BROWSER_13021, W2CT(DestinationName));
  349. }
  350. MailslotTested = TRUE;
  351. }
  352. }
  353. //
  354. // If we still haven't tested mailslots,
  355. // test them by sending the message to our own computername.
  356. //
  357. //#ifdef notdef // crashes build 1728
  358. if ( !MailslotTested ) {
  359. wcscpy( DestinationName, pResults->Global.swzNetBiosName );
  360. if ( !MailslotTest( pParams, DestinationName, pResults ) ) {
  361. hrRetVal = S_FALSE;
  362. }
  363. MailslotTested = TRUE;
  364. }
  365. //#endif // notdef // crashes build 1728
  366. Cleanup:
  367. if ( pWti0 )
  368. {
  369. NetApiBufferFree( pWti0 );
  370. }
  371. if ( TransportList != NULL )
  372. {
  373. NetApiBufferFree(TransportList);
  374. }
  375. if ( FHrOK(hrRetVal) )
  376. {
  377. PrintStatusMessage(pParams, 0, IDS_GLOBAL_PASS_NL);
  378. }
  379. else
  380. {
  381. PrintStatusMessage(pParams, 0, IDS_GLOBAL_FAIL_NL);
  382. }
  383. pResults->Browser.hrTestResult = hrRetVal;
  384. return hrRetVal;
  385. }
  386. NET_API_STATUS
  387. GetBrowserTransportList(
  388. OUT PLMDR_TRANSPORT_LIST *TransportList
  389. )
  390. /*++
  391. Routine Description:
  392. This routine returns the list of transports bound into the browser.
  393. Arguments:
  394. OUT PLMDR_TRANSPORT_LIST *TransportList - Transport list to return.
  395. Return Value:
  396. NET_API_STATUS - NERR_Success or reason for failure.
  397. --*/
  398. {
  399. NET_API_STATUS NetStatus;
  400. HANDLE BrowserHandle;
  401. LMDR_REQUEST_PACKET RequestPacket;
  402. NetStatus = OpenBrowser(&BrowserHandle);
  403. if (NetStatus != NERR_Success) {
  404. DebugMessage2(" [FATAL] Unable to open browser driver. [%s]\n", NetStatusToString(NetStatus) );
  405. return NetStatus;
  406. }
  407. RequestPacket.Version = LMDR_REQUEST_PACKET_VERSION_DOM;
  408. RequestPacket.Type = EnumerateXports;
  409. RtlInitUnicodeString(&RequestPacket.TransportName, NULL);
  410. RtlInitUnicodeString(&RequestPacket.EmulatedDomainName, NULL);
  411. NetStatus = DeviceControlGetInfo(
  412. BrowserHandle,
  413. IOCTL_LMDR_ENUMERATE_TRANSPORTS,
  414. &RequestPacket,
  415. sizeof(RequestPacket),
  416. (PVOID *)TransportList,
  417. 0xffffffff,
  418. 4096,
  419. NULL);
  420. NtClose(BrowserHandle);
  421. return NetStatus;
  422. }
  423. BOOL
  424. MailslotTest(
  425. NETDIAG_PARAMS* pParams,
  426. IN LPWSTR DestinationName,
  427. NETDIAG_RESULT* pResults
  428. )
  429. /*++
  430. Routine Description:
  431. Ensure we can send mailslot messages.
  432. Test both via redir and browser.
  433. Don't test responses (since that really tests if the DC is up).
  434. Arguments:
  435. DestinationName - Name to send the message to
  436. Name ends in * if destination is the [1c] name.
  437. Return Value:
  438. TRUE: Test suceeded.
  439. FALSE: Test failed
  440. --*/
  441. {
  442. BOOL RetVal = TRUE;
  443. NET_API_STATUS NetStatus;
  444. NTSTATUS Status;
  445. HANDLE ResponseMailslotHandle = NULL;
  446. TCHAR ResponseMailslotName[MAX_PATH+1];
  447. WCHAR NetlogonMailslotName[MAX_PATH+1];
  448. WCHAR BrowserDestinationName[MAX_PATH+1];
  449. DWORD BrowserDestinationNameLen;
  450. DGRECEIVER_NAME_TYPE NameType;
  451. PVOID PingMessage = NULL;
  452. ULONG PingMessageSize = 0;
  453. //
  454. // Open a mailslot to get ping responses on.
  455. //
  456. //
  457. NetStatus = NetpLogonCreateRandomMailslot( ResponseMailslotName,
  458. &ResponseMailslotHandle );
  459. if (NetStatus != NO_ERROR ) {
  460. //IDS_BROWSER_13022 " [FATAL] Cannot create temp mailslot. [%s]\n"
  461. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13022, NetStatusToString(NetStatus) );
  462. RetVal = FALSE;
  463. goto Cleanup;
  464. }
  465. //
  466. // Allocate a mailslot message to send
  467. //
  468. NetStatus = NetpDcBuildPing (
  469. FALSE, // Not only PDC
  470. 0, // Retry count
  471. pResults->Global.swzNetBiosName, //replace GlobalNetbiosComputerName,
  472. NULL, // No Account name
  473. ResponseMailslotName,
  474. 0, // no AllowableAccountControlBits,
  475. NULL, // No Domain SID
  476. 0, // Not NT Version 5
  477. &PingMessage,
  478. &PingMessageSize );
  479. if ( NetStatus != NO_ERROR ) {
  480. //IDS_BROWSER_13023 " [FATAL] Cannot allocate mailslot message. [%s]\n"
  481. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13023,
  482. NetStatusToString(NetStatus) );
  483. RetVal = FALSE;
  484. goto Cleanup;
  485. }
  486. //
  487. // Build the destination mailslot name.
  488. //
  489. NetlogonMailslotName[0] = '\\';
  490. NetlogonMailslotName[1] = '\\';
  491. wcscpy(NetlogonMailslotName + 2, DestinationName );
  492. wcscat( NetlogonMailslotName, NETLOGON_LM_MAILSLOT_W );
  493. //
  494. // Send the mailslot via the redir.
  495. //
  496. NetStatus = NetpLogonWriteMailslot(
  497. NetlogonMailslotName,
  498. (PCHAR)PingMessage,
  499. PingMessageSize );
  500. if ( NetStatus != NO_ERROR ) {
  501. //IDS_BROWSER_13024 " [FATAL] Cannot send mailslot message to '%ws' via redir. [%s]\n"
  502. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13024,
  503. NetlogonMailslotName, NetStatusToString(NetStatus) );
  504. RetVal = FALSE;
  505. goto Cleanup;
  506. }
  507. //
  508. // Send the mailslot via the browser
  509. //
  510. // Avoid this test if this build has an old value for the IOCTL function
  511. // code to the browser.
  512. //
  513. if ( _ttoi(pResults->Global.pszCurrentBuildNumber) < NTBUILD_BOWSER )
  514. {
  515. if ( pParams->fReallyVerbose ) {
  516. //IDS_BROWSER_13025 " Cannot sending mailslot messages via the browser since this machine is running build %ld. [Test skipped.]\n"
  517. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13025, pResults->Global.pszCurrentBuildNumber );
  518. }
  519. }
  520. else
  521. {
  522. wcscpy( BrowserDestinationName, DestinationName );
  523. BrowserDestinationNameLen = wcslen(BrowserDestinationName);
  524. if ( BrowserDestinationName[BrowserDestinationNameLen-1] == L'*' )
  525. {
  526. BrowserDestinationName[BrowserDestinationNameLen-1] = L'\0';
  527. NameType = DomainName; // [1c] name
  528. }
  529. else
  530. {
  531. NameType = PrimaryDomain; // [00] name
  532. }
  533. Status = NettestBrowserSendDatagram(
  534. &pResults->NetBt.Transports,
  535. pResults->Global.pPrimaryDomainInfo,
  536. NULL,
  537. ALL_IP_TRANSPORTS,
  538. BrowserDestinationName,
  539. NameType,
  540. NULL, // All transports
  541. NETLOGON_LM_MAILSLOT_A,
  542. PingMessage,
  543. PingMessageSize );
  544. if ( !NT_SUCCESS(Status) )
  545. {
  546. NetStatus = NetpNtStatusToApiStatus(Status);
  547. //IDS_BROWSER_13026 " [FATAL] Cannot send mailslot message to '%ws' via browser. [%s]\n"
  548. AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13026,
  549. DestinationName, NetStatusToString(NetStatus) );
  550. RetVal = FALSE;
  551. goto Cleanup;
  552. }
  553. }
  554. Cleanup:
  555. if ( PingMessage != NULL ) {
  556. NetpMemoryFree( PingMessage );
  557. }
  558. if ( ResponseMailslotHandle != NULL ) {
  559. CloseHandle(ResponseMailslotHandle);
  560. }
  561. return RetVal;
  562. }
  563. NTSTATUS
  564. NettestBrowserSendDatagram(
  565. IN PLIST_ENTRY plistNetbtTransports,
  566. IN PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo,
  567. IN PVOID ContextDomainInfo,
  568. IN ULONG IpAddress,
  569. IN LPWSTR UnicodeDestinationName,
  570. IN DGRECEIVER_NAME_TYPE NameType,
  571. IN LPWSTR TransportName,
  572. IN LPSTR OemMailslotName,
  573. IN PVOID Buffer,
  574. IN ULONG BufferSize
  575. )
  576. /*++
  577. Routine Description:
  578. Send the specified mailslot message to the specified mailslot on the
  579. specified server on the specified transport..
  580. Arguments:
  581. DomainInfo - Hosted domain sending the datagram
  582. IpAddress - IpAddress of the machine to send the message to.
  583. If zero, UnicodeDestinationName must be specified.
  584. If ALL_IP_TRANSPORTS, UnicodeDestination must be specified but the datagram
  585. will only be sent on IP transports.
  586. UnicodeDestinationName -- Name of the server to send to.
  587. NameType -- Type of name represented by UnicodeDestinationName.
  588. TransportName -- Name of the transport to send on.
  589. Use NULL to send on all transports.
  590. OemMailslotName -- Name of the mailslot to send to.
  591. Buffer -- Specifies a pointer to the mailslot message to send.
  592. BufferSize -- Size in bytes of the mailslot message
  593. Return Value:
  594. Status of the operation.
  595. STATUS_NETWORK_UNREACHABLE: Cannot write to network.
  596. --*/
  597. {
  598. PLMDR_REQUEST_PACKET RequestPacket = NULL;
  599. NET_API_STATUS NetStatus;
  600. DWORD OemMailslotNameSize;
  601. DWORD TransportNameSize;
  602. DWORD DestinationNameSize;
  603. WCHAR IpAddressString[NL_IP_ADDRESS_LENGTH+1];
  604. ULONG Information;
  605. HANDLE BrowserHandle = NULL;
  606. NTSTATUS Status;
  607. LPBYTE Where;
  608. LONG test;
  609. //
  610. // If the transport isn't specified,
  611. // send on all transports.
  612. //
  613. if ( TransportName == NULL ) {
  614. ULONG i;
  615. PLIST_ENTRY ListEntry;
  616. NTSTATUS SavedStatus = STATUS_NETWORK_UNREACHABLE;
  617. //
  618. // Loop through the list of netbt transports finding this one.
  619. //
  620. for ( ListEntry = plistNetbtTransports->Flink ;
  621. ListEntry != plistNetbtTransports ;
  622. ListEntry = ListEntry->Flink ) {
  623. PNETBT_TRANSPORT NetbtTransport;
  624. //
  625. // If the transport names match,
  626. // return the entry
  627. //
  628. NetbtTransport = CONTAINING_RECORD( ListEntry, NETBT_TRANSPORT, Next );
  629. //
  630. // Skip deleted transports.
  631. //
  632. if ( (NetbtTransport->Flags & BOUND_TO_BOWSER) == 0 ) {
  633. continue;
  634. }
  635. Status = NettestBrowserSendDatagram(
  636. plistNetbtTransports,
  637. pPrimaryDomainInfo,
  638. ContextDomainInfo,
  639. IpAddress,
  640. UnicodeDestinationName,
  641. NameType,
  642. NetbtTransport->pswzTransportName,
  643. OemMailslotName,
  644. Buffer,
  645. BufferSize );
  646. if ( NT_SUCCESS(Status) ) {
  647. // If any transport works, we've been successful
  648. SavedStatus = STATUS_SUCCESS;
  649. } else {
  650. // Remember the real reason for the failure instead of the default failure status
  651. // Remember only the first failure.
  652. if ( SavedStatus == STATUS_NETWORK_UNREACHABLE ) {
  653. SavedStatus = Status;
  654. }
  655. }
  656. }
  657. return SavedStatus;
  658. }
  659. //
  660. // Open a handle to the browser.
  661. //
  662. NetStatus = OpenBrowser(&BrowserHandle);
  663. if (NetStatus != NERR_Success) {
  664. DebugMessage2(" [FATAL] Unable to open browser driver. [%s]\n", NetStatusToString(NetStatus));
  665. Status = NetpApiStatusToNtStatus( NetStatus );
  666. goto Cleanup;
  667. }
  668. //
  669. // Allocate a request packet.
  670. //
  671. OemMailslotNameSize = strlen(OemMailslotName) + 1;
  672. TransportNameSize = (wcslen(TransportName) + 1) * sizeof(WCHAR);
  673. if ( UnicodeDestinationName == NULL ) {
  674. return STATUS_INTERNAL_ERROR;
  675. }
  676. DestinationNameSize = wcslen(UnicodeDestinationName) * sizeof(WCHAR);
  677. RequestPacket = NetpMemoryAllocate(
  678. sizeof(LMDR_REQUEST_PACKET) +
  679. TransportNameSize +
  680. OemMailslotNameSize +
  681. DestinationNameSize + sizeof(WCHAR) +
  682. (wcslen( pPrimaryDomainInfo->DomainNameFlat ) + 1) * sizeof(WCHAR) +
  683. sizeof(WCHAR)) ; // For alignment
  684. if (RequestPacket == NULL) {
  685. Status = STATUS_NO_MEMORY;
  686. goto Cleanup;
  687. }
  688. //
  689. // Fill in the Request Packet.
  690. //
  691. RequestPacket->Type = Datagram;
  692. RequestPacket->Parameters.SendDatagram.DestinationNameType = NameType;
  693. //
  694. // Fill in the name of the machine to send the mailslot message to.
  695. //
  696. RequestPacket->Parameters.SendDatagram.NameLength = DestinationNameSize;
  697. Where = (LPBYTE) RequestPacket->Parameters.SendDatagram.Name;
  698. RtlCopyMemory( Where, UnicodeDestinationName, DestinationNameSize );
  699. Where += DestinationNameSize;
  700. //
  701. // Fill in the name of the mailslot to send to.
  702. //
  703. RequestPacket->Parameters.SendDatagram.MailslotNameLength =
  704. OemMailslotNameSize;
  705. strcpy( Where, OemMailslotName);
  706. Where += OemMailslotNameSize;
  707. Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
  708. //
  709. // Fill in the TransportName
  710. //
  711. wcscpy( (LPWSTR) Where, TransportName);
  712. RtlInitUnicodeString( &RequestPacket->TransportName, (LPWSTR) Where );
  713. Where += TransportNameSize;
  714. //
  715. // Copy the hosted domain name to the request packet.
  716. //
  717. //If the machine doesn't belong to a domain, we shouldn't get to here
  718. assert(pPrimaryDomainInfo->DomainNameFlat);
  719. if (pPrimaryDomainInfo->DomainNameFlat)
  720. {
  721. wcscpy( (LPWSTR)Where,
  722. pPrimaryDomainInfo->DomainNameFlat );
  723. RtlInitUnicodeString( &RequestPacket->EmulatedDomainName,
  724. (LPWSTR)Where );
  725. Where += (wcslen( pPrimaryDomainInfo->DomainNameFlat ) + 1) * sizeof(WCHAR);
  726. }
  727. //
  728. // Send the request to the browser.
  729. //
  730. NetStatus = BrDgReceiverIoControl(
  731. BrowserHandle,
  732. IOCTL_LMDR_WRITE_MAILSLOT,
  733. RequestPacket,
  734. (ULONG)(Where - (LPBYTE)RequestPacket),
  735. Buffer,
  736. BufferSize,
  737. &Information );
  738. if ( NetStatus != NO_ERROR ) {
  739. Status = NetpApiStatusToNtStatus( NetStatus );
  740. }
  741. //
  742. // Free locally used resources.
  743. //
  744. Cleanup:
  745. if ( BrowserHandle != NULL ) {
  746. NtClose(BrowserHandle);
  747. }
  748. if ( RequestPacket != NULL ) {
  749. NetpMemoryFree( RequestPacket );
  750. }
  751. return Status;
  752. }
  753. void BrowserGlobalPrint(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
  754. {
  755. if (pParams->fVerbose || !FHrOK(pResults->Browser.hrTestResult))
  756. {
  757. PrintNewLine(pParams, 2);
  758. PrintTestTitleResult(pParams,
  759. IDS_BROWSER_LONG,
  760. IDS_BROWSER_SHORT,
  761. pResults->Browser.fPerformed,
  762. pResults->Browser.hrTestResult,
  763. 0);
  764. }
  765. PrintMessageList(pParams, &pResults->Browser.lmsgOutput);
  766. }
  767. void BrowserPerInterfacePrint(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults, INTERFACE_RESULT *pInterfaceResults)
  768. {
  769. //no per interface results
  770. }
  771. void BrowserCleanup(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
  772. {
  773. MessageListCleanUp(&pResults->Browser.lmsgOutput);
  774. }