Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1566 lines
39 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: ipxname.cxx
  8. //
  9. //--------------------------------------------------------------------------
  10. /*++
  11. Module Name:
  12. gethost.c
  13. Abstract:
  14. Maps a server name to SPX address by consulting the Netware Bindery.
  15. Attach/Detach/FindFileServer, and ReadPropertyValue were all borrowed
  16. from the SQL 6.0 code base.
  17. Author:
  18. Jeff Roberts (jroberts) 20-Nov-1995
  19. Revision History:
  20. 20-Nov-1995 (jroberts) Took code from AndreasK of SQL Server, and modified
  21. it for RPC.
  22. 24-Jan-1997 (MarioGo) C++ and cache cleanup work.
  23. --*/
  24. #include <precomp.hxx>
  25. #include <CharConv.hxx>
  26. const GUID SERVICE_TYPE = { 0x000b0640, 0, 0, { 0xC0,0,0,0,0,0,0,0x46 } };
  27. #define CRITICAL_SECTION_WRAPPER RTL_CRITICAL_SECTION
  28. #define MAX_FILESRVS 5 /* try 5 servers (chicago uses this same number) */
  29. /***** NETWARE MAGIC NUMBERS *****/
  30. #define NSPROTO_NCP (NSPROTO_IPX+0x11)
  31. /* NCP Request Types */
  32. #define CREATE_CONN_REQTYPE 0x1111
  33. #define DESTROY_CONN_REQYPE 0x5555
  34. #define GENERAL_REQTYPE 0x2222
  35. /* NCP Request Codes */
  36. #define NCP_SCAN_BINDERY 0x17
  37. #define NCP_END_OF_TASK 0x18
  38. #define NCP_LOGOUT 0x19
  39. #define NCP_NEG_BUFFER_SIZE 0x21
  40. /* NCP Function codes */
  41. #define SCAN_BINDERY_FUNC 0x37
  42. #define READ_PROP_VALUE_FUNC 0x3D
  43. /* SAP protocol request codes */
  44. #define SAP_GENERAL_QUERY 0x0100 /* general query hi-lo */
  45. #define SAP_GENERAL_RESPONSE 0x0200 /* general response hi-lo */
  46. #define SAP_NEAREST_QUERY 0x0300 /* nearest query hi-lo */
  47. #define SAP_NEAREST_RESPONSE 0x0400 /* nearest response hi-lo */
  48. /* Socket Numbers */
  49. #define NCP_SOCKET 0x5104 /* SAP socket hi-lo */
  50. #define SAP_SOCKET 0x5204 /* SAP socket hi-lo */
  51. #define GUEST_SOCKET 0x1840
  52. /* SAP Service Types */
  53. #define FILE_SERVER 0x0400 /* netware file server hi-lo */
  54. #define SNA_SERVER 0x4404 /* SNA Server type 0x0444 */
  55. #define BRIDGE_SERVER 0x2400
  56. #define SAP_SERVICE_STOPPED 0x1000 /* invalid hub count, hi-lo */
  57. #define SAP_TIMEOUT 60000 /* SAP timeout, one minute */
  58. #define NCP_CONNECTION_ERROR 0x15 /* connection error mask */
  59. #define BINDERY_FAILURE 0x00FF /* bindery call failed */
  60. #define RPC_SAP_TYPE 0x0640
  61. #define SWAP(x) RpcpByteSwapShort(x)
  62. typedef struct
  63. {
  64. CSADDR_INFO info;
  65. SOCKADDR_IPX addr1;
  66. SOCKADDR_IPX addr2;
  67. } CSADDR_BUFFER;
  68. #pragma pack(1)
  69. typedef struct _sip_entry
  70. {
  71. char server_name[48];
  72. unsigned long network;
  73. char node[6];
  74. unsigned short socket;
  75. unsigned short hops;
  76. } SIP_ENTRY;
  77. typedef struct _sip /* Service Information Packet */
  78. {
  79. unsigned short response_type;
  80. unsigned short server_type;
  81. SIP_ENTRY entries[7];
  82. } SIP;
  83. typedef struct /* Service Query Packet */
  84. {
  85. unsigned short query_type;
  86. unsigned short server_type;
  87. } SQP;
  88. typedef struct /* NCP Request Header */
  89. {
  90. unsigned short req_type;
  91. unsigned char seq_no;
  92. unsigned char conn_no_low;
  93. unsigned char task_no;
  94. unsigned char conn_no_high;
  95. unsigned char req_code;
  96. } NCPHDR;
  97. typedef struct /* NCP Response Header */
  98. {
  99. unsigned short req_type;
  100. unsigned char seq_no;
  101. unsigned char conn_no_low;
  102. unsigned char task_no;
  103. unsigned char conn_no_high;
  104. unsigned char ret_code;
  105. unsigned char conn_status;
  106. } NCPRSP;
  107. typedef struct /* Scan Bindery Request */
  108. {
  109. NCPHDR hdr;
  110. unsigned short length;
  111. unsigned char func_code;
  112. unsigned long last_id;
  113. unsigned short obj_type;
  114. unsigned char sstring[49];
  115. } SCANREQ;
  116. #define SCANSIZE 56
  117. typedef struct /* Scan Bindery Response */
  118. {
  119. NCPRSP hdr;
  120. unsigned long obj_id;
  121. unsigned short obj_type;
  122. unsigned char obj_name[48];
  123. unsigned char obj_status;
  124. unsigned char sec_status;
  125. unsigned char status_flags;
  126. } SCANRSP;
  127. typedef struct /* Read Propery Value */
  128. {
  129. NCPHDR hdr;
  130. unsigned short length;
  131. unsigned char func_code;
  132. unsigned short obj_type;
  133. unsigned char obj_name[49];
  134. unsigned char seg_no;
  135. unsigned char prop_name[17];
  136. } RVALREQ;
  137. #define RVALSIZE 70
  138. typedef struct /* Read Propery Value Response */
  139. {
  140. NCPRSP hdr;
  141. unsigned char prop_value[128];
  142. unsigned char more_flag;
  143. unsigned char prop_flags;
  144. } RVALRSP;
  145. #pragma pack()
  146. #define BUFFER_SIZE 1024 /* Size of send and recv buffer */
  147. struct
  148. {
  149. SOCKADDR_IPX nsRemote[MAX_FILESRVS]; /* Remote IPX addresses */
  150. unsigned ServerCount; /* number of valid entries in nsRemote */
  151. unsigned ActiveServer; /* index of the the address in use */
  152. SOCKET s; /* Socket handle */
  153. unsigned short ConnectionId;
  154. NCPHDR *nhHeader; /* Last NCP header sent */
  155. char *RcvBuffer;
  156. }
  157. nsStatus;
  158. typedef struct IPXAddress
  159. {
  160. char network[4];
  161. char node[6];
  162. unsigned short socket;
  163. } IPXAddress;
  164. int FindFileServers();
  165. BOOL AttachToFileServer();
  166. BOOL ConnectToActiveServer();
  167. BOOL DetachFromActiveServer();
  168. int SendPacket( SOCKET, char *, int, SOCKADDR *, DWORD );
  169. USHORT ReadPropertyValue( char *, USHORT, char *, USHORT, UCHAR *,
  170. UCHAR *, UCHAR * );
  171. int
  172. NcpTransaction(
  173. int iSize
  174. );
  175. DWORD
  176. InitializeCriticalSectionWrapper(
  177. RTL_CRITICAL_SECTION * Mutex
  178. )
  179. {
  180. NTSTATUS NtStatus;
  181. NtStatus = RtlInitializeCriticalSection(Mutex);
  182. if (!NT_SUCCESS(NtStatus))
  183. {
  184. return RtlNtStatusToDosError(NtStatus);
  185. }
  186. return(NO_ERROR);
  187. }
  188. DWORD
  189. DeleteCriticalSectionWrapper(
  190. RTL_CRITICAL_SECTION * Mutex
  191. )
  192. {
  193. NTSTATUS NtStatus;
  194. NtStatus = RtlDeleteCriticalSection(Mutex);
  195. if (!NT_SUCCESS(NtStatus))
  196. {
  197. return RtlNtStatusToDosError(NtStatus);
  198. }
  199. return(NO_ERROR);
  200. }
  201. DWORD
  202. EnterCriticalSectionWrapper(
  203. RTL_CRITICAL_SECTION * Mutex
  204. )
  205. {
  206. NTSTATUS NtStatus;
  207. NtStatus = RtlEnterCriticalSection(Mutex);
  208. if (!NT_SUCCESS(NtStatus))
  209. {
  210. return RtlNtStatusToDosError(NtStatus);
  211. }
  212. return(NO_ERROR);
  213. }
  214. DWORD
  215. LeaveCriticalSectionWrapper(
  216. RTL_CRITICAL_SECTION * Mutex
  217. )
  218. {
  219. NTSTATUS NtStatus;
  220. NtStatus = RtlLeaveCriticalSection(Mutex);
  221. ASSERT (NT_SUCCESS(NtStatus));
  222. return(NO_ERROR);
  223. }
  224. BOOL
  225. AttachToFileServer(
  226. )
  227. //**************************************************************************
  228. //
  229. // This function creates an attachment between an NT workstation and
  230. // a Novell Netware file server.
  231. //
  232. // Params:
  233. // USHORT *pConectionID - Receives the connection ID for the newly
  234. // attached file server
  235. // LOBYTE(ConnectionID) = conn_no_low
  236. // HIBYTE(ConnectionID) = conn_no_high
  237. //
  238. // Return Values:
  239. //
  240. // TRUE - successful
  241. // FALSE - unsuccessful
  242. //
  243. //***************************************************************************
  244. {
  245. DWORD IDThread;
  246. unsigned i;
  247. char scratch[2];
  248. SOCKET s;
  249. SOCKADDR_IPX nsAddr;
  250. unsigned Timeout;
  251. s = socket( AF_NS, SOCK_DGRAM, NSPROTO_NCP );
  252. if ( s == INVALID_SOCKET )
  253. {
  254. return FALSE;
  255. }
  256. //
  257. // Set the receive timeout.
  258. //
  259. Timeout = 3000;
  260. if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &Timeout, sizeof(Timeout)))
  261. {
  262. closesocket(s);
  263. return FALSE;
  264. }
  265. memset( &nsAddr, '\0', sizeof(SOCKADDR_IPX) );
  266. nsAddr.sa_family = AF_NS;
  267. if (SOCKET_ERROR == bind(s, (SOCKADDR *)&nsAddr, sizeof(SOCKADDR_IPX)) )
  268. {
  269. closesocket(s);
  270. return FALSE;
  271. }
  272. nsStatus.s = s;
  273. /* Find the nearest file server. */
  274. if( nsStatus.ServerCount )
  275. {
  276. for (i=0; i < nsStatus.ServerCount; i++)
  277. {
  278. nsStatus.ActiveServer = i;
  279. if( ConnectToActiveServer() )
  280. {
  281. nsStatus.ConnectionId = nsStatus.nhHeader->conn_no_low + (nsStatus.nhHeader->conn_no_high << 8);
  282. return TRUE;
  283. }
  284. }
  285. }
  286. FindFileServers();
  287. if( nsStatus.ServerCount )
  288. {
  289. for (i=0; i < nsStatus.ServerCount; i++)
  290. {
  291. nsStatus.ActiveServer = i;
  292. if( ConnectToActiveServer() )
  293. {
  294. nsStatus.ConnectionId = nsStatus.nhHeader->conn_no_low + (nsStatus.nhHeader->conn_no_high << 8);
  295. return TRUE;
  296. }
  297. }
  298. }
  299. closesocket(s);
  300. nsStatus.s = 0;
  301. return FALSE;
  302. }
  303. int
  304. FindFileServers(
  305. )
  306. /****************************************************************************/
  307. /* */
  308. /* This function uses the SAP (Service Advertise Protocol) Find Nearest */
  309. /* query to find a netware file server. */
  310. /* */
  311. /* Returns: */
  312. /* Number of servers found (0 - MAX_FILESRVS) */
  313. /* */
  314. /****************************************************************************/
  315. {
  316. SOCKET s;
  317. BOOL bBcst;
  318. SQP sqp;
  319. SIP sip;
  320. unsigned Timeout;
  321. SOCKADDR_IPX raddr;
  322. SOCKADDR_IPX nsAddr;
  323. //
  324. // Create a socket for the SAP broadcast.
  325. //
  326. s = socket( AF_NS, SOCK_DGRAM, NSPROTO_IPX );
  327. if( s == INVALID_SOCKET )
  328. {
  329. return 0;
  330. }
  331. memset( &nsAddr, '\0', sizeof(SOCKADDR_IPX) );
  332. nsAddr.sa_family = AF_NS;
  333. if(SOCKET_ERROR == bind(s, (SOCKADDR *)&nsAddr, sizeof(SOCKADDR_IPX)) )
  334. {
  335. closesocket(s);
  336. return 0;
  337. }
  338. //
  339. // Enable broadcasts.
  340. //
  341. bBcst = TRUE;
  342. if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&bBcst, sizeof(BOOL)))
  343. {
  344. closesocket(s);
  345. return 0;
  346. }
  347. //
  348. // Set the receive timeout.
  349. //
  350. Timeout = 2000;
  351. if (SOCKET_ERROR == setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &Timeout, sizeof(Timeout)))
  352. {
  353. closesocket(s);
  354. return 0;
  355. }
  356. //
  357. // Build a SAP query packet.
  358. //
  359. sqp.query_type = SAP_NEAREST_QUERY;
  360. sqp.server_type = FILE_SERVER;
  361. raddr.sa_family = AF_NS;
  362. *((unsigned long UNALIGNED *) &raddr.sa_netnum) = 0;
  363. memset( &raddr.sa_nodenum, 0xff, 6 );
  364. raddr.sa_socket = SAP_SOCKET;
  365. //
  366. // Send the SAP request.
  367. //
  368. if (SOCKET_ERROR == sendto( s, (char *) &sqp, sizeof(SQP), 0, (SOCKADDR *) &raddr, sizeof(SOCKADDR_IPX) ))
  369. {
  370. closesocket(s);
  371. return 0;
  372. }
  373. //
  374. // Collate responses.
  375. //
  376. nsStatus.ServerCount = 0;
  377. do
  378. {
  379. unsigned length;
  380. irrelevant_packet:
  381. length = recvfrom(s, (char *) &sip, sizeof(sip), 0, 0, 0);
  382. if (SOCKET_ERROR == length)
  383. {
  384. break;
  385. }
  386. //
  387. // IPX router spec says find nearest responses can contain only one
  388. // entry.
  389. //
  390. if (length != sizeof(sip) - sizeof(sip.entries) + sizeof(SIP_ENTRY))
  391. {
  392. goto irrelevant_packet;
  393. }
  394. if (sip.response_type != SAP_NEAREST_RESPONSE)
  395. {
  396. goto irrelevant_packet;
  397. }
  398. if (sip.server_type != FILE_SERVER)
  399. {
  400. goto irrelevant_packet;
  401. }
  402. nsStatus.nsRemote[nsStatus.ServerCount].sa_family = AF_NS;
  403. nsStatus.nsRemote[nsStatus.ServerCount].sa_socket = NCP_SOCKET;
  404. memcpy( &nsStatus.nsRemote[nsStatus.ServerCount].sa_netnum,
  405. &sip.entries[0].network,
  406. sizeof(sip.entries[0].network)+sizeof(sip.entries[0].node)
  407. );
  408. }
  409. while ( ++nsStatus.ServerCount < MAX_FILESRVS );
  410. closesocket(s);
  411. return nsStatus.ServerCount;
  412. }
  413. BOOL
  414. ConnectToActiveServer(
  415. )
  416. /****************************************************************************/
  417. /* */
  418. /* This function creates a NCP connection between the local workstation */
  419. /* and the specified file server. It sends the following NCP packets to */
  420. /* the file server: */
  421. /* 1. Create Connection */
  422. /* 2. Negotiate Buffer Size */
  423. /* */
  424. /* Params: */
  425. /* SOCKADDR_IPX *ipxDest - server's IPX address */
  426. /* */
  427. /* Returns: */
  428. /* TRUE - SUCCEEDED */
  429. /* FALSE - FAILED */
  430. /* */
  431. /****************************************************************************/
  432. {
  433. SOCKADDR_IPX nsAddr;
  434. NCPHDR *pnhReq;
  435. NCPRSP *pnrResp;
  436. USHORT UNALIGNED *pwBufSize;
  437. BOOL fSuccess;
  438. //
  439. // Build a CREATE_CONNECTION request.
  440. //
  441. memset( nsStatus.nhHeader, '\0', sizeof(NCPHDR));
  442. pnhReq = nsStatus.nhHeader;
  443. pnhReq->req_type = CREATE_CONN_REQTYPE;
  444. pnhReq->seq_no = 0; /* reset sequence number */
  445. pnhReq->conn_no_low = 0xFF; /* no connection yet */
  446. pnhReq->conn_no_high = 0xFF; /* no connection yet */
  447. pnhReq->task_no = 0;
  448. pnhReq->req_code = 0;
  449. //
  450. // Send the packet and wait for response.
  451. //
  452. fSuccess = FALSE;
  453. if (SOCKET_ERROR != NcpTransaction(sizeof(NCPHDR)) )
  454. {
  455. /* Save our connection number, it is used in all the subsequent */
  456. /* NCP packets. */
  457. pnrResp = (NCPRSP *)nsStatus.RcvBuffer;
  458. if ( pnrResp->ret_code == 0 )
  459. {
  460. nsStatus.nhHeader->conn_no_low = pnrResp->conn_no_low;
  461. nsStatus.nhHeader->conn_no_high = pnrResp->conn_no_high;
  462. fSuccess = TRUE;
  463. }
  464. }
  465. return fSuccess;
  466. }
  467. BOOL
  468. DetachFromActiveServer(
  469. )
  470. /****************************************************************************/
  471. /* */
  472. /* This function logs out the bindery object and detaches the workstation */
  473. /* from the specified file server. */
  474. /* */
  475. /* Params: */
  476. /* none
  477. /* */
  478. /* Returns: */
  479. /* TRUE - Always */
  480. /* */
  481. /****************************************************************************/
  482. {
  483. int iret;
  484. if (0 == nsStatus.s)
  485. {
  486. return TRUE;
  487. }
  488. nsStatus.nhHeader->req_type = DESTROY_CONN_REQYPE;
  489. nsStatus.nhHeader->seq_no++;
  490. nsStatus.nhHeader->req_code = 0;
  491. NcpTransaction(sizeof(NCPHDR));
  492. closesocket( nsStatus.s );
  493. nsStatus.s = 0;
  494. return TRUE;
  495. }
  496. USHORT
  497. ReadPropertyValue(
  498. char *ObjectName,
  499. USHORT ObjectType,
  500. char *PropertyName,
  501. USHORT SegmentNumber,
  502. UCHAR *PropertyValue,
  503. UCHAR *MoreSegments,
  504. UCHAR *PropertyFlags
  505. )
  506. {
  507. /*++
  508. Routine Description:
  509. Arguments:
  510. Return Value:
  511. --*/
  512. RVALREQ *pReq;
  513. RVALRSP *pRsp;
  514. int iRet;
  515. if ( !nsStatus.s )
  516. {
  517. return BINDERY_FAILURE;
  518. }
  519. /* Build a SCAN_BINDERY request */
  520. pReq = (RVALREQ *) nsStatus.nhHeader;
  521. pReq->hdr.seq_no++;
  522. pReq->hdr.req_code = NCP_SCAN_BINDERY;
  523. pReq->hdr.req_type = GENERAL_REQTYPE;
  524. pReq->func_code = READ_PROP_VALUE_FUNC;
  525. pReq->length = SWAP(RVALSIZE);
  526. pReq->obj_type = SWAP(ObjectType);
  527. memset( pReq->obj_name, '\0', sizeof(pReq->obj_name));
  528. strcpy((PCHAR)pReq->obj_name+1, ObjectName );
  529. pReq->obj_name[0] = (UCHAR)(sizeof(pReq->obj_name)-1);
  530. pReq->seg_no = (UCHAR)SegmentNumber;
  531. memset( pReq->prop_name, '\0', sizeof(pReq->prop_name));
  532. strcpy((PCHAR)pReq->prop_name+1, PropertyName );
  533. pReq->prop_name[0] = (UCHAR)strlen(PropertyName);
  534. /* Send the request and wait for response */
  535. iRet = NcpTransaction(sizeof(RVALREQ));
  536. /* If OK set output parameter values from the response packet */
  537. if ( iRet != SOCKET_ERROR )
  538. {
  539. pRsp = (RVALRSP *) nsStatus.RcvBuffer;
  540. if ( pRsp->hdr.ret_code == 0 )
  541. {
  542. *MoreSegments = pRsp->more_flag;
  543. *PropertyFlags = pRsp->prop_flags;
  544. memcpy( PropertyValue, pRsp->prop_value, sizeof(pRsp->prop_value));
  545. }
  546. return((USHORT)pRsp->hdr.ret_code);
  547. }
  548. return(BINDERY_FAILURE);
  549. }
  550. int
  551. NcpTransaction(
  552. int iSize
  553. )
  554. {
  555. /*++
  556. Routine Description:
  557. Send an NCP request to the active file server and wait for a response.
  558. Most necessary data has been stored in the nsStatus structure by
  559. the caller.
  560. Arguments:
  561. iSize - size of buffer to send.
  562. Return Value:
  563. SOCKET_ERROR if the fn failed,
  564. anything else if successful
  565. --*/
  566. NCPRSP * pRsp;
  567. SOCKADDR_IPX SockAddr;
  568. int SockAddrLength;
  569. int Bytes;
  570. int Attempts = 0;
  571. /* Send the packet and retry three times if the response doesn't */
  572. /* arrive within the specified timeout */
  573. SockAddrLength = sizeof(SOCKADDR_IPX);
  574. pRsp = (NCPRSP *) nsStatus.RcvBuffer;
  575. do
  576. {
  577. if (SOCKET_ERROR == sendto( nsStatus.s,
  578. (char *) nsStatus.nhHeader,
  579. iSize,
  580. 0,
  581. (SOCKADDR *) &nsStatus.nsRemote[nsStatus.ActiveServer],
  582. sizeof(SOCKADDR_IPX)
  583. ))
  584. {
  585. return SOCKET_ERROR;
  586. }
  587. irrelevant_packet:
  588. Bytes = recvfrom( nsStatus.s,
  589. nsStatus.RcvBuffer,
  590. BUFFER_SIZE,
  591. 0,
  592. (SOCKADDR *) &SockAddr,
  593. &SockAddrLength
  594. );
  595. //
  596. // If we get a packet, compare the source address and sequence #.
  597. // We also compare the connection number except on the initial
  598. // connection request.
  599. //
  600. if (Bytes != SOCKET_ERROR)
  601. {
  602. if (0 != memcmp(SockAddr.sa_nodenum,
  603. nsStatus.nsRemote[nsStatus.ActiveServer].sa_nodenum,
  604. 6))
  605. {
  606. goto irrelevant_packet;
  607. }
  608. if (0 != memcmp(SockAddr.sa_netnum,
  609. nsStatus.nsRemote[nsStatus.ActiveServer].sa_netnum,
  610. 4))
  611. {
  612. goto irrelevant_packet;
  613. }
  614. if (nsStatus.nhHeader->req_type != CREATE_CONN_REQTYPE)
  615. {
  616. if (pRsp->conn_no_low != nsStatus.nhHeader->conn_no_low ||
  617. pRsp->conn_no_high != nsStatus.nhHeader->conn_no_high)
  618. {
  619. goto irrelevant_packet;
  620. }
  621. }
  622. if (pRsp->seq_no != nsStatus.nhHeader->seq_no )
  623. {
  624. goto irrelevant_packet;
  625. }
  626. }
  627. }
  628. while ( Bytes == SOCKET_ERROR && WSAGetLastError() == WSAETIMEDOUT && ++Attempts < 3 );
  629. return Bytes;
  630. }
  631. CRITICAL_SECTION_WRAPPER FileServerMutex;
  632. BOOL fCsnwCheckCompleted = FALSE;
  633. BOOL fCsnwInstalled = FALSE;
  634. DWORD
  635. GetCsnwStatus(
  636. LPSERVICE_STATUS pServiceStatus
  637. )
  638. {
  639. SC_HANDLE ServiceController;
  640. SC_HANDLE Csnw;
  641. DWORD status;
  642. ServiceController = OpenSCManager (NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
  643. if (NULL == ServiceController)
  644. {
  645. return GetLastError();
  646. }
  647. Csnw = OpenService(ServiceController, L"NWCWorkstation", SERVICE_QUERY_STATUS);
  648. status = GetLastError();
  649. CloseServiceHandle(ServiceController);
  650. if (NULL == Csnw)
  651. {
  652. return(status);
  653. }
  654. if (FALSE == QueryServiceStatus(Csnw, pServiceStatus))
  655. {
  656. status = GetLastError();
  657. }
  658. else
  659. {
  660. status = 0;
  661. }
  662. CloseServiceHandle(Csnw);
  663. return status;
  664. }
  665. void
  666. CheckForCsnw(
  667. )
  668. /*++
  669. Routine Description:
  670. Asks the service controller whether Client Services for Netware is installed.
  671. Arguments:
  672. none
  673. Return Value:
  674. no explicit return value
  675. updates fKnowCsnwInstallState and fCsnwInstalled
  676. --*/
  677. {
  678. DWORD Status;
  679. SERVICE_STATUS ServiceStatus;
  680. Status = GetCsnwStatus(&ServiceStatus);
  681. if (Status && Status != ERROR_SERVICE_DOES_NOT_EXIST)
  682. {
  683. return;
  684. }
  685. if (!Status)
  686. {
  687. if (ServiceStatus.dwCurrentState == SERVICE_RUNNING ||
  688. ServiceStatus.dwCurrentState == SERVICE_START_PENDING ||
  689. ServiceStatus.dwCurrentState == SERVICE_CONTINUE_PENDING )
  690. {
  691. fCsnwInstalled = TRUE;
  692. }
  693. }
  694. fCsnwCheckCompleted = TRUE;
  695. }
  696. struct
  697. {
  698. PCHAR Name;
  699. SOCKADDR_IPX Address;
  700. unsigned Time;
  701. }
  702. ServerCache[CACHE_SIZE];
  703. CRITICAL_SECTION_WRAPPER CacheMutex;
  704. RPC_STATUS
  705. InitializeIpxNameCache(
  706. )
  707. {
  708. static BOOL fInitialized = FALSE;
  709. if (fInitialized)
  710. {
  711. return(RPC_S_OK);
  712. }
  713. RPC_STATUS Status;
  714. PVOID Buffer0, Buffer1;
  715. Buffer0 = I_RpcAllocate(1024);
  716. if (Buffer0 == NULL)
  717. return(RPC_S_OUT_OF_MEMORY);
  718. Buffer1 = I_RpcAllocate(1024);
  719. if (Buffer1 == NULL)
  720. {
  721. I_RpcFree(Buffer0);
  722. return(RPC_S_OUT_OF_MEMORY);
  723. }
  724. Status = InitializeCriticalSectionWrapper(&CacheMutex);
  725. if (!Status)
  726. {
  727. Status = InitializeCriticalSectionWrapper(&FileServerMutex);
  728. if (Status)
  729. {
  730. DeleteCriticalSectionWrapper(&CacheMutex);
  731. }
  732. }
  733. if (Status)
  734. {
  735. I_RpcFree(Buffer0);
  736. I_RpcFree(Buffer1);
  737. return(Status);
  738. }
  739. nsStatus.nhHeader = (NCPHDR *)Buffer0;
  740. nsStatus.RcvBuffer = (PCHAR) Buffer1;
  741. ASSERT(nsStatus.ServerCount == 0);
  742. ASSERT(nsStatus.s == 0);
  743. ASSERT(!fInitialized);
  744. fInitialized = TRUE;
  745. return Status;
  746. }
  747. RPC_STATUS
  748. AddServerToCache(
  749. IN char * Name,
  750. IN SOCKADDR_IPX * Address
  751. )
  752. {
  753. unsigned i;
  754. RPC_STATUS Status;
  755. Status = EnterCriticalSectionWrapper(&CacheMutex);
  756. if (Status)
  757. {
  758. return Status;
  759. }
  760. //
  761. // Check if the name is already in the cache, we might be re-resolving
  762. // the name or another thread might have put the name in the cache
  763. // since we last checked.
  764. //
  765. for (i=0; i < CACHE_SIZE; ++i)
  766. {
  767. if ( ServerCache[i].Name &&
  768. 0 == RpcpStringCompareA(ServerCache[i].Name, Name))
  769. {
  770. // Check if entry already matches our address.
  771. if ( memcmp(Address->sa_netnum, ServerCache[i].Address.sa_netnum, 4)
  772. || memcmp(Address->sa_nodenum, ServerCache[i].Address.sa_nodenum, 6))
  773. {
  774. // New information, update cache.
  775. memcpy(&ServerCache[i].Address, Address, sizeof(SOCKADDR_IPX));
  776. Status = RPC_S_OK;
  777. }
  778. else
  779. {
  780. Status = RPC_P_MATCHED_CACHE;
  781. }
  782. LeaveCriticalSectionWrapper(&CacheMutex);
  783. return(Status);
  784. }
  785. }
  786. //
  787. // If it is not in the table, try to find an empty entry to fill.
  788. //
  789. if (i == CACHE_SIZE)
  790. {
  791. for (i=0; i < CACHE_SIZE; ++i)
  792. {
  793. if (ServerCache[i].Name == 0)
  794. {
  795. break;
  796. }
  797. }
  798. }
  799. //
  800. // If all entries are full, overwrite the oldest one.
  801. //
  802. if (i == CACHE_SIZE)
  803. {
  804. unsigned BestIndex = 0;
  805. LONG now = GetTickCount();
  806. LONG BestDiff = now - ServerCache[0].Time;
  807. ASSERT(CACHE_SIZE > 1);
  808. for (i = 1; i < CACHE_SIZE; ++i)
  809. {
  810. LONG diff = now - ServerCache[i].Time;
  811. if (diff > BestDiff)
  812. {
  813. BestIndex = i;
  814. BestDiff = diff;
  815. }
  816. }
  817. i = BestIndex;
  818. }
  819. //
  820. // Update the entry's information.
  821. //
  822. ASSERT(strlen(Name) <= IPX_MAXIMUM_PRETTY_NAME);
  823. if (NULL == ServerCache[i].Name)
  824. {
  825. ServerCache[i].Name = new CHAR[IPX_MAXIMUM_PRETTY_NAME + 1];
  826. }
  827. if (ServerCache[i].Name)
  828. {
  829. strcpy(ServerCache[i].Name, Name);
  830. memcpy(&ServerCache[i].Address, Address, sizeof(SOCKADDR_IPX));
  831. ServerCache[i].Time = GetTickCount();
  832. Status = RPC_S_OK;
  833. }
  834. else
  835. {
  836. Status = RPC_S_OUT_OF_MEMORY;
  837. }
  838. LeaveCriticalSectionWrapper(&CacheMutex);
  839. return (Status);
  840. }
  841. BOOL
  842. FindServerInCache(
  843. char * Name,
  844. SOCKADDR_IPX * Address,
  845. unsigned * Time
  846. )
  847. {
  848. unsigned i;
  849. RPC_STATUS Status;
  850. Status = EnterCriticalSectionWrapper(&CacheMutex);
  851. if (Status)
  852. {
  853. return FALSE;
  854. }
  855. for (i = 0; i < CACHE_SIZE; ++i)
  856. {
  857. if ( ServerCache[i].Name
  858. && (0 == RpcpStringCompareA(ServerCache[i].Name, Name)) )
  859. {
  860. memcpy(Address, &ServerCache[i].Address, sizeof(SOCKADDR_IPX));
  861. *Time = ServerCache[i].Time;
  862. LeaveCriticalSectionWrapper(&CacheMutex);
  863. return TRUE;
  864. }
  865. }
  866. LeaveCriticalSectionWrapper(&CacheMutex);
  867. return FALSE;
  868. }
  869. BOOL
  870. CachedServerNotContacted(
  871. char * Name
  872. )
  873. {
  874. unsigned i;
  875. BOOL Flushed = FALSE;
  876. RPC_STATUS Status;
  877. Status = EnterCriticalSectionWrapper(&CacheMutex);
  878. if (Status)
  879. {
  880. return Flushed;
  881. }
  882. for (i=0; i < CACHE_SIZE; ++i)
  883. {
  884. if ( ServerCache[i].Name
  885. && 0 == RpcpStringCompareA(ServerCache[i].Name, Name))
  886. {
  887. if (GetTickCount() - ServerCache[i].Time > CACHE_EXPIRATION_TIME)
  888. {
  889. delete ServerCache[i].Name;
  890. ServerCache[i].Name = 0;
  891. Flushed = TRUE;
  892. }
  893. break;
  894. }
  895. }
  896. LeaveCriticalSectionWrapper(&CacheMutex);
  897. return Flushed;
  898. }
  899. void
  900. CachedServerContacted(
  901. char * Name
  902. )
  903. {
  904. unsigned i;
  905. RPC_STATUS Status;
  906. Status = EnterCriticalSectionWrapper(&CacheMutex);
  907. if (Status)
  908. {
  909. return;
  910. }
  911. for (i=0; i < CACHE_SIZE; ++i)
  912. {
  913. if ( ServerCache[i].Name
  914. && 0 == RpcpStringCompareA(ServerCache[i].Name, Name))
  915. {
  916. ServerCache[i].Time = GetTickCount();
  917. break;
  918. }
  919. }
  920. LeaveCriticalSectionWrapper(&CacheMutex);
  921. }
  922. RPC_STATUS
  923. LookupViaRnr(
  924. char * Name,
  925. SOCKADDR_IPX * Address,
  926. unsigned Timeout
  927. )
  928. {
  929. CSADDR_BUFFER csaddr[2];
  930. int num;
  931. INT protocol_list[2];
  932. DWORD csaddr_size = sizeof(csaddr);
  933. protocol_list[0] = NSPROTO_IPX ;
  934. protocol_list[1] = 0;
  935. num = GetAddressByNameA(NS_SAP,
  936. (GUID *)&SERVICE_TYPE,
  937. Name,
  938. protocol_list,
  939. 0,
  940. FALSE,
  941. &csaddr,
  942. &csaddr_size,
  943. NULL,
  944. 0);
  945. if (num <= 0)
  946. {
  947. return RPC_S_SERVER_UNAVAILABLE;
  948. }
  949. memcpy( Address, csaddr[0].info.RemoteAddr.lpSockaddr, sizeof(SOCKADDR_IPX) );
  950. return(AddServerToCache(Name, Address));
  951. }
  952. RPC_STATUS
  953. LookupViaBindery(
  954. char * Name,
  955. SOCKADDR_IPX * Address,
  956. unsigned Timeout
  957. )
  958. {
  959. USHORT Connection;
  960. USHORT NwStatus;
  961. UCHAR MoreSegments;
  962. UCHAR PropertyFlags;
  963. UCHAR buffer[128];
  964. RPC_STATUS Status;
  965. Status = EnterCriticalSectionWrapper(&FileServerMutex);
  966. if (Status)
  967. {
  968. return Status;
  969. }
  970. //
  971. // Find a Netware server and connect to it.
  972. //
  973. if (FALSE == AttachToFileServer())
  974. {
  975. LeaveCriticalSectionWrapper(&FileServerMutex);
  976. return RPC_S_SERVER_UNAVAILABLE;
  977. }
  978. //
  979. // Read from the bindery.
  980. //
  981. NwStatus = ReadPropertyValue( Name,
  982. RPC_SAP_TYPE,
  983. "NET_ADDRESS",
  984. 1,
  985. buffer,
  986. &MoreSegments,
  987. &PropertyFlags
  988. );
  989. //
  990. // Disconnect from the file server.
  991. //
  992. DetachFromActiveServer();
  993. LeaveCriticalSectionWrapper(&FileServerMutex);
  994. if (!NwStatus)
  995. {
  996. memcpy(&Address->sa_netnum, buffer, 12);
  997. return(AddServerToCache(Name, Address));
  998. }
  999. return RPC_S_SERVER_UNAVAILABLE;
  1000. }
  1001. RPC_STATUS
  1002. IpxNameToAddress(
  1003. char * Name,
  1004. SOCKADDR_IPX * Address,
  1005. unsigned Timeout
  1006. )
  1007. {
  1008. RPC_STATUS Status = RPC_S_OK;
  1009. Status = EnterCriticalSectionWrapper(&FileServerMutex);
  1010. if (Status)
  1011. {
  1012. return Status;
  1013. }
  1014. if (!fCsnwCheckCompleted)
  1015. {
  1016. CheckForCsnw();
  1017. }
  1018. LeaveCriticalSectionWrapper(&FileServerMutex);
  1019. if (fCsnwInstalled)
  1020. {
  1021. Status = LookupViaRnr(Name, Address, Timeout);
  1022. }
  1023. else
  1024. {
  1025. Status = LookupViaBindery(Name, Address, Timeout);
  1026. if ( Status != RPC_S_OK
  1027. && Status != RPC_P_MATCHED_CACHE)
  1028. {
  1029. Status = LookupViaRnr(Name, Address, Timeout);
  1030. }
  1031. }
  1032. return Status;
  1033. }
  1034. void IPX_AddressToName(
  1035. IN SOCKADDR_IPX *pAddr,
  1036. OUT RPC_CHAR *pName
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. Converts a raw IPX address into the string address format used
  1041. by RPC.
  1042. ~NNNNNNNNAAAAAAAAAAAA
  1043. N - network number in hex
  1044. A - network address (IEEE 802) in hex
  1045. Arguments:
  1046. pAddr - The sockaddr containing the address to convert
  1047. pName - Will contain the string address on return, assumed
  1048. to be IPX_MAXIMUM_RAW_NAME characters.
  1049. Return Value:
  1050. None
  1051. --*/
  1052. {
  1053. int i;
  1054. *pName++ = '~';
  1055. for (i = 0; i < sizeof(pAddr->sa_netnum); i++)
  1056. {
  1057. *pName++ = HexDigits[ (UCHAR)(pAddr->sa_netnum[i]) >> 4 ];
  1058. *pName++ = HexDigits[ (UCHAR)(pAddr->sa_netnum[i]) & 0x0F ];
  1059. }
  1060. for (i = 0; i < sizeof(pAddr->sa_nodenum); i++)
  1061. {
  1062. *pName++ = HexDigits[ (UCHAR)(pAddr->sa_nodenum[i]) >> 4 ];
  1063. *pName++ = HexDigits[ (UCHAR)(pAddr->sa_nodenum[i]) & 0x0F ];
  1064. }
  1065. *pName = 0;
  1066. }
  1067. RPC_STATUS
  1068. IPX_NameToAddress(
  1069. RPC_CHAR *Name,
  1070. BOOL fUseCache,
  1071. OUT SOCKADDR_IPX *pAddr
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. Converts a name into an IPX address if possible. Handles the
  1076. case of ~ names and pretty names.
  1077. Arguments:
  1078. Name - The name to convert
  1079. fUseCache - Usually TRUE, if which case a value cached from
  1080. a previous call with the same name maybe used. If FALSE,
  1081. then full name resolution must be used.
  1082. pAddr - Will overwrite the sa_netnum and sa_nodenum with the
  1083. IPX address if successful.
  1084. Return Value:
  1085. RPC_S_OK - Full lookup, completed ok.
  1086. RPC_S_FOUND_IN_CACHE - Lookup completed and found in cache.
  1087. RPC_S_MATCHED_CACHE - Full lookup required (fUseCache == FALSE) but
  1088. results didn't change.
  1089. RPC_S_SERVER_UNAVAILABLE - Lookup failed.
  1090. RPC_S_OUT_OF_RESOURCES
  1091. RPC_S_OUT_OF_MEMORY
  1092. --*/
  1093. {
  1094. int length;
  1095. ASSERT(pAddr->sa_family == AF_IPX);
  1096. ASSERT(pAddr->sa_socket == 0);
  1097. //
  1098. // First see if the address is local.
  1099. //
  1100. if (Name == 0 || *Name == 0)
  1101. {
  1102. //
  1103. // Use the cached local address, if valid.
  1104. //
  1105. if (fIpxAddrValid == TRUE)
  1106. {
  1107. memcpy(pAddr->sa_netnum, IpxAddr.sa_netnum, 4);
  1108. memcpy(pAddr->sa_nodenum, IpxAddr.sa_nodenum, 6);
  1109. return(RPC_S_OK);
  1110. }
  1111. //
  1112. // Figure out the loopback address, not a easy task on IPX.
  1113. //
  1114. SOCKET sock;
  1115. sock = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
  1116. if (sock == INVALID_SOCKET)
  1117. {
  1118. //
  1119. switch(GetLastError())
  1120. {
  1121. case WSAEAFNOSUPPORT:
  1122. case WSAEPROTONOSUPPORT:
  1123. return(RPC_S_PROTSEQ_NOT_SUPPORTED);
  1124. break;
  1125. case WSAENOBUFS:
  1126. case WSAEMFILE:
  1127. return(RPC_S_OUT_OF_MEMORY);
  1128. break;
  1129. default:
  1130. ASSERT(0);
  1131. return(RPC_S_OUT_OF_MEMORY);
  1132. break;
  1133. }
  1134. }
  1135. // zero-out the netnum and nodenum members
  1136. memset(pAddr->sa_netnum, 0, sizeof(pAddr->sa_netnum));
  1137. memset(pAddr->sa_nodenum, 0, sizeof(pAddr->sa_nodenum));
  1138. if ( bind(sock, (PSOCKADDR)pAddr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR)
  1139. {
  1140. closesocket(sock);
  1141. return(RPC_S_OUT_OF_RESOURCES);
  1142. }
  1143. int len = sizeof(SOCKADDR_IPX);
  1144. if ( getsockname(sock, (PSOCKADDR)pAddr, &len) == SOCKET_ERROR)
  1145. {
  1146. closesocket(sock);
  1147. return(RPC_S_OUT_OF_RESOURCES);
  1148. }
  1149. // Update cache
  1150. memcpy(IpxAddr.sa_netnum, pAddr->sa_netnum, sizeof(IpxAddr.sa_netnum));
  1151. memcpy(IpxAddr.sa_nodenum, pAddr->sa_nodenum, sizeof(IpxAddr.sa_nodenum));
  1152. fIpxAddrValid = TRUE;
  1153. closesocket(sock);
  1154. return(RPC_S_OK);
  1155. }
  1156. //
  1157. // Must resolve the name, validate and convert to ansi.
  1158. //
  1159. length = RpcpStringLength(Name) + 1;
  1160. if (length > IPX_MAXIMUM_PRETTY_NAME)
  1161. {
  1162. return(RPC_S_SERVER_UNAVAILABLE);
  1163. }
  1164. if ( *Name == RPC_T('~')
  1165. && length != IPX_MAXIMUM_RAW_NAME)
  1166. {
  1167. return(RPC_S_SERVER_UNAVAILABLE);
  1168. }
  1169. CHAR AnsiName[IPX_MAXIMUM_PRETTY_NAME + 1];
  1170. RpcpMemorySet(&(AnsiName[0]), 0x00, IPX_MAXIMUM_PRETTY_NAME + 1);
  1171. PlatformToAnsi(Name, AnsiName);
  1172. //
  1173. // If the name starts with ~, convert it directly to a network address.
  1174. //
  1175. if (AnsiName[0] == '~')
  1176. {
  1177. ASSERT(Name[0] == RPC_T('~'));
  1178. int i;
  1179. PCHAR p = AnsiName;
  1180. p++; // Skip ~
  1181. for (i = 0; i < 4; i++)
  1182. {
  1183. pAddr->sa_netnum[i] = HexDigitsToBinary(*p, *(p+1));
  1184. p += 2;
  1185. }
  1186. for (i = 0; i < 6; i++)
  1187. {
  1188. pAddr->sa_nodenum[i] = HexDigitsToBinary(*p, *(p+1));
  1189. p += 2;
  1190. }
  1191. if (fUseCache)
  1192. {
  1193. return(RPC_S_OK);
  1194. }
  1195. else
  1196. {
  1197. return(RPC_P_MATCHED_CACHE);
  1198. }
  1199. }
  1200. if (fUseCache)
  1201. {
  1202. UINT t = 0;
  1203. //
  1204. // Look up the server in the name cache.
  1205. //
  1206. if (FindServerInCache(AnsiName, pAddr, &t))
  1207. {
  1208. return(RPC_P_FOUND_IN_CACHE);
  1209. }
  1210. }
  1211. //
  1212. // Gotta go look for it.
  1213. //
  1214. RPC_STATUS status = IpxNameToAddress(AnsiName, pAddr, 0);
  1215. if ( (status == RPC_P_MATCHED_CACHE)
  1216. && fUseCache)
  1217. {
  1218. // Race - another thread added the name to the cache
  1219. // while we did the lookup.
  1220. return(RPC_S_OK);
  1221. }
  1222. return(status);
  1223. }
  1224. BOOL fIpxAddrValid = FALSE;
  1225. SOCKADDR_IPX IpxAddr;
  1226. RPC_STATUS
  1227. IPX_BuildAddressVector(
  1228. OUT NETWORK_ADDRESS_VECTOR **ppAddressVector
  1229. )
  1230. /*++
  1231. Routine Description:
  1232. Use by both IPX and SPX RPC servers to build the network
  1233. address structure to be returned to the RPC runtime.
  1234. Before calling this the caller must make sure the global
  1235. fIpxAddrValid is TRUE.
  1236. Arguments:
  1237. ppAddressVector - The place to store the constructed address
  1238. vector.
  1239. Return Value:
  1240. RPC_S_OK
  1241. RPC_S_OUT_OF_MEMORY
  1242. --*/
  1243. {
  1244. NETWORK_ADDRESS_VECTOR *pVector;
  1245. pVector = new( sizeof(RPC_CHAR *)
  1246. + gdwComputerNameLength * sizeof(RPC_CHAR))
  1247. NETWORK_ADDRESS_VECTOR;
  1248. if (NULL == pVector)
  1249. {
  1250. return(RPC_S_OUT_OF_MEMORY);
  1251. }
  1252. pVector->Count = 1;
  1253. pVector->NetworkAddresses[0] = (RPC_CHAR*)&pVector->NetworkAddresses[1];
  1254. RpcpStringCopy(pVector->NetworkAddresses[0], gpstrComputerName);
  1255. *ppAddressVector = pVector;
  1256. return(RPC_S_OK);
  1257. }