Windows NT 4.0 source code leak
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.

622 lines
14 KiB

4 years ago
  1. /* --------------------------------------------------------------------
  2. File : nbltclnt.c
  3. Title : client loadable transport for Windows NT NetBIOS - client side
  4. Description :
  5. History :
  6. 19-1-95 Tony Chan Use winsock to support NetBIOS
  7. WITH SEQ_NUMBER
  8. Compatibility issue
  9. In order to be compatible with the old NetBIOS server transport,
  10. If the first DWORD of the packet is 0, we know that it's a old NetBIOS
  11. client connection. Therefore, we will take away the seq # and return only
  12. the data to the runtime.
  13. If the first DWORD of the first message is not 0, it's actually is the
  14. runtime message_header RPC_version #, so we hand the whole buffer to the
  15. runtime.
  16. If we are dealing with old server, on all subsequence Send, we need to
  17. prepend seq_number, and we need to take away sequence # on all recv from
  18. old client
  19. -------------------------------------------------------------------- */
  20. /*
  21. OLD_CLIENT:
  22. if define old client, this transport will behave as an old client otherwise
  23. it will behave as a new client without sending out sequence number.
  24. */
  25. #define OLD_CLIENT 1
  26. #include "sysinc.h"
  27. #define FD_SETSIZE 1
  28. #include <winsock.h>
  29. #include <tdi.h>
  30. // NetBIOS winsock header file
  31. #include <wsnetbs.h>
  32. #include <winbase.h>
  33. #include <stdlib.h>
  34. #include "rpc.h"
  35. #include "rpcdcep.h"
  36. #include "rpctran.h"
  37. #include "rpcerrp.h"
  38. #include "common.h"
  39. #include "reg.h" /* registry lookup rountine */
  40. /*
  41. Following Macros and structs are needed for Tower Stuff
  42. */
  43. #pragma pack(1)
  44. #define NB_TRANSPORTID 0x12
  45. #define NB_NBID 0x13
  46. #define NB_XNSID 0x15
  47. #define NB_IPID 0x09
  48. #define NB_IPXID 0x0d
  49. #define NB_TOWERFLOORS 5
  50. #define NB_PROTSEQ "ncacn_nb_nb"
  51. #define IP_PROTSEQ "ncacn_nb_tcp"
  52. #define IPX_PROTSEQ "ncacn_nb_ipx"
  53. typedef struct _FLOOR_234 {
  54. unsigned short ProtocolIdByteCount;
  55. unsigned char FloorId;
  56. unsigned short AddressByteCount;
  57. unsigned char Data[2];
  58. } FLOOR_234, __RPC_FAR * PFLOOR_234;
  59. #define NEXTFLOOR(t,x) (t)((unsigned char __RPC_FAR *)x +((t)x)->ProtocolIdByteCount\
  60. + ((t)x)->AddressByteCount\
  61. + sizeof(((t)x)->ProtocolIdByteCount)\
  62. + sizeof(((t)x)->AddressByteCount))
  63. /*
  64. End of Tower Stuff!
  65. */
  66. #define ENDIAN_MASK 16
  67. #define ENDPOINT_LEN 3
  68. #define PFC_FIRST_FRAG 0x01
  69. typedef struct
  70. {
  71. SOCKET Socket;
  72. char PAPI * Buffer;
  73. fd_set SockSet;
  74. BOOL LocalRpc;
  75. #ifdef OLD_CLIENT
  76. int seq_num; /* for the old client case */
  77. #endif
  78. } CONNECTION, *PCONNECTION;
  79. #define NB_OK 0
  80. #define NB_CONTINUE 1
  81. #define NB_FAIL 2
  82. extern int NumCards; /* defined in reg.h */
  83. int CreateAndSetupNBSocket (
  84. IN PCONNECTION pConn,
  85. IN RPC_CHAR PAPI *RpcProtocolSequence,
  86. IN char PAPI *HostName,
  87. IN int PortIn,
  88. IN int CardIndex
  89. )
  90. {
  91. PPROTOCOL_MAP ProtocolEntry;
  92. SOCKADDR_NB server ;
  93. int Status;
  94. BOOL reuse; /* for socket option */
  95. if (Status = MapProtocol(RpcProtocolSequence, CardIndex, &ProtocolEntry))
  96. {
  97. return NB_CONTINUE ;
  98. }
  99. // Get a socket, the PROTOCOL
  100. // is defined to be (-1 * LANA numbmer)
  101. if ((pConn->Socket = socket(AF_NETBIOS,
  102. SOCK_SEQPACKET ,
  103. -1 * (ProtocolEntry->Lana)))
  104. == INVALID_SOCKET)
  105. {
  106. #ifdef DEBUGRPC
  107. PrintToDebugger( "%s: socket - %d\n",
  108. "rpcltccm - NB", WSAGetLastError() );
  109. #endif
  110. return(NB_FAIL);
  111. }
  112. reuse = TRUE;
  113. setsockopt(pConn->Socket, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse,
  114. sizeof(BOOL));
  115. // setup server sockaddr
  116. server.snb_family = AF_NETBIOS;
  117. SET_NETBIOS_SOCKADDR((&server), NETBIOS_UNIQUE_NAME,
  118. HostName, (char ) PortIn);
  119. // try to connect
  120. if (connect(pConn->Socket, (struct sockaddr *) &server,
  121. sizeof (server)) == SOCKET_ERROR)
  122. {
  123. #ifdef DEBUGRPC
  124. PrintToDebugger( "%s: Connect - %d to port %d\n",
  125. "rpcltccm - NB", WSAGetLastError(), PortIn );
  126. #endif
  127. closesocket(pConn->Socket);
  128. pConn->Socket = 0;
  129. return(NB_CONTINUE);
  130. }
  131. return NB_OK ;
  132. }
  133. RPC_STATUS RPC_ENTRY
  134. ClientOpen (
  135. IN PCONNECTION pConn,
  136. IN RPC_CHAR * NetworkAddress,
  137. IN RPC_CHAR * Endpoint,
  138. IN RPC_CHAR * NetworkOptions,
  139. IN RPC_CHAR * TransportAddress,
  140. IN RPC_CHAR * RpcProtocolSequence,
  141. IN unsigned int Timeout
  142. )
  143. // Open a client connection
  144. {
  145. SOCKADDR_NB server; /* sock address for server */
  146. size_t hostNameLen; /* length of the host name */
  147. unsigned char remotehostname[NETBIOS_NAME_LENGTH+1];
  148. unsigned char port[ENDPOINT_LEN+1]; /* port number in string format */
  149. int status;
  150. int i;
  151. unsigned int PortIn; /* port in integer format */
  152. PPROTOCOL_MAP ProtocolEntry;
  153. UNUSED(NetworkAddress);
  154. UNUSED(NetworkOptions);
  155. UNUSED(TransportAddress);
  156. UNUSED(RpcProtocolSequence);
  157. UNUSED(Timeout);
  158. if (RpcpStringLength(NetworkAddress) > NETBIOS_NAME_LENGTH)
  159. {
  160. return (RPC_S_INVALID_NET_ADDR) ;
  161. }
  162. #ifdef NTENV
  163. if(RpcpStringLength(Endpoint) != wcsspn(Endpoint, RPC_CONST_STRING("0123456789")))
  164. #else
  165. if(RpcpStringLength(Endpoint) != strspn(Endpoint, RPC_CONST_STRING("0123456789")))
  166. #endif // #ifdef NTENV
  167. {
  168. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  169. }
  170. if(RpcpStringLength(Endpoint) > ENDPOINT_LEN)
  171. {
  172. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  173. }
  174. // Convert the endpoint string to a number and validate.
  175. unicode_to_ascii (Endpoint, port);
  176. PortIn = atoi(port);
  177. if((PortIn == 0) ||( PortIn >= 255) )
  178. {
  179. return(RPC_S_INVALID_ENDPOINT_FORMAT);
  180. }
  181. /* setup hostname */
  182. unicode_to_ascii (NetworkAddress, remotehostname);
  183. if ( remotehostname[0] == '\0')
  184. {
  185. pConn->LocalRpc = TRUE;
  186. hostNameLen = MAX_COMPUTERNAME_LENGTH + 1;
  187. GetComputerName(remotehostname, &hostNameLen);
  188. }
  189. _strupr(remotehostname); /* conver to upper case for netbios */
  190. for (i = 0; i <=NumCards; i++)
  191. {
  192. status = CreateAndSetupNBSocket(
  193. pConn, RpcProtocolSequence, remotehostname,
  194. PortIn, i) ;
  195. if (status == NB_CONTINUE)
  196. {
  197. continue;
  198. }
  199. if (status != NB_OK)
  200. {
  201. return RPC_S_SERVER_UNAVAILABLE ;
  202. }
  203. break;
  204. }
  205. if (status != NB_OK)
  206. {
  207. return RPC_S_SERVER_UNAVAILABLE ;
  208. }
  209. // got the connection
  210. #ifdef OLD_CLIENT
  211. pConn->seq_num = 0; /* init seq number */
  212. #endif
  213. return(RPC_S_OK);
  214. }
  215. RPC_STATUS RPC_ENTRY
  216. ClientClose (
  217. IN PCONNECTION pConn
  218. )
  219. // Close a client connection
  220. {
  221. closesocket(pConn->Socket);
  222. pConn->Socket = 0;
  223. return (RPC_S_OK);
  224. }
  225. RPC_STATUS RPC_ENTRY
  226. ClientSend (
  227. IN PCONNECTION pConn,
  228. IN void PAPI * Buffer,
  229. IN unsigned int BufferLength
  230. )
  231. {
  232. int bytes;
  233. int total_bytes = 0;
  234. int Status;
  235. unsigned long PrevTicks;
  236. #ifdef OLD_CLIENT
  237. /* structure to support seq number */
  238. typedef struct a_BufferWithSeq {
  239. DWORD seq_num;
  240. char Buffer[5280];
  241. } t_BufferWithSeq;
  242. t_BufferWithSeq BufferWithSeq ;
  243. ASSERT(BufferLength <= 5280);
  244. BufferWithSeq.seq_num = pConn->seq_num;
  245. memcpy(&(BufferWithSeq.Buffer), Buffer, BufferLength);
  246. bytes = send(pConn->Socket, (char *) & BufferWithSeq,
  247. (int) sizeof(DWORD) + BufferLength, 0);
  248. if (bytes != (int) (BufferLength + sizeof(DWORD)))
  249. {
  250. ClientClose ( pConn );
  251. return(RPC_P_SEND_FAILED);
  252. }
  253. pConn->seq_num++;
  254. #else
  255. ASSERT(BufferLength <= 5280);
  256. bytes = send(pConn->Socket, (char *) Buffer, (int) BufferLength, 0);
  257. if (bytes != (int) BufferLength )
  258. {
  259. ClientClose ( pConn );
  260. return(RPC_P_SEND_FAILED);
  261. }
  262. #endif
  263. return(RPC_S_OK);
  264. }
  265. RPC_TRANS_STATUS RPC_ENTRY
  266. ClientRecv (
  267. IN PCONNECTION pConn,
  268. IN OUT void PAPI * PAPI * Buffer,
  269. IN OUT unsigned int PAPI * BufferLength
  270. )
  271. // Read a message from a connection.
  272. {
  273. RPC_STATUS RpcStatus = RPC_S_OK;
  274. int bytes;
  275. unsigned int totalBytes = 0;
  276. int err; /* for error message */
  277. int flags;
  278. int retry ;
  279. /* reset seq number once receive */
  280. pConn->seq_num = 0;
  281. if (*Buffer == 0)
  282. {
  283. *BufferLength = 1024;
  284. RpcStatus =
  285. I_RpcTransClientReallocBuffer(pConn, Buffer, 0,
  286. *BufferLength);
  287. if (RpcStatus != RPC_S_OK)
  288. {
  289. return(RPC_S_OUT_OF_MEMORY);
  290. }
  291. }
  292. retry = 1;
  293. while(1)
  294. {
  295. flags = 0;
  296. bytes = WSARecvEx( pConn->Socket, (char *)*Buffer + totalBytes,
  297. *BufferLength - totalBytes, &flags);
  298. if (bytes <= 0 ) // if connection close, bytes will = 0, we need to close connection
  299. {
  300. #ifdef DEBUGRPC
  301. PrintToDebugger("rpcltccm - NB: bad client receive lasterr(%d) \n",
  302. WSAGetLastError());
  303. #endif
  304. ClientClose(pConn);
  305. return(RPC_P_RECEIVE_FAILED);
  306. }
  307. totalBytes += bytes;
  308. if(flags & MSG_PARTIAL)
  309. {
  310. if (retry == 0)
  311. {
  312. #ifdef DEBUGRPC
  313. PrintToDebugger("rpcltccm - NB: twice client receive lasterr(%d) \n",
  314. WSAGetLastError());
  315. #endif
  316. ClientClose(pConn);
  317. return(RPC_P_RECEIVE_FAILED);
  318. }
  319. *BufferLength = I_RpcTransClientMaxFrag(pConn);
  320. RpcStatus = I_RpcTransClientReallocBuffer(pConn,
  321. Buffer,
  322. totalBytes,
  323. *BufferLength);
  324. if (RpcStatus != RPC_S_OK)
  325. {
  326. #ifdef DEBUGRPC
  327. PrintToDebugger("rpcltccm - NB: bad client receive \n");
  328. #endif
  329. return(RPC_S_OUT_OF_MEMORY);
  330. }
  331. retry = 0;
  332. }
  333. else
  334. {
  335. *BufferLength = totalBytes;
  336. return(RPC_S_OK);
  337. }
  338. }
  339. ASSERT(0);
  340. return(RPC_S_INTERNAL_ERROR);
  341. }
  342. #pragma pack(1)
  343. RPC_STATUS RPC_ENTRY
  344. ClientTowerConstruct(
  345. IN char PAPI * Endpoint,
  346. IN char PAPI * NetworkAddress,
  347. OUT short PAPI * Floors,
  348. OUT unsigned long PAPI * ByteCount,
  349. OUT unsigned char PAPI * PAPI * Tower,
  350. IN char PAPI * Protseq
  351. )
  352. {
  353. unsigned long TowerSize;
  354. UNALIGNED PFLOOR_234 Floor;
  355. unsigned long HostId;
  356. //BUGBUG: Need appropriate error code for unsupported Protseqs
  357. if (strcmp(Protseq,NB_PROTSEQ) == 0)
  358. HostId = NB_NBID;
  359. else if (strcmp(Protseq, IP_PROTSEQ) == 0)
  360. HostId = NB_IPID;
  361. else if (strcmp(Protseq, IPX_PROTSEQ) == 0)
  362. HostId = NB_IPXID;
  363. else return (RPC_S_OUT_OF_MEMORY);
  364. *Floors = NB_TOWERFLOORS;
  365. TowerSize = ((Endpoint == NULL) || (*Endpoint == '\0')) ?
  366. 2 : strlen(Endpoint) + 1;
  367. TowerSize += ((NetworkAddress== NULL) || (*NetworkAddress== '\0')) ?
  368. 2 : strlen(NetworkAddress) + 1;
  369. TowerSize += 2*sizeof(FLOOR_234) - 4;
  370. if ((*Tower = (unsigned char __RPC_FAR*)I_RpcAllocate((unsigned int)
  371. (*ByteCount = TowerSize)))
  372. == NULL)
  373. {
  374. return (RPC_S_OUT_OF_MEMORY);
  375. }
  376. Floor = (PFLOOR_234) *Tower;
  377. Floor->ProtocolIdByteCount = 1;
  378. Floor->FloorId = (unsigned char)(NB_TRANSPORTID & 0xFF);
  379. if ((Endpoint) && (*Endpoint))
  380. {
  381. memcpy((char __RPC_FAR *)&Floor->Data[0], Endpoint,
  382. (Floor->AddressByteCount = strlen(Endpoint)+1));
  383. }
  384. else
  385. {
  386. Floor->AddressByteCount = 2;
  387. Floor->Data[0] = 0;
  388. }
  389. //Onto the next floor
  390. Floor = NEXTFLOOR(PFLOOR_234, Floor);
  391. Floor->ProtocolIdByteCount = 1;
  392. Floor->FloorId = (unsigned char)(HostId & 0xFF);
  393. if ((NetworkAddress) && (*NetworkAddress))
  394. {
  395. memcpy((char __RPC_FAR *)&Floor->Data[0], NetworkAddress,
  396. (Floor->AddressByteCount = strlen(NetworkAddress) + 1));
  397. }
  398. else
  399. {
  400. Floor->AddressByteCount = 2;
  401. Floor->Data[0] = 0;
  402. }
  403. return(RPC_S_OK);
  404. }
  405. RPC_STATUS RPC_ENTRY
  406. ClientTowerExplode(
  407. IN unsigned char PAPI * Tower,
  408. OUT char PAPI * PAPI * Protseq,
  409. OUT char PAPI * PAPI * Endpoint,
  410. OUT char PAPI * PAPI * NetworkAddress
  411. )
  412. {
  413. UNALIGNED PFLOOR_234 Floor = (PFLOOR_234) Tower;
  414. RPC_STATUS Status = RPC_S_OK;
  415. char __RPC_FAR * Pseq;
  416. UNUSED(NetworkAddress);
  417. if (Endpoint != NULL)
  418. {
  419. *Endpoint = I_RpcAllocate(Floor->AddressByteCount);
  420. if (*Endpoint == NULL)
  421. {
  422. Status = RPC_S_OUT_OF_MEMORY;
  423. }
  424. else
  425. {
  426. memcpy(*Endpoint, (char __RPC_FAR *)&Floor->Data[0],
  427. Floor->AddressByteCount);
  428. }
  429. }
  430. Floor = NEXTFLOOR(PFLOOR_234, Floor);
  431. switch (Floor->FloorId)
  432. {
  433. case NB_NBID:
  434. Pseq = NB_PROTSEQ;
  435. break;
  436. case NB_IPID:
  437. Pseq = IP_PROTSEQ;
  438. break;
  439. case NB_IPXID:
  440. Pseq = IPX_PROTSEQ;
  441. break;
  442. default:
  443. return(RPC_S_OUT_OF_MEMORY);
  444. }
  445. if ((Protseq != NULL) && (Status == RPC_S_OK))
  446. {
  447. *Protseq = I_RpcAllocate(strlen(Pseq) + 1);
  448. if (*Protseq == NULL)
  449. {
  450. Status = RPC_S_OUT_OF_MEMORY;
  451. if (Endpoint != NULL)
  452. I_RpcFree(*Endpoint);
  453. }
  454. else
  455. {
  456. memcpy(*Protseq, Pseq, strlen(Pseq) + 1);
  457. }
  458. }
  459. return(Status);
  460. }
  461. #pragma pack()
  462. RPC_CLIENT_TRANSPORT_INFO NB_TransInfo = {
  463. RPC_TRANSPORT_INTERFACE_VERSION,
  464. NB_TRANSPORTID,
  465. ClientTowerConstruct,
  466. ClientTowerExplode,
  467. 5280,
  468. sizeof (CONNECTION),
  469. ClientOpen,
  470. ClientClose,
  471. ClientSend,
  472. ClientRecv,
  473. NULL,
  474. NULL,
  475. NULL,
  476. NULL
  477. };