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.

1380 lines
36 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. WshNetbs.c
  5. Abstract:
  6. This module contains necessary routines for the Netbios
  7. Windows Sockets Helper DLL. This DLL provides the
  8. transport-specific support necessary for the Windows Sockets DLL to
  9. _access any Netbios transport.
  10. Author:
  11. David Treadwell (davidtr) 19-Jul-1992
  12. Revision History:
  13. --*/
  14. #define UNICODE
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windef.h>
  19. #include <winbase.h>
  20. #include <tdi.h>
  21. #include <winsock2.h>
  22. #include <wsahelp.h>
  23. #include <wsnetbs.h>
  24. #include <nb30.h>
  25. #include <wchar.h>
  26. #include <basetyps.h>
  27. #include <nspapi.h>
  28. #include <nspapip.h>
  29. //
  30. // Structure and variables to define the triples supported by Netbios.
  31. // The first entry of each array is considered the canonical triple for
  32. // that socket type; the other entries are synonyms for the first.
  33. //
  34. typedef struct _MAPPING_TRIPLE {
  35. INT AddressFamily;
  36. INT SocketType;
  37. INT Protocol;
  38. } MAPPING_TRIPLE, *PMAPPING_TRIPLE;
  39. MAPPING_TRIPLE VcMappingTriples[] = { AF_NETBIOS, SOCK_SEQPACKET, 0 };
  40. MAPPING_TRIPLE DgMappingTriples[] = { AF_NETBIOS, SOCK_DGRAM, 0 };
  41. //
  42. // Structure defined for holding transport (provider) information for
  43. // each Netbios transport loaded on the machine.
  44. //
  45. typedef struct _WSHNETBS_PROVIDER_INFO {
  46. UCHAR Enum;
  47. UCHAR LanaNumber;
  48. INT ProtocolNumber;
  49. PWSTR ProviderName;
  50. } WSHNETBS_PROVIDER_INFO, *PWSHNETBS_PROVIDER_INFO;
  51. PWSHNETBS_PROVIDER_INFO ProviderInfo;
  52. PVOID ProviderNames = NULL;
  53. ULONG ProviderCount;
  54. typedef struct _LANA_MAP {
  55. BOOLEAN Enum;
  56. UCHAR Lana;
  57. } LANA_MAP, *PLANA_MAP;
  58. PLANA_MAP LanaMap;
  59. //
  60. // Maintain all of the config parameters in one memory
  61. // block so we can replace it when info changes.
  62. //
  63. typedef struct _WSHNETBS_CONFIG_INFO {
  64. LONG ReferenceCount; // Reference count to keep the info for
  65. // the sockets that are already open
  66. // until they are closed
  67. UCHAR Blob[1];
  68. } WSHNETBS_CONFIG_INFO, *PWSHNETBS_CONFIG_INFO;
  69. PWSHNETBS_CONFIG_INFO ConfigInfo;
  70. #define REFERENCE_CONFIG_INFO(_info) \
  71. InterlockedIncrement (&_info->ReferenceCount)
  72. #define DEREFERENCE_CONFIG_INFO(_info) \
  73. ASSERT (_info->ReferenceCount>0); \
  74. if (InterlockedDecrement (&_info->ReferenceCount)==0) { \
  75. RtlFreeHeap( RtlProcessHeap( ), 0, _info ); \
  76. }
  77. //
  78. // Synchronize changes in configuration info
  79. //
  80. RTL_CRITICAL_SECTION ConfigInfoLock;
  81. //
  82. // Registry key and event to monitor changes in configuration info.
  83. //
  84. HKEY NetbiosKey = NULL;
  85. LARGE_INTEGER NetbiosUpdateTime = {0,0};
  86. //
  87. //
  88. // The socket context structure for this DLL. Each open Netbios socket will
  89. // have one of these context structures, which is used to maintain
  90. // information about the socket.
  91. //
  92. typedef struct _WSHNETBS_SOCKET_CONTEXT {
  93. INT AddressFamily;
  94. INT SocketType;
  95. INT Protocol;
  96. PWSHNETBS_PROVIDER_INFO Provider;
  97. PWSHNETBS_CONFIG_INFO ConfigInfo;
  98. } WSHNETBS_SOCKET_CONTEXT, *PWSHNETBS_SOCKET_CONTEXT;
  99. //
  100. // The GUID identifying this provider.
  101. //
  102. GUID NetBIOSProviderGuid = { /* 8d5f1830-c273-11cf-95c8-00805f48a192 */
  103. 0x8d5f1830,
  104. 0xc273,
  105. 0x11cf,
  106. {0x95, 0xc8, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}
  107. };
  108. INT
  109. LoadProviderInfo (
  110. VOID
  111. );
  112. BOOLEAN
  113. DllInitialize (
  114. IN PVOID DllHandle,
  115. IN ULONG Reason,
  116. IN PVOID Context OPTIONAL
  117. )
  118. {
  119. NTSTATUS status;
  120. switch ( Reason ) {
  121. case DLL_PROCESS_ATTACH:
  122. status = RtlInitializeCriticalSection (&ConfigInfoLock);
  123. if (!NT_SUCCESS (status)) {
  124. return FALSE;
  125. }
  126. //
  127. // Ignore error here, we'll retry if necessary.
  128. //
  129. LoadProviderInfo ();
  130. break;
  131. case DLL_THREAD_ATTACH:
  132. case DLL_THREAD_DETACH:
  133. break;
  134. case DLL_PROCESS_DETACH:
  135. //
  136. // If the process is terminating, do not bother to do any
  137. // resource deallocation as the system will do it automatically.
  138. //
  139. if ( Context != NULL ) {
  140. return TRUE;
  141. }
  142. if ( ConfigInfo != NULL ) {
  143. DEREFERENCE_CONFIG_INFO (ConfigInfo);
  144. ConfigInfo = NULL;
  145. }
  146. if (NetbiosKey!=NULL) {
  147. RegCloseKey (NetbiosKey);
  148. NetbiosKey = NULL;
  149. }
  150. RtlDeleteCriticalSection (&ConfigInfoLock);
  151. break;
  152. }
  153. return TRUE;
  154. } // SockInitialize
  155. INT
  156. WSHGetSockaddrType (
  157. IN PSOCKADDR Sockaddr,
  158. IN DWORD SockaddrLength,
  159. OUT PSOCKADDR_INFO SockaddrInfo
  160. )
  161. /*++
  162. Routine Description:
  163. This routine parses a sockaddr to determine the type of the
  164. machine address and endpoint address portions of the sockaddr.
  165. This is called by the winsock DLL whenever it needs to interpret
  166. a sockaddr.
  167. Arguments:
  168. Sockaddr - a pointer to the sockaddr structure to evaluate.
  169. SockaddrLength - the number of bytes in the sockaddr structure.
  170. SockaddrInfo - a pointer to a structure that will receive information
  171. about the specified sockaddr.
  172. Return Value:
  173. INT - a winsock error code indicating the status of the operation, or
  174. NO_ERROR if the operation succeeded.
  175. --*/
  176. {
  177. UNALIGNED SOCKADDR_NB *sockaddr = (PSOCKADDR_NB)Sockaddr;
  178. //
  179. // Make sure that the address family is correct.
  180. //
  181. if ( sockaddr->snb_family != AF_NETBIOS ) {
  182. return WSAEAFNOSUPPORT;
  183. }
  184. //
  185. // Make sure that the length is correct.
  186. //
  187. if ( SockaddrLength < sizeof(SOCKADDR_NB) ) {
  188. return WSAEFAULT;
  189. }
  190. //
  191. // The address passed the tests, looks like a good address.
  192. // Netbios only supports "normal" addresses.
  193. //
  194. SockaddrInfo->AddressInfo = SockaddrAddressInfoNormal;
  195. return NO_ERROR;
  196. } // WSHGetSockaddrType
  197. INT
  198. WSHGetSocketInformation (
  199. IN PVOID HelperDllSocketContext,
  200. IN SOCKET SocketHandle,
  201. IN HANDLE TdiAddressObjectHandle,
  202. IN HANDLE TdiConnectionObjectHandle,
  203. IN INT Level,
  204. IN INT OptionName,
  205. OUT PCHAR OptionValue,
  206. OUT PINT OptionLength
  207. )
  208. /*++
  209. Routine Description:
  210. This routine retrieves information about a socket for those socket
  211. options supported in this helper DLL. The options supported here
  212. are SO_KEEPALIVE and SO_DONTROUTE. This routine is called by
  213. the winsock DLL when a level/option name combination is passed
  214. to getsockopt() that the winsock DLL does not understand.
  215. Arguments:
  216. HelperDllSocketContext - the context pointer returned from
  217. WSHOpenSocket().
  218. SocketHandle - the handle of the socket for which we're getting
  219. information.
  220. TdiAddressObjectHandle - the TDI address object of the socket, if
  221. any. If the socket is not yet bound to an address, then
  222. it does not have a TDI address object and this parameter
  223. will be NULL.
  224. TdiConnectionObjectHandle - the TDI connection object of the socket,
  225. if any. If the socket is not yet connected, then it does not
  226. have a TDI connection object and this parameter will be NULL.
  227. Level - the level parameter passed to getsockopt().
  228. OptionName - the optname parameter passed to getsockopt().
  229. OptionValue - the optval parameter passed to getsockopt().
  230. OptionLength - the optlen parameter passed to getsockopt().
  231. Return Value:
  232. INT - a winsock error code indicating the status of the operation, or
  233. NO_ERROR if the operation succeeded.
  234. --*/
  235. {
  236. PWSHNETBS_SOCKET_CONTEXT context = HelperDllSocketContext;
  237. UNREFERENCED_PARAMETER( SocketHandle );
  238. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  239. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  240. //
  241. // Check if this is an internal request for context information.
  242. //
  243. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  244. //
  245. // The Windows Sockets DLL is requesting context information
  246. // from us. If an output buffer was not supplied, the Windows
  247. // Sockets DLL is just requesting the size of our context
  248. // information.
  249. //
  250. if ( OptionValue != NULL ) {
  251. //
  252. // Make sure that the buffer is sufficient to hold all the
  253. // context information.
  254. //
  255. if ( *OptionLength < sizeof(*context) ) {
  256. return WSAEFAULT;
  257. }
  258. //
  259. // Copy in the context information.
  260. //
  261. RtlCopyMemory( OptionValue, context, sizeof(*context) );
  262. }
  263. *OptionLength = sizeof(*context);
  264. return NO_ERROR;
  265. }
  266. //
  267. // No other options are supported for Netbios sockets.
  268. return WSAEINVAL;
  269. } // WSHGetSocketInformation
  270. INT
  271. WSHGetWildcardSockaddr (
  272. IN PVOID HelperDllSocketContext,
  273. OUT PSOCKADDR Sockaddr,
  274. OUT PINT SockaddrLength
  275. )
  276. /*++
  277. Routine Description:
  278. This routine returns a wildcard socket address. Netbios doesn't
  279. currently support the concept of a wildcard socket address.
  280. Arguments:
  281. HelperDllSocketContext - the context pointer returned from
  282. WSHOpenSocket() for the socket for which we need a wildcard
  283. address.
  284. Sockaddr - points to a buffer which will receive the wildcard socket
  285. address.
  286. SockaddrLength - receives the length of the wildcard sockaddr.
  287. Return Value:
  288. INT - a winsock error code indicating the status of the operation, or
  289. NO_ERROR if the operation succeeded.
  290. --*/
  291. {
  292. PSOCKADDR_NB sockaddr = (PSOCKADDR_NB)Sockaddr;
  293. HANDLE providerHandle;
  294. TDI_REQUEST_QUERY_INFORMATION tdiQuery;
  295. NTSTATUS status;
  296. OBJECT_ATTRIBUTES objectAttributes;
  297. UNICODE_STRING providerName;
  298. PWSHNETBS_SOCKET_CONTEXT context = (PWSHNETBS_SOCKET_CONTEXT)HelperDllSocketContext;
  299. ADAPTER_STATUS adapterStatusInfo;
  300. IO_STATUS_BLOCK ioStatusBlock;
  301. //
  302. // We're going to return a Netbios sockaddr with a unique name
  303. // which is the premanent name of the Lana.
  304. //
  305. sockaddr->snb_family = AF_NETBIOS;
  306. sockaddr->snb_type = NETBIOS_UNIQUE_NAME;
  307. sockaddr->snb_name[0] = '\0';
  308. sockaddr->snb_name[1] = '\0';
  309. sockaddr->snb_name[2] = '\0';
  310. sockaddr->snb_name[3] = '\0';
  311. sockaddr->snb_name[4] = '\0';
  312. sockaddr->snb_name[5] = '\0';
  313. sockaddr->snb_name[6] = '\0';
  314. sockaddr->snb_name[7] = '\0';
  315. sockaddr->snb_name[8] = '\0';
  316. sockaddr->snb_name[9] = '\0';
  317. *SockaddrLength = sizeof(SOCKADDR_NB);
  318. //
  319. // We'll do a query directly to the TDI provider to get the
  320. // permanent address for this Lana. First open a control channel to
  321. // the provider.
  322. //
  323. RtlInitUnicodeString( &providerName, context->Provider->ProviderName );
  324. InitializeObjectAttributes(
  325. &objectAttributes,
  326. &providerName,
  327. OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
  328. NULL,
  329. NULL
  330. );
  331. //
  332. // Open a control channel to the provider.
  333. //
  334. status = NtCreateFile(
  335. &providerHandle,
  336. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  337. &objectAttributes,
  338. &ioStatusBlock,
  339. NULL, // AllocationSize
  340. 0L, // FileAttributes
  341. FILE_SHARE_READ | FILE_SHARE_WRITE, // ShareAccess
  342. FILE_OPEN_IF, // CreateDisposition
  343. FILE_SYNCHRONOUS_IO_NONALERT, // CreateOptions
  344. NULL,
  345. 0
  346. );
  347. if ( !NT_SUCCESS(status) ) {
  348. return WSAENOBUFS;
  349. }
  350. //
  351. // Do the actual query adapter status.
  352. //
  353. RtlZeroMemory( &tdiQuery, sizeof(tdiQuery) );
  354. tdiQuery.QueryType = TDI_QUERY_ADAPTER_STATUS;
  355. status = NtDeviceIoControlFile(
  356. providerHandle,
  357. NULL,
  358. NULL,
  359. NULL,
  360. &ioStatusBlock,
  361. IOCTL_TDI_QUERY_INFORMATION,
  362. &tdiQuery,
  363. sizeof(tdiQuery),
  364. &adapterStatusInfo,
  365. sizeof(adapterStatusInfo)
  366. );
  367. if ( status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW ) {
  368. NtClose( providerHandle );
  369. return WSAENOBUFS;
  370. }
  371. //
  372. // Close the handle to the provider, we're done with it.
  373. //
  374. NtClose( providerHandle );
  375. //
  376. // Copy the six bytes of adapter address to the end of the Netbios
  377. // name.
  378. //
  379. sockaddr->snb_name[10] = adapterStatusInfo.adapter_address[0];
  380. sockaddr->snb_name[11] = adapterStatusInfo.adapter_address[1];
  381. sockaddr->snb_name[12] = adapterStatusInfo.adapter_address[2];
  382. sockaddr->snb_name[13] = adapterStatusInfo.adapter_address[3];
  383. sockaddr->snb_name[14] = adapterStatusInfo.adapter_address[4];
  384. sockaddr->snb_name[15] = adapterStatusInfo.adapter_address[5];
  385. return NO_ERROR;
  386. } // WSAGetWildcardSockaddr
  387. DWORD
  388. WSHGetWinsockMapping (
  389. OUT PWINSOCK_MAPPING Mapping,
  390. IN DWORD MappingLength
  391. )
  392. /*++
  393. Routine Description:
  394. Returns the list of address family/socket type/protocol triples
  395. supported by this helper DLL.
  396. Arguments:
  397. Mapping - receives a pointer to a WINSOCK_MAPPING structure that
  398. describes the triples supported here.
  399. MappingLength - the length, in bytes, of the passed-in Mapping buffer.
  400. Return Value:
  401. DWORD - the length, in bytes, of a WINSOCK_MAPPING structure for this
  402. helper DLL. If the passed-in buffer is too small, the return
  403. value will indicate the size of a buffer needed to contain
  404. the WINSOCK_MAPPING structure.
  405. --*/
  406. {
  407. DWORD mappingLength;
  408. mappingLength = sizeof(WINSOCK_MAPPING) - sizeof(MAPPING_TRIPLE) +
  409. sizeof(VcMappingTriples) + sizeof(DgMappingTriples);
  410. //
  411. // If the passed-in buffer is too small, return the length needed
  412. // now without writing to the buffer. The caller should allocate
  413. // enough memory and call this routine again.
  414. //
  415. if ( mappingLength > MappingLength ) {
  416. return mappingLength;
  417. }
  418. //
  419. // Fill in the output mapping buffer with the list of triples
  420. // supported in this helper DLL.
  421. //
  422. Mapping->Rows = sizeof(VcMappingTriples) / sizeof(VcMappingTriples[0])
  423. + sizeof(DgMappingTriples) / sizeof(DgMappingTriples[0]);
  424. Mapping->Columns = sizeof(MAPPING_TRIPLE) / sizeof(DWORD);
  425. RtlMoveMemory(
  426. Mapping->Mapping,
  427. VcMappingTriples,
  428. sizeof(VcMappingTriples)
  429. );
  430. RtlMoveMemory(
  431. (PCHAR)Mapping->Mapping + sizeof(VcMappingTriples),
  432. DgMappingTriples,
  433. sizeof(DgMappingTriples)
  434. );
  435. //
  436. // Return the number of bytes we wrote.
  437. //
  438. return mappingLength;
  439. } // WSHGetWinsockMapping
  440. INT
  441. WSHOpenSocket (
  442. IN OUT PINT AddressFamily,
  443. IN OUT PINT SocketType,
  444. IN OUT PINT Protocol,
  445. OUT PUNICODE_STRING TransportDeviceName,
  446. OUT PVOID *HelperDllSocketContext,
  447. OUT PDWORD NotificationEvents
  448. )
  449. /*++
  450. Routine Description:
  451. Does the necessary work for this helper DLL to open a socket and is
  452. called by the winsock DLL in the socket() routine. This routine
  453. verifies that the specified triple is valid, determines the NT
  454. device name of the TDI provider that will support that triple,
  455. allocates space to hold the socket's context block, and
  456. canonicalizes the triple.
  457. Arguments:
  458. AddressFamily - on input, the address family specified in the
  459. socket() call. On output, the canonicalized value for the
  460. address family.
  461. SocketType - on input, the socket type specified in the socket()
  462. call. On output, the canonicalized value for the socket type.
  463. Protocol - on input, the protocol specified in the socket() call.
  464. On output, the canonicalized value for the protocol.
  465. TransportDeviceName - receives the name of the TDI provider that
  466. will support the specified triple.
  467. HelperDllSocketContext - receives a context pointer that the winsock
  468. DLL will return to this helper DLL on future calls involving
  469. this socket.
  470. NotificationEvents - receives a bitmask of those state transitions
  471. this helper DLL should be notified on.
  472. Return Value:
  473. INT - a winsock error code indicating the status of the operation, or
  474. NO_ERROR if the operation succeeded.
  475. --*/
  476. {
  477. PWSHNETBS_SOCKET_CONTEXT context;
  478. ULONG i;
  479. BOOLEAN found = FALSE;
  480. INT error;
  481. //
  482. // Only sockets of types SOCK_SEQPACKET and SOCK_DGRAM are supported
  483. // by Netbios providers.
  484. //
  485. if ( *SocketType != SOCK_SEQPACKET && *SocketType != SOCK_DGRAM ) {
  486. return WSAESOCKTNOSUPPORT;
  487. }
  488. if ((error=LoadProviderInfo ())!=NO_ERROR) {
  489. if (error!=ERROR_NOT_ENOUGH_MEMORY)
  490. error = WSASYSCALLFAILURE;
  491. return error;
  492. }
  493. //
  494. // Allocate context for this socket. The Windows Sockets DLL will
  495. // return this value to us when it asks us to get/set socket options.
  496. //
  497. context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
  498. if ( context == NULL ) {
  499. return WSAENOBUFS;
  500. }
  501. //
  502. // Treat 0x80000000 just like 0--EnumProtocols() returns 0x80000000
  503. // for lana 0 because GetAddressByName uses 0 as the protocol array
  504. // terminator.
  505. //
  506. if ( *Protocol == 0x80000000 ) {
  507. *Protocol = 0;
  508. }
  509. RtlEnterCriticalSection (&ConfigInfoLock);
  510. //
  511. // If the Protocol parameter is less than or equal to zero, then
  512. // it specifies a Lana number. Otherwise, it specifies an actual
  513. // protocol number. Loop through our array of providers looking
  514. // for one with a matching Lana or protocol value.
  515. //
  516. for ( i = 0; i < ProviderCount; i++ ) {
  517. if ( ( *Protocol <= 0 && -*Protocol == ProviderInfo[i].LanaNumber &&
  518. ProviderInfo[i].Enum != 0 )
  519. ||
  520. (*Protocol == ProviderInfo[i].ProtocolNumber && *Protocol != 0) ) {
  521. REFERENCE_CONFIG_INFO (ConfigInfo);
  522. context->ConfigInfo = ConfigInfo;
  523. context->Provider = &ProviderInfo[i];
  524. found = TRUE;
  525. break;
  526. }
  527. }
  528. RtlLeaveCriticalSection (&ConfigInfoLock);
  529. //
  530. // If we didn't find a hit, fail.
  531. //
  532. if ( found ) {
  533. //
  534. // Indicate the name of the TDI device that will service this
  535. // socket.
  536. //
  537. RtlInitUnicodeString(
  538. TransportDeviceName,
  539. context->Provider->ProviderName
  540. );
  541. //
  542. // Initialize the context for the socket.
  543. //
  544. context->AddressFamily = *AddressFamily;
  545. context->SocketType = *SocketType;
  546. context->Protocol = *Protocol;
  547. //
  548. // Tell the Windows Sockets DLL which state transitions we're
  549. // interested in being notified of. The only times we need to be
  550. // called is after a connect has completed so that we can turn on
  551. // the sending of keepalives if SO_KEEPALIVE was set before the
  552. // socket was connected, when the socket is closed so that we can
  553. // free context information, and when a connect fails so that we
  554. // can, if appropriate, dial in to the network that will support the
  555. // connect attempt.
  556. //
  557. *NotificationEvents = WSH_NOTIFY_CLOSE;
  558. //
  559. // Everything worked, return success.
  560. //
  561. *HelperDllSocketContext = context;
  562. return NO_ERROR;
  563. }
  564. RtlFreeHeap( RtlProcessHeap( ), 0, context );
  565. return WSAEPROTONOSUPPORT;
  566. } // WSHOpenSocket
  567. INT
  568. WSHNotify (
  569. IN PVOID HelperDllSocketContext,
  570. IN SOCKET SocketHandle,
  571. IN HANDLE TdiAddressObjectHandle,
  572. IN HANDLE TdiConnectionObjectHandle,
  573. IN DWORD NotifyEvent
  574. )
  575. /*++
  576. Routine Description:
  577. This routine is called by the winsock DLL after a state transition
  578. of the socket. Only state transitions returned in the
  579. NotificationEvents parameter of WSHOpenSocket() are notified here.
  580. This routine allows a winsock helper DLL to track the state of
  581. socket and perform necessary actions corresponding to state
  582. transitions.
  583. Arguments:
  584. HelperDllSocketContext - the context pointer given to the winsock
  585. DLL by WSHOpenSocket().
  586. SocketHandle - the handle for the socket.
  587. TdiAddressObjectHandle - the TDI address object of the socket, if
  588. any. If the socket is not yet bound to an address, then
  589. it does not have a TDI address object and this parameter
  590. will be NULL.
  591. TdiConnectionObjectHandle - the TDI connection object of the socket,
  592. if any. If the socket is not yet connected, then it does not
  593. have a TDI connection object and this parameter will be NULL.
  594. NotifyEvent - indicates the state transition for which we're being
  595. called.
  596. Return Value:
  597. INT - a winsock error code indicating the status of the operation, or
  598. NO_ERROR if the operation succeeded.
  599. --*/
  600. {
  601. PWSHNETBS_SOCKET_CONTEXT context = HelperDllSocketContext;
  602. //
  603. // We should only be called when the socket is being closed.
  604. //
  605. if ( NotifyEvent == WSH_NOTIFY_CLOSE ) {
  606. //
  607. // Dereference config info and free the socket context.
  608. //
  609. DEREFERENCE_CONFIG_INFO (context->ConfigInfo);
  610. RtlFreeHeap( RtlProcessHeap( ), 0, HelperDllSocketContext );
  611. } else {
  612. return WSAEINVAL;
  613. }
  614. return NO_ERROR;
  615. } // WSHNotify
  616. INT
  617. WSHSetSocketInformation (
  618. IN PVOID HelperDllSocketContext,
  619. IN SOCKET SocketHandle,
  620. IN HANDLE TdiAddressObjectHandle,
  621. IN HANDLE TdiConnectionObjectHandle,
  622. IN INT Level,
  623. IN INT OptionName,
  624. IN PCHAR OptionValue,
  625. IN INT OptionLength
  626. )
  627. /*++
  628. Routine Description:
  629. This routine sets information about a socket for those socket
  630. options supported in this helper DLL. The options supported here
  631. are SO_KEEPALIVE and SO_DONTROUTE. This routine is called by the
  632. winsock DLL when a level/option name combination is passed to
  633. setsockopt() that the winsock DLL does not understand.
  634. Arguments:
  635. HelperDllSocketContext - the context pointer returned from
  636. WSHOpenSocket().
  637. SocketHandle - the handle of the socket for which we're getting
  638. information.
  639. TdiAddressObjectHandle - the TDI address object of the socket, if
  640. any. If the socket is not yet bound to an address, then
  641. it does not have a TDI address object and this parameter
  642. will be NULL.
  643. TdiConnectionObjectHandle - the TDI connection object of the socket,
  644. if any. If the socket is not yet connected, then it does not
  645. have a TDI connection object and this parameter will be NULL.
  646. Level - the level parameter passed to setsockopt().
  647. OptionName - the optname parameter passed to setsockopt().
  648. OptionValue - the optval parameter passed to setsockopt().
  649. OptionLength - the optlen parameter passed to setsockopt().
  650. Return Value:
  651. INT - a winsock error code indicating the status of the operation, or
  652. NO_ERROR if the operation succeeded.
  653. --*/
  654. {
  655. PWSHNETBS_SOCKET_CONTEXT context = HelperDllSocketContext;
  656. UNREFERENCED_PARAMETER( SocketHandle );
  657. UNREFERENCED_PARAMETER( TdiAddressObjectHandle );
  658. UNREFERENCED_PARAMETER( TdiConnectionObjectHandle );
  659. //
  660. // Check if this is an internal request for context information.
  661. //
  662. if ( Level == SOL_INTERNAL && OptionName == SO_CONTEXT ) {
  663. //
  664. // The Windows Sockets DLL is requesting that we set context
  665. // information for a new socket. If the new socket was
  666. // accept()'ed, then we have already been notified of the socket
  667. // and HelperDllSocketContext will be valid. If the new socket
  668. // was inherited or duped into this process, then this is our
  669. // first notification of the socket and HelperDllSocketContext
  670. // will be equal to NULL.
  671. //
  672. // Insure that the context information being passed to us is
  673. // sufficiently large.
  674. //
  675. if ( OptionLength < sizeof(*context) ) {
  676. return WSAEINVAL;
  677. }
  678. if ( HelperDllSocketContext == NULL ) {
  679. //
  680. // This is our notification that a socket handle was
  681. // inherited or duped into this process. Allocate a context
  682. // structure for the new socket.
  683. //
  684. context = RtlAllocateHeap( RtlProcessHeap( ), 0, sizeof(*context) );
  685. if ( context == NULL ) {
  686. return WSAENOBUFS;
  687. }
  688. //
  689. // Copy over information into the context block.
  690. //
  691. RtlCopyMemory( context, OptionValue, sizeof(*context) );
  692. //
  693. // Tell the Windows Sockets DLL where our context information is
  694. // stored so that it can return the context pointer in future
  695. // calls.
  696. //
  697. *(PWSHNETBS_SOCKET_CONTEXT *)OptionValue = context;
  698. return NO_ERROR;
  699. } else {
  700. PWSHNETBS_SOCKET_CONTEXT parentContext;
  701. INT one = 1;
  702. //
  703. // The socket was accept()'ed and it needs to have the same
  704. // properties as it's parent. The OptionValue buffer
  705. // contains the context information of this socket's parent.
  706. //
  707. parentContext = (PWSHNETBS_SOCKET_CONTEXT)OptionValue;
  708. ASSERT( context->AddressFamily == parentContext->AddressFamily );
  709. ASSERT( context->SocketType == parentContext->SocketType );
  710. ASSERT( context->Protocol == parentContext->Protocol );
  711. return NO_ERROR;
  712. }
  713. }
  714. //
  715. // No other options are supported for Netbios sockets.
  716. //
  717. return WSAEINVAL;
  718. } // WSHSetSocketInformation
  719. INT
  720. WSHEnumProtocols (
  721. IN LPINT lpiProtocols,
  722. IN LPWSTR lpTransportKeyName,
  723. IN OUT LPVOID lpProtocolBuffer,
  724. IN OUT LPDWORD lpdwBufferLength
  725. )
  726. {
  727. DWORD bytesRequired;
  728. DWORD i;
  729. PPROTOCOL_INFO protocolInfo;
  730. PCHAR namePointer;
  731. lpTransportKeyName; // Avoid compiler warnings.
  732. //
  733. // Make sure that the caller cares about NETBIOS protocol information.
  734. //
  735. if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
  736. *lpdwBufferLength = 0;
  737. return 0;
  738. }
  739. if (LoadProviderInfo ()!=NO_ERROR) {
  740. *lpdwBufferLength = 0;
  741. return 0;
  742. }
  743. //
  744. // Make sure that the caller has specified a sufficiently large
  745. // buffer.
  746. //
  747. bytesRequired = 0;
  748. for ( i = 0; i < ProviderCount; i++ ) {
  749. bytesRequired += sizeof(PROTOCOL_INFO) * 2;
  750. bytesRequired +=
  751. ((wcslen( ProviderInfo[i].ProviderName ) + 1) * sizeof(WCHAR)) * 2;
  752. }
  753. if ( bytesRequired > *lpdwBufferLength ) {
  754. *lpdwBufferLength = bytesRequired;
  755. return -1;
  756. }
  757. //
  758. // Fill in info for each Netbios provider.
  759. //
  760. namePointer = (PCHAR)lpProtocolBuffer + *lpdwBufferLength;
  761. protocolInfo = lpProtocolBuffer;
  762. for ( i = 0; i < ProviderCount * 2; i++ ) {
  763. protocolInfo[i].dwServiceFlags = XP_GUARANTEED_DELIVERY |
  764. XP_GUARANTEED_ORDER |
  765. XP_MESSAGE_ORIENTED |
  766. XP_FRAGMENTATION;
  767. protocolInfo[i].iAddressFamily = AF_NETBIOS;
  768. protocolInfo[i].iMaxSockAddr = sizeof(SOCKADDR_NB);
  769. protocolInfo[i].iMinSockAddr = sizeof(SOCKADDR_NB);
  770. protocolInfo[i].iSocketType = SOCK_SEQPACKET;
  771. //
  772. // Return the lana number, but convert 0 to 0x80000000 so that
  773. // we do not confuse GetAddressByName. That API uses 0 as the
  774. // protocol array terminator.
  775. //
  776. protocolInfo[i].iProtocol = -1*ProviderInfo[i/2].LanaNumber;
  777. if ( protocolInfo[i].iProtocol == 0 ) {
  778. protocolInfo[i].iProtocol = 0x80000000;
  779. }
  780. protocolInfo[i].dwMessageSize = 64000;
  781. namePointer =
  782. ( namePointer -
  783. ( (wcslen( ProviderInfo[i/2].ProviderName ) + 1) * sizeof(WCHAR) ) );
  784. protocolInfo[i].lpProtocol = (LPWSTR)namePointer;
  785. wcscpy( protocolInfo[i].lpProtocol, ProviderInfo[i/2].ProviderName );
  786. i++;
  787. protocolInfo[i].dwServiceFlags = XP_CONNECTIONLESS |
  788. XP_MESSAGE_ORIENTED |
  789. XP_SUPPORTS_BROADCAST |
  790. XP_FRAGMENTATION;
  791. protocolInfo[i].iAddressFamily = AF_NETBIOS;
  792. protocolInfo[i].iMaxSockAddr = sizeof(SOCKADDR_NB);
  793. protocolInfo[i].iMinSockAddr = sizeof(SOCKADDR_NB);
  794. protocolInfo[i].iSocketType = SOCK_DGRAM;
  795. protocolInfo[i].iProtocol = -1*ProviderInfo[i/2].LanaNumber;
  796. if ( protocolInfo[i].iProtocol == 0 ) {
  797. protocolInfo[i].iProtocol = 0x80000000;
  798. }
  799. protocolInfo[i].dwMessageSize = 64000;
  800. namePointer =
  801. ( namePointer -
  802. ( (wcslen( ProviderInfo[i/2].ProviderName ) + 1) * sizeof(WCHAR) ) );
  803. protocolInfo[i].lpProtocol = (LPWSTR)namePointer;
  804. wcscpy( protocolInfo[i].lpProtocol, ProviderInfo[i/2].ProviderName );
  805. }
  806. *lpdwBufferLength = bytesRequired;
  807. return ProviderCount * 2;
  808. } // WSHEnumProtocols
  809. INT
  810. WINAPI
  811. WSHGetProviderGuid (
  812. IN LPWSTR ProviderName,
  813. OUT LPGUID ProviderGuid
  814. )
  815. /*++
  816. Routine Description:
  817. Returns the GUID identifying the protocols supported by this helper.
  818. Arguments:
  819. ProviderName - Contains the name of the provider, such as "TcpIp".
  820. ProviderGuid - Points to a buffer that receives the provider's GUID.
  821. Return Value:
  822. INT - 0 if successful, WinSock error code if not.
  823. --*/
  824. {
  825. if( ProviderName == NULL ||
  826. ProviderGuid == NULL ) {
  827. return WSAEFAULT;
  828. }
  829. if( _wcsicmp( ProviderName, L"NetBIOS" ) == 0 ) {
  830. RtlCopyMemory(
  831. ProviderGuid,
  832. &NetBIOSProviderGuid,
  833. sizeof(GUID)
  834. );
  835. return NO_ERROR;
  836. }
  837. return WSAEINVAL;
  838. } // WSHGetProviderGuid
  839. #define ALIGN_TO_MAX_NATURAL(_sz) \
  840. (((_sz) + (MAX_NATURAL_ALIGNMENT-1)) & (~(MAX_NATURAL_ALIGNMENT-1)))
  841. INT
  842. LoadProviderInfo (
  843. VOID
  844. )
  845. {
  846. INT error;
  847. HKEY netbiosKey = NULL;
  848. ULONG providerListLength;
  849. ULONG lanaMapLength;
  850. ULONG type;
  851. ULONG i;
  852. PWSTR currentProviderName;
  853. PWSHNETBS_CONFIG_INFO configInfo = NULL;
  854. PLANA_MAP lanaMap;
  855. PWSHNETBS_PROVIDER_INFO providerInfo;
  856. PVOID providerNames;
  857. ULONG providerCount;
  858. LARGE_INTEGER lastWriteTime;
  859. if (NetbiosKey==NULL) {
  860. //
  861. // Read the registry for information on all Netbios providers,
  862. // including Lana numbers, protocol numbers, and provider device
  863. // names. First, open the Netbios key in the registry.
  864. //
  865. error = RegOpenKeyExW(
  866. HKEY_LOCAL_MACHINE,
  867. L"SYSTEM\\CurrentControlSet\\Services\\Netbios\\Linkage",
  868. 0,
  869. MAXIMUM_ALLOWED,
  870. &netbiosKey
  871. );
  872. if ( error != NO_ERROR ) {
  873. goto error_exit;
  874. }
  875. }
  876. else {
  877. //
  878. // Key is already opened, use it.
  879. //
  880. netbiosKey = NetbiosKey;
  881. }
  882. //
  883. // Check if data has changed since last time we read it.
  884. //
  885. error = RegQueryInfoKey (
  886. netbiosKey, // handle to key to query
  887. NULL, // address of buffer for class string
  888. NULL, // address of size of class string buffer
  889. NULL, // reserved
  890. NULL, // address of buffer for number of
  891. // subkeys
  892. NULL, // address of buffer for longest subkey
  893. // name length
  894. NULL, // address of buffer for longest class
  895. // string length
  896. NULL, // address of buffer for number of value
  897. // entries
  898. NULL, // address of buffer for longest
  899. // value name length
  900. NULL, // address of buffer for longest value
  901. // data length
  902. NULL, // address of buffer for security
  903. // descriptor length
  904. (PFILETIME)&lastWriteTime
  905. // address of buffer for last write
  906. // time
  907. );
  908. if (error!=NO_ERROR) {
  909. goto error_exit;
  910. }
  911. if (NetbiosKey!=NULL && lastWriteTime.QuadPart==NetbiosUpdateTime.QuadPart) {
  912. return NO_ERROR;
  913. }
  914. //
  915. // Determine the size of the provider names. We need this so
  916. // that we can allocate enough memory to hold it.
  917. //
  918. providerListLength = 0;
  919. error = RegQueryValueExW(
  920. netbiosKey,
  921. L"Bind",
  922. NULL,
  923. &type,
  924. NULL,
  925. &providerListLength
  926. );
  927. if ( error != ERROR_MORE_DATA && error != NO_ERROR ) {
  928. goto error_exit;
  929. }
  930. //
  931. // If the list of providers is empty, then Netbios is installed
  932. // but has no bindings. Special-case a quit right here, since
  933. // the LanaMap value in the registry may be non-empty.
  934. //
  935. if ( providerListLength <= sizeof(WCHAR) ) {
  936. goto error_exit;
  937. }
  938. error = RegQueryValueExW(
  939. netbiosKey,
  940. L"LanaMap",
  941. NULL,
  942. &type,
  943. NULL,
  944. &lanaMapLength
  945. );
  946. if ( error != ERROR_MORE_DATA && error != NO_ERROR ) {
  947. goto error_exit;
  948. }
  949. //
  950. // Determine the number of Netbios providers loaded on the system.
  951. //
  952. providerCount = lanaMapLength / sizeof(LANA_MAP);
  953. //
  954. // Allocate enough memory to hold the blob.
  955. //
  956. configInfo = RtlAllocateHeap( RtlProcessHeap( ), 0,
  957. ALIGN_TO_MAX_NATURAL(FIELD_OFFSET (WSHNETBS_CONFIG_INFO, Blob)) +
  958. ALIGN_TO_MAX_NATURAL(providerListLength) +
  959. ALIGN_TO_MAX_NATURAL(lanaMapLength) +
  960. providerCount * sizeof(WSHNETBS_PROVIDER_INFO)
  961. );
  962. if ( configInfo == NULL ) {
  963. error = ERROR_NOT_ENOUGH_MEMORY;
  964. goto error_exit;
  965. }
  966. configInfo->ReferenceCount = 1;
  967. providerNames = (PVOID)((PUCHAR)configInfo + ALIGN_TO_MAX_NATURAL(FIELD_OFFSET (WSHNETBS_CONFIG_INFO, Blob)));
  968. lanaMap = (PVOID)((PUCHAR)providerNames + ALIGN_TO_MAX_NATURAL(providerListLength));
  969. providerInfo = (PVOID)((PUCHAR)lanaMap + ALIGN_TO_MAX_NATURAL(lanaMapLength));
  970. //
  971. // Get the list of transports from the registry.
  972. //
  973. error = RegQueryValueExW(
  974. netbiosKey,
  975. L"Bind",
  976. NULL,
  977. &type,
  978. (PVOID)providerNames,
  979. &providerListLength
  980. );
  981. if ( error != NO_ERROR ) {
  982. goto error_exit;
  983. }
  984. error = RegQueryValueExW(
  985. netbiosKey,
  986. L"LanaMap",
  987. NULL,
  988. &type,
  989. (PVOID)lanaMap,
  990. &lanaMapLength
  991. );
  992. if ( error != NO_ERROR ) {
  993. goto error_exit;
  994. }
  995. //
  996. // Fill in the array or provider information.
  997. //
  998. for ( currentProviderName = providerNames, i = 0;
  999. *currentProviderName != UNICODE_NULL && i < providerCount;
  1000. currentProviderName += wcslen( currentProviderName ) + 1, i++ ) {
  1001. providerInfo[i].Enum = lanaMap[i].Enum;
  1002. providerInfo[i].LanaNumber = lanaMap[i].Lana;
  1003. providerInfo[i].ProtocolNumber = lanaMap[i].Lana;
  1004. providerInfo[i].ProviderName = currentProviderName;
  1005. }
  1006. if (i<providerCount) {
  1007. error = ERROR_INVALID_PARAMETER;
  1008. goto error_exit;
  1009. }
  1010. RtlEnterCriticalSection (&ConfigInfoLock);
  1011. if (ConfigInfo!=NULL) {
  1012. DEREFERENCE_CONFIG_INFO (ConfigInfo);
  1013. }
  1014. if (NetbiosKey==NULL) {
  1015. NetbiosKey = netbiosKey;
  1016. netbiosKey = NULL;
  1017. }
  1018. NetbiosUpdateTime = lastWriteTime;
  1019. ConfigInfo = configInfo;
  1020. LanaMap = lanaMap;
  1021. ProviderInfo = providerInfo;
  1022. ProviderCount = providerCount;
  1023. RtlLeaveCriticalSection (&ConfigInfoLock);
  1024. if (netbiosKey!=NULL && netbiosKey!=NetbiosKey) {
  1025. RegCloseKey (netbiosKey);
  1026. }
  1027. return NO_ERROR;
  1028. error_exit:
  1029. if (netbiosKey!=NULL && netbiosKey!=NetbiosKey) {
  1030. RegCloseKey (netbiosKey);
  1031. }
  1032. if ( configInfo != NULL ) {
  1033. RtlFreeHeap( RtlProcessHeap( ), 0, configInfo );
  1034. }
  1035. return error;
  1036. }