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.

1041 lines
25 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. nspatalk.c
  5. Abstract:
  6. Contains support for the winsock 1.x Name Space Provider for Appletalk.
  7. Author:
  8. Sue Adams (suea) 10-Mar-1995
  9. Revision History:
  10. --*/
  11. #include "nspatalk.h"
  12. #define ADSP_BIT 0x0001 // Bitmask used internally to store the
  13. #define PAP_BIT 0x0002 // protocols requested by the caller
  14. INT
  15. APIENTRY
  16. NPLoadNameSpaces(
  17. IN OUT LPDWORD lpdwVersion,
  18. IN OUT LPNS_ROUTINE nsrBuffer,
  19. IN OUT LPDWORD lpdwBufferLength
  20. )
  21. /*++
  22. Routine Description:
  23. This routine returns name space info and functions supported in this
  24. dll.
  25. Arguments:
  26. lpdwVersion - dll version
  27. nsrBuffer - on return, this will be filled with an array of
  28. NS_ROUTINE structures
  29. lpdwBufferLength - on input, the number of bytes contained in the buffer
  30. pointed to by nsrBuffer. On output, the minimum number of bytes
  31. to pass for the nsrBuffer to retrieve all the requested info
  32. Return Value:
  33. The number of NS_ROUTINE structures returned, or SOCKET_ERROR (-1) if
  34. the nsrBuffer is too small. Use GetLastError() to retrieve the
  35. error code.
  36. --*/
  37. {
  38. DWORD err;
  39. DWORD dwLengthNeeded;
  40. *lpdwVersion = DLL_VERSION;
  41. //
  42. // Check to see if the buffer is large enough
  43. //
  44. dwLengthNeeded = sizeof(NS_ROUTINE) + 4 * sizeof(LPFN_NSPAPI);
  45. if ( ( *lpdwBufferLength < dwLengthNeeded )
  46. || ( nsrBuffer == NULL )
  47. )
  48. {
  49. *lpdwBufferLength = dwLengthNeeded;
  50. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  51. return (DWORD) SOCKET_ERROR;
  52. }
  53. //
  54. // We only support 1 name space, so fill in the NS_ROUTINE.
  55. //
  56. nsrBuffer->dwFunctionCount = 3;
  57. nsrBuffer->alpfnFunctions = (LPFN_NSPAPI *)
  58. ((BYTE *) nsrBuffer + sizeof(NS_ROUTINE));
  59. (nsrBuffer->alpfnFunctions)[NSPAPI_GET_ADDRESS_BY_NAME] =
  60. (LPFN_NSPAPI) NbpGetAddressByName;
  61. (nsrBuffer->alpfnFunctions)[NSPAPI_GET_SERVICE] = NULL;
  62. (nsrBuffer->alpfnFunctions)[NSPAPI_SET_SERVICE] =
  63. (LPFN_NSPAPI) NbpSetService;
  64. (nsrBuffer->alpfnFunctions)[3] = NULL;
  65. nsrBuffer->dwNameSpace = NS_NBP;
  66. nsrBuffer->dwPriority = NS_STANDARD_PRIORITY;
  67. return 1; // number of namespaces
  68. }
  69. INT
  70. NbpGetAddressByName(
  71. IN LPGUID lpServiceType,
  72. IN LPWSTR lpServiceName,
  73. IN LPDWORD lpdwProtocols,
  74. IN DWORD dwResolution,
  75. IN OUT LPVOID lpCsAddrBuffer,
  76. IN OUT LPDWORD lpdwBufferLength,
  77. IN OUT LPWSTR lpAliasBuffer,
  78. IN OUT LPDWORD lpdwAliasBufferLength,
  79. IN HANDLE hCancellationEvent
  80. )
  81. /*++
  82. Routine Description:
  83. This routine returns address information about a specific service.
  84. Arguments:
  85. lpServiceType - pointer to the GUID for the service type
  86. lpServiceName - unique string representing the service name.
  87. lpdwProtocols - a zero terminated array of protocol ids. This parameter
  88. is optional; if lpdwProtocols is NULL, information on all available
  89. Protocols is returned
  90. dwResolution - can be one of the following values:RES_SERVICE
  91. lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
  92. lpdwBufferLength - on input, the number of bytes contained in the buffer
  93. pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
  94. to pass for the lpCsAddrBuffer to retrieve all the requested info
  95. lpAliasBuffer - not used
  96. lpdwAliasBufferLength - not used
  97. hCancellationEvent - the event which signals us to cancel the request
  98. Return Value:
  99. The number of CSADDR_INFO structures returned, or SOCKET_ERROR (-1) if
  100. the lpCsAddrBuffer is too small. Use GetLastError() to retrieve the
  101. error code.
  102. --*/
  103. {
  104. DWORD err;
  105. WSH_NBP_NAME NbpLookupName;
  106. DWORD cAddress = 0; // Count of the number of address returned
  107. // in lpCsAddrBuffer
  108. DWORD cProtocols = 0; // Count of the number of protocols contained
  109. // in lpdwProtocols + 1 ( for zero terminate )
  110. DWORD nProt = ADSP_BIT | PAP_BIT;
  111. if ( ARGUMENT_PRESENT( lpdwAliasBufferLength )
  112. && ARGUMENT_PRESENT( lpAliasBuffer )
  113. )
  114. {
  115. if ( *lpdwAliasBufferLength >= sizeof(WCHAR) )
  116. *lpAliasBuffer = 0;
  117. }
  118. //DebugBreak();
  119. //
  120. // Check for invalid parameters
  121. //
  122. if ( ( lpServiceType == NULL )
  123. || ( (lpServiceName == NULL) && (dwResolution != RES_SERVICE) )
  124. || ( lpdwBufferLength == NULL )
  125. )
  126. {
  127. SetLastError( ERROR_INVALID_PARAMETER );
  128. return SOCKET_ERROR;
  129. }
  130. // The size of the user's buffer will dictate also how many
  131. // tuples can be returned from the NBP lookup in case they
  132. // are querying using wildcards.
  133. if ( *lpdwBufferLength < (sizeof(WSH_LOOKUP_NAME) + sizeof(WSH_NBP_TUPLE)) )
  134. {
  135. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  136. return SOCKET_ERROR;
  137. }
  138. //
  139. // If an array of protocol ids is passed in, check to see if
  140. // the ADSP or PAP protocol is requested. If not, return 0 since
  141. // we only support these 2.
  142. //
  143. if ( lpdwProtocols != NULL )
  144. {
  145. INT i = -1;
  146. nProt = 0;
  147. while ( lpdwProtocols[++i] != 0 )
  148. {
  149. if ( lpdwProtocols[i] == ATPROTO_ADSP )
  150. nProt |= ADSP_BIT;
  151. if ( lpdwProtocols[i] == ATPROTO_PAP )
  152. nProt |= PAP_BIT;
  153. }
  154. if ( nProt == 0 )
  155. return 0; // No address found
  156. }
  157. //
  158. // If this is a service asking what local address to use when
  159. // bind()-ing its appletalk socket, return the generic Appletalk
  160. // socket address.
  161. //
  162. if ((dwResolution & RES_SERVICE) != 0)
  163. {
  164. err = FillBufferWithCsAddr( NULL,
  165. nProt,
  166. lpCsAddrBuffer,
  167. lpdwBufferLength,
  168. &cAddress );
  169. if ( err )
  170. {
  171. SetLastError( err );
  172. return SOCKET_ERROR;
  173. }
  174. return cAddress;
  175. }
  176. //
  177. // This is a client trying to do an NBP lookup on an Appletalk
  178. // named entity to find out what remote address to connect() to.
  179. //
  180. err = GetNameInNbpFormat(lpServiceType,
  181. lpServiceName,
  182. &NbpLookupName);
  183. if (err)
  184. {
  185. KdPrint(("GetNameInNbpFormat failed with error %d for name %ws\n", err, lpServiceName ));
  186. SetLastError(err);
  187. return SOCKET_ERROR;
  188. }
  189. err = NbpLookupAddress( &NbpLookupName,
  190. nProt,
  191. lpCsAddrBuffer,
  192. lpdwBufferLength,
  193. &cAddress );
  194. #if DBG
  195. if ( err == NO_ERROR )
  196. {
  197. KdPrint(("NbpGetAddrByName:Successfully got %d address for %ws from NBP.\n",
  198. cAddress, lpServiceName ));
  199. }
  200. else
  201. {
  202. KdPrint(("NbpGetAddrByName:Failed with err %d when getting address for %ws from NBP.\n", err, lpServiceName ));
  203. }
  204. #endif
  205. if ( err )
  206. {
  207. SetLastError( err );
  208. return SOCKET_ERROR;
  209. }
  210. return cAddress;
  211. }
  212. NTSTATUS
  213. GetNameInNbpFormat(
  214. IN LPGUID pServiceType,
  215. IN LPWSTR pServiceName,
  216. IN OUT PWSH_NBP_NAME pNbpName
  217. )
  218. /*++
  219. Routine description:
  220. Convert pServiceType and pServiceName to system ANSI strings in
  221. the pLookupName structure so they can be used to do NBP lookup.
  222. Arguments:
  223. Return value:
  224. --*/
  225. {
  226. INT err;
  227. WCHAR wtypeBuf[MAX_ENTITY + 1];
  228. CHAR entityBuf[(MAX_ENTITY + 1) * 2]; // potentially all multibyte
  229. PWCHAR pColon, pAtSign, pType = wtypeBuf, pObject = pServiceName, pZone = L"*";
  230. // Parse the service name for "object:type@zone" form. If we find a
  231. // ':' there must also be a '@' (and vice-versa).
  232. // If there is a type in the servicename string, we will still convert
  233. // the LPGUID to a string. If the types don't match return an error.
  234. // So, we will accept the following forms for the service name:
  235. // object OR object:type@zone. If just object is given, then the zone
  236. // used will be the default zone "*". Wildcards are acceptible for
  237. // NBP Lookup, but not for NBP (De)Register. No checking is done for that.
  238. //
  239. pColon = wcschr(pServiceName, L':');
  240. pAtSign = wcschr(pServiceName, L'@');
  241. if ( ((pColon != NULL) && (pAtSign == NULL)) ||
  242. ((pAtSign != NULL) && (pColon == NULL)) ||
  243. (pColon > pAtSign) )
  244. {
  245. return(ERROR_INVALID_PARAMETER);
  246. }
  247. //
  248. // By default we only use our own local zone
  249. //
  250. if (pAtSign != NULL)
  251. {
  252. pZone = pAtSign + 1;
  253. if ((wcslen(pZone) == 0) ||
  254. (wcslen(pZone) > MAX_ENTITY))
  255. {
  256. return ERROR_INVALID_PARAMETER;
  257. }
  258. }
  259. if (WideCharToMultiByte(CP_ACP,
  260. 0,
  261. pZone,
  262. -1, // says that wchar string is null terminated
  263. entityBuf,
  264. sizeof(entityBuf),
  265. NULL,
  266. NULL) == 0)
  267. {
  268. DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pZone));
  269. return GetLastError();
  270. }
  271. pNbpName->ZoneNameLen = strlen( entityBuf );
  272. memcpy( pNbpName->ZoneName,
  273. entityBuf,
  274. pNbpName->ZoneNameLen );
  275. if (pAtSign != NULL)
  276. {
  277. // change the @ to a null so the type will be null terminated
  278. *pAtSign = 0;
  279. }
  280. //
  281. // Convert the Type string
  282. //
  283. err = GetNameByType(pServiceType, wtypeBuf, sizeof(wtypeBuf));
  284. if (err != NO_ERROR)
  285. {
  286. // Appletalk type can be 32 chars max, so if this
  287. // fails with buffer too small error it couldn't be
  288. // used on appletalk anyway
  289. return err;
  290. }
  291. // If there was a type name in the ServiceName, then it better match
  292. // what the LPGUID resolved to.
  293. if (pColon != NULL)
  294. {
  295. pType = pColon + 1;
  296. if ((wcslen(pType) == 0) ||
  297. // (wcscmp(pType, wtypeBuf) != 0) ||
  298. (wcslen(pType) > MAX_ENTITY))
  299. {
  300. return ERROR_INVALID_PARAMETER;
  301. }
  302. }
  303. if (WideCharToMultiByte(CP_ACP,
  304. 0,
  305. pType,
  306. -1, // says that wchar string is null terminated
  307. entityBuf,
  308. sizeof(entityBuf),
  309. NULL,
  310. NULL) == 0)
  311. {
  312. DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pType));
  313. return GetLastError();
  314. }
  315. pNbpName->TypeNameLen = strlen( entityBuf );
  316. memcpy( pNbpName->TypeName,
  317. entityBuf,
  318. pNbpName->TypeNameLen );
  319. if (pColon != NULL)
  320. {
  321. // change the colon to a null so the object will be null terminated
  322. *pColon = 0;
  323. }
  324. //
  325. // Convert the Object string
  326. //
  327. if ((wcslen(pObject) == 0) ||
  328. (wcslen(pObject) > MAX_ENTITY))
  329. {
  330. return ERROR_INVALID_PARAMETER;
  331. }
  332. if (WideCharToMultiByte(CP_ACP,
  333. 0,
  334. pServiceName,
  335. -1, // says that wchar string is null terminated
  336. entityBuf,
  337. sizeof(entityBuf),
  338. NULL,
  339. NULL) == 0)
  340. {
  341. DBGPRINT(("GetNameInNbpFormat FAILED wctomb %ws\n", pServiceName));
  342. return GetLastError();
  343. }
  344. pNbpName->ObjectNameLen = strlen( entityBuf );
  345. memcpy( pNbpName->ObjectName,
  346. entityBuf,
  347. pNbpName->ObjectNameLen );
  348. return STATUS_SUCCESS;
  349. } // GetNameInNbpFormat
  350. NTSTATUS
  351. NbpLookupAddress(
  352. IN PWSH_NBP_NAME pNbpLookupName,
  353. IN DWORD nProt,
  354. IN OUT LPVOID lpCsAddrBuffer,
  355. IN OUT LPDWORD lpdwBufferLength,
  356. OUT LPDWORD lpcAddress
  357. )
  358. /*++
  359. Routine Description:
  360. This routine uses NBP requests to find the address of the given service
  361. name/type.
  362. Arguments:
  363. pNbpLookupName - NBP name to lookup
  364. nProt - ADSP_BIT | PAP_BIT
  365. lpCsAddrBuffer - on return, will be filled with CSADDR_INFO structures
  366. lpdwBufferLength - on input, the number of bytes contained in the buffer
  367. pointed to by lpCsAddrBuffer. On output, the minimum number of bytes
  368. to pass for the lpCsAddrBuffer to retrieve all the requested info
  369. hCancellationEvent - the event which signals us to cancel the request???
  370. lpcAddress - on output, the number of CSADDR_INFO structures returned
  371. Return Value:
  372. Win32 error code.
  373. --*/
  374. {
  375. DWORD err = NO_ERROR;
  376. NTSTATUS ntstatus;
  377. WSADATA wsaData;
  378. SOCKET socketNbp;
  379. SOCKADDR_AT socketAddr = {AF_APPLETALK, 0, 0, 0};
  380. PWSH_LOOKUP_NAME pWshLookupName;
  381. PWSH_ATALK_ADDRESS pWshATAddr;
  382. PBYTE pTmp = lpCsAddrBuffer;
  383. DWORD templen = *lpdwBufferLength;
  384. DWORD bufsize;
  385. PBYTE buf = NULL;
  386. int i;
  387. *lpcAddress = 0;
  388. //
  389. // Initialize the socket interface
  390. //
  391. err = WSAStartup( WSOCK_VER_REQD, &wsaData );
  392. if ( err )
  393. {
  394. return err;
  395. }
  396. //
  397. // Open an Appletalk datagram socket
  398. // ISSUE: should we use DDPPROTO_NBP, or just a random
  399. // dynamic DDP socket? Or an ADSP socket since we know
  400. // that works and has been tested...Does it really matter
  401. // since this only defines what devicename will be opened
  402. // in the appletalk driver i.e. \\device\\atalkddp\2 .
  403. //
  404. socketNbp = socket( AF_APPLETALK, SOCK_DGRAM, DDPPROTO_NBP);
  405. if ( socketNbp == INVALID_SOCKET )
  406. {
  407. err = WSAGetLastError();
  408. (VOID) WSACleanup();
  409. return err;
  410. }
  411. do
  412. {
  413. //
  414. // Bind the socket (this does not actually go thru
  415. // the WSHAtalk helper dll, it goes thru AFD which
  416. // Ioctls appletalk directly. The node and net values
  417. // are ignored, and socket 0 means give me a dynamic
  418. // socket number)
  419. //
  420. if ( bind( socketNbp,
  421. (PSOCKADDR) &socketAddr,
  422. sizeof( SOCKADDR_AT)) == SOCKET_ERROR )
  423. {
  424. err = WSAGetLastError();
  425. break;
  426. }
  427. //
  428. // Determine how many CSADDR_INFO structures could fit
  429. // into this buffer, then allocate a buffer to use for
  430. // the NBP lookup that can hold this many returned tuples
  431. //
  432. bufsize = sizeof(WSH_LOOKUP_NAME) +
  433. ( (*lpdwBufferLength / (sizeof(CSADDR_INFO) + (2*sizeof(SOCKADDR_AT)))) *
  434. sizeof(WSH_NBP_TUPLE) );
  435. if ((buf = LocalAlloc(LMEM_ZEROINIT, bufsize)) == NULL)
  436. {
  437. err = GetLastError();
  438. break;
  439. }
  440. // copy the NBP name to look for into the buffer
  441. pWshLookupName = (PWSH_LOOKUP_NAME)buf;
  442. pWshLookupName->LookupTuple.NbpName = *pNbpLookupName;
  443. //
  444. // Send the Nbp lookup request
  445. //
  446. if (getsockopt( socketNbp,
  447. SOL_APPLETALK,
  448. SO_LOOKUP_NAME,
  449. buf,
  450. &bufsize) != NO_ERROR)
  451. {
  452. err = WSAGetLastError();
  453. if (err == WSAENOBUFS)
  454. {
  455. // this assumes that getsockopt will NOT
  456. // put the required number of bytes into the
  457. // bufsize parameter on error
  458. *lpdwBufferLength = 2 * *lpdwBufferLength;
  459. }
  460. break;
  461. }
  462. if (pWshLookupName->NoTuples == 0)
  463. {
  464. // didn't find anything matching this NBP entity name
  465. *lpdwBufferLength = 0;
  466. break;
  467. }
  468. // point to the returned tuples
  469. pWshATAddr = (PWSH_ATALK_ADDRESS)(pWshLookupName + 1);
  470. for ( i = 0; i < (INT)pWshLookupName->NoTuples; i++ )
  471. {
  472. DWORD cAddr, bytesWritten;
  473. socketAddr.sat_net = pWshATAddr->Network;
  474. socketAddr.sat_node = pWshATAddr->Node;
  475. socketAddr.sat_socket = pWshATAddr->Socket;
  476. err = FillBufferWithCsAddr( &socketAddr,
  477. nProt,
  478. // USE LOCALS TO KEEP TRACK OF BUF POSITION AND COUNT LEFT
  479. pTmp,
  480. &templen,
  481. &cAddr);
  482. if (err != NO_ERROR)
  483. {
  484. // Fill in how many bytes the buffer should have been to
  485. // hold all the returned addresses
  486. *lpdwBufferLength = templen * pWshLookupName->NoTuples;
  487. break; // from for and then from while
  488. }
  489. else
  490. {
  491. pTmp += sizeof(CSADDR_INFO) * cAddr;
  492. templen -= (sizeof(CSADDR_INFO) + (2 * sizeof(SOCKADDR_AT))) * cAddr;
  493. *lpcAddress += cAddr; // running count of CSADDR_INFOs in buffer
  494. (PWSH_NBP_TUPLE)pWshATAddr ++; // get next NBP tuple
  495. }
  496. }
  497. } while (FALSE);
  498. //
  499. // Clean up the socket interface
  500. //
  501. if (buf != NULL)
  502. {
  503. LocalFree(buf);
  504. }
  505. closesocket( socketNbp );
  506. (VOID) WSACleanup();
  507. return err;
  508. }
  509. DWORD
  510. FillBufferWithCsAddr(
  511. IN PSOCKADDR_AT pAddress, // if NULL, then return generic appletalk socket address for RemoteAddr
  512. IN DWORD nProt,
  513. IN OUT LPVOID lpCsAddrBuffer,
  514. IN OUT LPDWORD lpdwBufferLength,
  515. OUT LPDWORD pcAddress
  516. )
  517. {
  518. DWORD nAddrCount = 0;
  519. CSADDR_INFO *pCsAddr;
  520. SOCKADDR_AT *pAddrLocal, *pAddrRemote;
  521. DWORD i;
  522. LPBYTE pBuffer;
  523. if ( nProt & ADSP_BIT )
  524. nAddrCount ++;
  525. if ( nProt & PAP_BIT )
  526. nAddrCount++;
  527. if ( *lpdwBufferLength <
  528. nAddrCount * ( sizeof( CSADDR_INFO) + 2*sizeof( SOCKADDR_AT)))
  529. {
  530. *lpdwBufferLength = nAddrCount *
  531. ( sizeof( CSADDR_INFO) + 2*sizeof( SOCKADDR_AT));
  532. return ERROR_INSUFFICIENT_BUFFER;
  533. }
  534. pBuffer = ((LPBYTE) lpCsAddrBuffer) + *lpdwBufferLength -
  535. (2*sizeof( SOCKADDR_AT) * nAddrCount);
  536. for ( i = 0, pCsAddr = (CSADDR_INFO *)lpCsAddrBuffer;
  537. (i < nAddrCount) && ( nProt != 0 );
  538. i++, pCsAddr++ )
  539. {
  540. if ( nProt & ADSP_BIT )
  541. {
  542. pCsAddr->iSocketType = SOCK_RDM;
  543. pCsAddr->iProtocol = ATPROTO_ADSP;
  544. nProt &= ~ADSP_BIT;
  545. }
  546. else if ( nProt & PAP_BIT )
  547. {
  548. pCsAddr->iSocketType = SOCK_RDM;
  549. pCsAddr->iProtocol = ATPROTO_PAP;
  550. nProt &= ~PAP_BIT;
  551. }
  552. else
  553. {
  554. break;
  555. }
  556. pCsAddr->LocalAddr.iSockaddrLength = sizeof( SOCKADDR_AT );
  557. pCsAddr->RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_AT );
  558. pCsAddr->LocalAddr.lpSockaddr = (LPSOCKADDR) pBuffer;
  559. pCsAddr->RemoteAddr.lpSockaddr =
  560. (LPSOCKADDR) ( pBuffer + sizeof(SOCKADDR_AT));
  561. pBuffer += 2 * sizeof( SOCKADDR_AT );
  562. pAddrLocal = (SOCKADDR_AT *) pCsAddr->LocalAddr.lpSockaddr;
  563. pAddrRemote = (SOCKADDR_AT *) pCsAddr->RemoteAddr.lpSockaddr;
  564. pAddrLocal->sat_family = AF_APPLETALK;
  565. pAddrRemote->sat_family = AF_APPLETALK;
  566. //
  567. // The default local sockaddr for ADSP and PAP is
  568. // sa_family = AF_APPLETALK and all other bytes = 0.
  569. //
  570. pAddrLocal->sat_net = 0;
  571. pAddrLocal->sat_node = 0;
  572. pAddrLocal->sat_socket = 0;
  573. //
  574. // If pAddress is NULL, i.e. we are doing RES_SERVICE,
  575. // just make all bytes in remote address zero.
  576. //
  577. if ( pAddress == NULL )
  578. {
  579. pAddrRemote->sat_net = 0;
  580. pAddrRemote->sat_node = 0;
  581. pAddrRemote->sat_socket = 0;
  582. }
  583. else
  584. {
  585. pAddrRemote->sat_net = pAddress->sat_net;
  586. pAddrRemote->sat_node = pAddress->sat_node;
  587. pAddrRemote->sat_socket = pAddress->sat_socket;
  588. }
  589. }
  590. *pcAddress = nAddrCount;
  591. return NO_ERROR;
  592. } // FillBufferWithCSAddr
  593. NTSTATUS
  594. NbpSetService (
  595. IN DWORD dwOperation,
  596. IN DWORD dwFlags,
  597. IN BOOL fUnicodeBlob,
  598. IN LPSERVICE_INFO lpServiceInfo
  599. )
  600. /*++
  601. Routine Description:
  602. This routine registers or deregisters the given service type/name on NBP.
  603. Arguments:
  604. dwOperation - Either SERVICE_REGISTER or SERVICE_DEREGISTER
  605. dwFlags - ignored
  606. fUnicodeBlob - ignored
  607. lpServiceInfo - Pointer to a SERVICE_INFO structure containing all info
  608. about the service.
  609. Return Value:
  610. Win32 error code.
  611. --*/
  612. {
  613. NTSTATUS err = STATUS_SUCCESS;
  614. SOCKADDR_AT sockAddr;
  615. WSH_NBP_NAME nbpName;
  616. DWORD i;
  617. INT nNBP = -1;
  618. UNREFERENCED_PARAMETER( dwFlags );
  619. UNREFERENCED_PARAMETER( fUnicodeBlob );
  620. DBGPRINT(("NbpSetService entered...\n"));
  621. //
  622. // Check for invalid parameters
  623. //
  624. if ( ( lpServiceInfo == NULL )
  625. || ( lpServiceInfo->lpServiceType == NULL )
  626. || ( lpServiceInfo->lpServiceName == NULL ) )
  627. {
  628. return ERROR_INVALID_PARAMETER;
  629. }
  630. if ( lpServiceInfo->lpServiceAddress == NULL )
  631. return ERROR_INCORRECT_ADDRESS;
  632. switch (dwOperation)
  633. {
  634. case SERVICE_REGISTER:
  635. case SERVICE_DEREGISTER:
  636. {
  637. //
  638. // Check to see if the service address array contains NBP address,
  639. // we will only use the first NBP address contained in the array.
  640. //
  641. for ( i = 0; i < lpServiceInfo->lpServiceAddress->dwAddressCount; i++)
  642. {
  643. if ( lpServiceInfo->lpServiceAddress->Addresses[i].dwAddressType == AF_APPLETALK )
  644. {
  645. sockAddr = *(PSOCKADDR_AT)(lpServiceInfo->lpServiceAddress->Addresses[i].lpAddress);
  646. nNBP = (INT) i;
  647. break;
  648. }
  649. }
  650. //
  651. // If we cannot find a atalk address in the user's array, return error
  652. //
  653. if ( nNBP == -1 )
  654. {
  655. DBGPRINT(("NbpSetService: no Appletalk addresses in lpServiceInfo!\n"));
  656. return ERROR_INCORRECT_ADDRESS;
  657. }
  658. //
  659. // Convert the service type and name into NBP form
  660. //
  661. err = GetNameInNbpFormat(lpServiceInfo->lpServiceType,
  662. lpServiceInfo->lpServiceName,
  663. &nbpName);
  664. if (err != NO_ERROR)
  665. {
  666. break;
  667. }
  668. err = NbpRegDeregService(dwOperation, &nbpName, &sockAddr);
  669. break;
  670. }
  671. case SERVICE_FLUSH:
  672. case SERVICE_ADD_TYPE:
  673. case SERVICE_DELETE_TYPE:
  674. //
  675. // This is a no-op in our provider, so just return success
  676. //
  677. return NO_ERROR;
  678. default:
  679. //
  680. // We can probably say all other operations which we have no
  681. // knowledge of are ignored by us. So, just return success.
  682. //
  683. return NO_ERROR;
  684. }
  685. return err;
  686. }
  687. DWORD
  688. NbpRegDeregService(
  689. IN DWORD dwOperation,
  690. IN PWSH_NBP_NAME pNbpName,
  691. IN PSOCKADDR_AT pSockAddr
  692. )
  693. /*++
  694. Routine Description:
  695. This routine registers or deregisters the given service on NBP.
  696. Arguments:
  697. dwOperation - either SERVICE_REGISTER or SERVICE_DEREGISTER
  698. pNbpName - points to NBP name to register (zone should be "*")
  699. pSockAddr - socket address on which to register name
  700. Return Value:
  701. Win32 error.
  702. --*/
  703. {
  704. int status;
  705. BYTE EaBuffer[sizeof(FILE_FULL_EA_INFORMATION) +
  706. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  707. sizeof(TA_APPLETALK_ADDRESS)];
  708. PFILE_FULL_EA_INFORMATION pEaBuf = (PFILE_FULL_EA_INFORMATION)EaBuffer;
  709. TA_APPLETALK_ADDRESS Ta;
  710. OBJECT_ATTRIBUTES ObjAttr;
  711. UNICODE_STRING DeviceName;
  712. IO_STATUS_BLOCK IoStsBlk;
  713. NBP_TUPLE nbpTuple;
  714. SOCKET bogusSocket = 0;
  715. HANDLE AtalkAddressHandle = NULL, eventHandle = NULL;
  716. PTDI_ACTION_HEADER tdiAction;
  717. ULONG tdiActionLength;
  718. BOOLEAN freeTdiAction = FALSE, closeEventHandle = FALSE;
  719. PNBP_REGDEREG_ACTION nbpAction;
  720. PVOID completionApc = NULL;
  721. PVOID apcContext = NULL;
  722. DBGPRINT(("NbpRegDeregService entered...\n"));
  723. DebugBreak();
  724. // Dosn't matter what protocol or socket we open, we just want a
  725. // device handle into the stack.
  726. RtlInitUnicodeString(&DeviceName, WSH_ATALK_ADSPRDM);
  727. InitializeObjectAttributes(&ObjAttr, &DeviceName, 0, NULL, NULL);
  728. // Initialize the EA Buffer
  729. pEaBuf->NextEntryOffset = 0;
  730. pEaBuf->Flags = 0;
  731. pEaBuf->EaValueLength = sizeof(TA_APPLETALK_ADDRESS);
  732. pEaBuf->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  733. RtlCopyMemory(pEaBuf->EaName,TdiTransportAddress,
  734. TDI_TRANSPORT_ADDRESS_LENGTH + 1);
  735. Ta.TAAddressCount = 1;
  736. Ta.Address[0].AddressType = TDI_ADDRESS_TYPE_APPLETALK;
  737. Ta.Address[0].AddressLength = sizeof(TDI_ADDRESS_APPLETALK);
  738. // Open dynamic socket - note we will be using up one extra socket for the
  739. // duration we have the device handle open in this routine.
  740. Ta.Address[0].Address[0].Socket = 0;
  741. Ta.Address[0].Address[0].Network = 0;
  742. Ta.Address[0].Address[0].Node = 0;
  743. RtlCopyMemory(&pEaBuf->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1], &Ta, sizeof(Ta));
  744. // Open a handle to appletalk stack DDP device
  745. status = NtCreateFile(
  746. &AtalkAddressHandle,
  747. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  748. &ObjAttr,
  749. &IoStsBlk,
  750. NULL, // Don't Care
  751. 0, // Don't Care
  752. FILE_SHARE_READ | FILE_SHARE_WRITE,
  753. FILE_CREATE,
  754. 0,
  755. &EaBuffer,
  756. sizeof(EaBuffer));
  757. if (!NT_SUCCESS(status))
  758. {
  759. DBGPRINT(("NbpRegDeregService: NtCreateFile failed (0x%x)\n", status));
  760. return WSHNtStatusToWinsockErr(status);
  761. }
  762. do
  763. {
  764. status = NtCreateEvent(
  765. &eventHandle,
  766. EVENT_ALL_ACCESS,
  767. NULL,
  768. SynchronizationEvent,
  769. FALSE
  770. );
  771. if ( !NT_SUCCESS(status) )
  772. {
  773. DBGPRINT(("NbpRegDeregService: Create event failed (%d)\n", status));
  774. break;
  775. }
  776. else
  777. closeEventHandle = TRUE;
  778. tdiActionLength = sizeof(NBP_REGDEREG_ACTION);
  779. tdiAction = RtlAllocateHeap( RtlProcessHeap( ), 0, tdiActionLength );
  780. if ( tdiAction == NULL )
  781. {
  782. status = STATUS_NO_MEMORY;
  783. DBGPRINT(("NbpRegDeregService: Could not allocate tdiAction\n"));
  784. break;
  785. }
  786. else
  787. freeTdiAction = TRUE;
  788. tdiAction->TransportId = MATK;
  789. tdiAction->ActionCode = (dwOperation == SERVICE_REGISTER) ?
  790. COMMON_ACTION_NBPREGISTER_BY_ADDR :
  791. COMMON_ACTION_NBPREMOVE_BY_ADDR;
  792. nbpAction = (PNBP_REGDEREG_ACTION)tdiAction;
  793. //
  794. // Copy the nbp tuple info to the proper place
  795. //
  796. nbpAction->Params.RegisterTuple.Address.Network = pSockAddr->sat_net;
  797. nbpAction->Params.RegisterTuple.Address.Node = pSockAddr->sat_node;
  798. nbpAction->Params.RegisterTuple.Address.Socket = pSockAddr->sat_socket;
  799. nbpAction->Params.RegisterTuple.Enumerator = 0;
  800. nbpAction->Params.RegisterTuple.NbpName = *((PNBP_NAME)pNbpName);
  801. //
  802. // Convert the tuple to MAC code page
  803. //
  804. if (!WshNbpNameToMacCodePage(
  805. (PWSH_NBP_NAME)&nbpAction->Params.RegisterTuple.NbpName))
  806. {
  807. status = STATUS_INVALID_PARAMETER;
  808. break;
  809. }
  810. status = NtDeviceIoControlFile(
  811. AtalkAddressHandle,
  812. eventHandle,
  813. completionApc,
  814. apcContext,
  815. &IoStsBlk,
  816. IOCTL_TDI_ACTION,
  817. NULL, // Input buffer
  818. 0, // Length of input buffer
  819. tdiAction,
  820. tdiActionLength
  821. );
  822. if ( status == STATUS_PENDING )
  823. {
  824. status = NtWaitForSingleObject( eventHandle, FALSE, NULL );
  825. ASSERT( NT_SUCCESS(status) );
  826. status = IoStsBlk.Status;
  827. }
  828. if (status != NO_ERROR)
  829. {
  830. DBGPRINT(("NbpRegDeregService: DevIoctl SO_(DE)REGISTER_NAME failed (0x%x)\n", status));
  831. }
  832. } while (0);
  833. if (closeEventHandle)
  834. NtClose(eventHandle);
  835. if (freeTdiAction)
  836. RtlFreeHeap( RtlProcessHeap( ), 0, tdiAction );
  837. NtClose(AtalkAddressHandle);
  838. return WSHNtStatusToWinsockErr(status);
  839. }
  840.