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.

1096 lines
27 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. httptran.cxx
  5. Abstract:
  6. HTTP transport-specific functions.
  7. Author:
  8. GopalP 06-25-97 Cloned from EdwardR's NT 4.0 RPC version.
  9. Revision History:
  10. EdwardR 01-26-98 Rewrite NetworkOptions parsing.
  11. --*/
  12. #define FD_SETSIZE 1
  13. #include <precomp.hxx>
  14. #include <CharConv.hxx>
  15. #define SPACE ' '
  16. #define TAB '\t'
  17. #define EQUALS '='
  18. #define COMMA ','
  19. #define COLON ':'
  20. #define ZERO '0'
  21. #define NINE '9'
  22. #define KEYWORD_HTTPPROXY "httpproxy"
  23. #define KEYWORD_RPCPROXY "rpcproxy"
  24. #define KID_NONE 0
  25. #define KID_HTTPPROXY 1
  26. #define KID_RPCPROXY 2
  27. //-------------------------------------------------------------
  28. // SkipWhiteSpace()
  29. //
  30. // Routine Description:
  31. //
  32. // Skip over spaces and tabs, return new string position.
  33. // Return NULL on end-of-string.
  34. //-------------------------------------------------------------
  35. inline static CHAR *SkipWhiteSpace( IN CHAR *psz )
  36. {
  37. if (psz)
  38. {
  39. while ((*psz)&&((*psz==SPACE)||(*psz==TAB))) psz++;
  40. if (!*psz)
  41. {
  42. psz = NULL; // Return NULL on end-of-string.
  43. }
  44. }
  45. return psz;
  46. }
  47. inline static char *
  48. NextToken(
  49. IN char *psz
  50. )
  51. /*++
  52. Routine Description:
  53. This routine skips whitespace characters to the start of the
  54. next token in the string.
  55. Arguments:
  56. psz - The string in question.
  57. Return Value:
  58. NULL, if there is no next token.
  59. Pointer to the next token, otherwise.
  60. --*/
  61. {
  62. while ((*psz != CHAR_SPACE) &&
  63. (*psz != CHAR_TAB) &&
  64. (*psz != CHAR_NL) &&
  65. (*psz != CHAR_NUL))
  66. {
  67. psz++;
  68. }
  69. if ((*psz == CHAR_NL) || (*psz == CHAR_NUL))
  70. {
  71. return NULL;
  72. }
  73. psz = SkipWhiteSpace(psz);
  74. return psz;
  75. }
  76. inline unsigned int
  77. HttpMessageLength(
  78. IN char *pBuffer
  79. )
  80. /*++
  81. --*/
  82. {
  83. unsigned int len = 0;
  84. char *p = pBuffer;
  85. ASSERT(p);
  86. if (p == NULL)
  87. {
  88. return (0);
  89. }
  90. //
  91. // Look for a <CR><LF> sequence.
  92. //
  93. while ((*p != CHAR_CR) &&
  94. (*(p+1) != CHAR_LF) &&
  95. (len <= MAX_HTTP_MESSAGE_LENGTH))
  96. {
  97. p++;
  98. len++;
  99. }
  100. return (len);
  101. }
  102. DWORD
  103. HttpParseResponse(
  104. IN char *pBuffer
  105. )
  106. /*++
  107. Routine Description:
  108. This routine looks for a string of the form:
  109. HTTP/1.0 nnnn message_string
  110. Ex: "HTTP/1.0 200 Connection established"
  111. Arguments:
  112. pBuffer - The response buffer.
  113. Return Value:
  114. HTTP status code (nnnn), if successful.
  115. -1, if there is no next token yet.
  116. 0, otherwise.
  117. --*/
  118. {
  119. DWORD dwStatus = 0;
  120. char *psz = pBuffer;
  121. psz = NextToken(psz);
  122. if (psz)
  123. {
  124. dwStatus = atoi(psz);
  125. }
  126. else
  127. {
  128. return (-1);
  129. }
  130. // Make sure a connection is established:
  131. if ( (dwStatus < 200) || (dwStatus > 299) )
  132. {
  133. #ifdef DBG
  134. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  135. DPFLTR_WARNING_LEVEL,
  136. "HttpParseResponse(): Connection Failed: %d\n",
  137. dwStatus));
  138. #endif // DBG
  139. dwStatus = 0;
  140. }
  141. return dwStatus;
  142. }
  143. //-------------------------------------------------------------
  144. // ParseLiteral()
  145. //
  146. // Routine Description:
  147. //
  148. // Check the next non-whitespace literal character to see if
  149. // its equal to cLiteral. If yes, the advance the string pointer
  150. // past it to the next character in the string. If no, then
  151. // return status set to RPC_S_INVALID_NETWORK_OPTIONS and return
  152. // the string pointer pointing to the invalid character.
  153. //
  154. //-------------------------------------------------------------
  155. CHAR *ParseLiteral( IN CHAR *psz,
  156. IN CHAR cLiteral,
  157. OUT DWORD *pdwStatus )
  158. {
  159. psz = SkipWhiteSpace(psz);
  160. if (psz)
  161. {
  162. if (*psz == cLiteral)
  163. {
  164. psz++;
  165. }
  166. else
  167. {
  168. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  169. }
  170. }
  171. return psz;
  172. }
  173. //-------------------------------------------------------------
  174. // ParsePort()
  175. //
  176. // Routine Description:
  177. //
  178. // Parse the next token as a "port-number", return its value
  179. // in the out parameter ppszPort.
  180. //
  181. // Note: Use I_RpcFree() to release the memory for ppszPort
  182. // when you are finished with it.
  183. //-------------------------------------------------------------
  184. CHAR *ParsePort( IN CHAR *psz,
  185. OUT CHAR **ppszPort,
  186. OUT DWORD *pdwStatus )
  187. {
  188. psz = SkipWhiteSpace(psz);
  189. if (psz)
  190. {
  191. CHAR *p = psz;
  192. while ((*p >= ZERO) && (*p <= NINE))
  193. {
  194. p++;
  195. }
  196. if (p == psz)
  197. {
  198. // The next token isn't a number...
  199. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  200. return psz;
  201. }
  202. CHAR cSave = *p;
  203. *p = 0;
  204. *ppszPort = (CHAR*)RpcpFarAllocate(1+strlen(psz));
  205. if (!*ppszPort)
  206. {
  207. *p = cSave;
  208. *pdwStatus = RPC_S_OUT_OF_MEMORY;
  209. return psz;
  210. }
  211. strcpy(*ppszPort,psz);
  212. *p = cSave;
  213. psz = p;
  214. }
  215. return psz;
  216. }
  217. //-------------------------------------------------------------
  218. // ParseMachine()
  219. //
  220. // Routine Description:
  221. //
  222. // Parse the next token as a machine name. The machine name
  223. // is returned in ppszMachine, and psz is advance to point to
  224. // the next character after the machine name.
  225. //
  226. // Note: That the machine name cannot contain any of ':' (colon),
  227. // ',' (comma), or ' ' (space). These are used in finding
  228. // the end of the machine name sub-string.
  229. //
  230. // Note: Use I_RpcFree() to release the memory for ppszMachine
  231. // when you are finished with it.
  232. //-------------------------------------------------------------
  233. CHAR *ParseMachine( IN CHAR *psz,
  234. OUT CHAR **ppszMachine,
  235. OUT DWORD *pdwStatus )
  236. {
  237. psz = SkipWhiteSpace(psz);
  238. if (psz)
  239. {
  240. CHAR *p = psz;
  241. while ((*p) && (*p != COLON) && (*p != COMMA) && (*p != SPACE))
  242. {
  243. p++;
  244. }
  245. if (p == psz)
  246. {
  247. // zero length machine name...
  248. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  249. return psz;
  250. }
  251. CHAR cSave = *p;
  252. *p = 0;
  253. *ppszMachine = (CHAR*)RpcpFarAllocate(1+strlen(psz));
  254. if (!*ppszMachine)
  255. {
  256. *p = cSave;
  257. *pdwStatus = RPC_S_OUT_OF_MEMORY;
  258. return psz;
  259. }
  260. strcpy(*ppszMachine,psz);
  261. *p = cSave;
  262. psz = p;
  263. }
  264. else
  265. {
  266. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  267. }
  268. return psz;
  269. }
  270. //-------------------------------------------------------------
  271. // KeywordMatch()
  272. //
  273. // Routine Description:
  274. //
  275. // Compare the starting characters of the string (psz) with
  276. // the specified keyword (pszKeyword). If they match independent
  277. // of case, then return TRUE. If they don't match, return FALSE.
  278. //-------------------------------------------------------------
  279. BOOL KeywordMatch( CHAR *psz,
  280. CHAR *pszKeyword )
  281. {
  282. DWORD dwLen1 = strlen( (char*)psz);
  283. DWORD dwLen2 = strlen( (char*)pszKeyword);
  284. BOOL fMatch;
  285. if (dwLen1 < dwLen2)
  286. {
  287. return FALSE; // String is not long enough to hold
  288. } // the keyword.
  289. CHAR cSave = psz[dwLen2];
  290. psz[dwLen2] = 0;
  291. if (!RpcpStringCompareA((char*)psz,(char*)pszKeyword))
  292. {
  293. // Keyword matches the start of the string.
  294. fMatch = TRUE;
  295. }
  296. else
  297. {
  298. // Not a match.
  299. fMatch = FALSE;
  300. }
  301. psz[dwLen2] = cSave;
  302. return fMatch;
  303. }
  304. //-------------------------------------------------------------
  305. // ParseKeyword()
  306. //
  307. // Routine Description:
  308. //
  309. // Parse the next token as a keyword, return its keyword ID
  310. // in pdwKid. There are currently two keywords to look for
  311. // "HttpProxy" (ID is KID_HTTPPROXY) and "RpcProxy" (ID is
  312. // KID_RPCPROXY). If the next text token doesn't match either
  313. // of these, then return KID_NONE (no match) and status is
  314. // returned as RPC_S_INVALID_NETWORK_OPTIONS.
  315. //
  316. // If there is a match return the string pointer (psz) updated
  317. // to point to the next character after the end of the keyword.
  318. //-------------------------------------------------------------
  319. CHAR *ParseKeyword( IN CHAR *psz,
  320. OUT DWORD *pdwKid,
  321. OUT DWORD *pdwStatus )
  322. {
  323. psz = SkipWhiteSpace(psz);
  324. if (psz)
  325. {
  326. if (KeywordMatch(psz,(CHAR*)KEYWORD_HTTPPROXY))
  327. {
  328. // Keyword is "HttpProxy".
  329. *pdwKid = KID_HTTPPROXY;
  330. psz += strlen(KEYWORD_HTTPPROXY);
  331. }
  332. else if (KeywordMatch(psz,(CHAR*)KEYWORD_RPCPROXY))
  333. {
  334. // Keyword is "RpcProxy".
  335. *pdwKid = KID_RPCPROXY;
  336. psz += strlen(KEYWORD_RPCPROXY);
  337. }
  338. else
  339. {
  340. *pdwKid = KID_NONE;
  341. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  342. }
  343. }
  344. return psz;
  345. }
  346. //-------------------------------------------------------------
  347. // ParseOptValue()
  348. //
  349. // Routine Description:
  350. //
  351. // Parse strings of the following form:
  352. //
  353. // OptValue <- machine ':' port
  354. // <- machine
  355. //
  356. // If the parse is successful, then return the machine name
  357. // in ppszProxy, and the port in ppszPort. These are both new
  358. // strings allocated via RpcpFarAllocate().
  359. //
  360. // The production ends with either the end of the string (null
  361. // terminated), the end of the port number (non-digit), or a
  362. // comma (which will start the begining of a new OptValue string.
  363. //
  364. // On successful parse, return updated string position to the
  365. // next character after the end of the OptValue sub-string.
  366. //-------------------------------------------------------------
  367. CHAR *ParseOptValue( IN CHAR *psz,
  368. OUT CHAR **ppszProxy,
  369. OUT CHAR **ppszPort,
  370. OUT DWORD *pdwStatus )
  371. {
  372. //
  373. // Get the machine name:
  374. //
  375. psz = ParseMachine(psz,ppszProxy,pdwStatus);
  376. if (*pdwStatus != NO_ERROR)
  377. {
  378. return psz;
  379. }
  380. //
  381. // If we're at the end of the string, or we've run into a
  382. // comma (start of another option) then we are done.
  383. //
  384. if ((!psz) || (*psz == 0) || (*psz == COMMA))
  385. {
  386. return psz;
  387. }
  388. psz = ParseLiteral(psz,COLON,pdwStatus);
  389. if (*pdwStatus != NO_ERROR)
  390. {
  391. return psz;
  392. }
  393. if (!psz)
  394. {
  395. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  396. return psz;
  397. }
  398. psz = ParsePort(psz,ppszPort,pdwStatus);
  399. return psz;
  400. }
  401. //-------------------------------------------------------------
  402. // ParseOpt()
  403. //
  404. // Routine Description:
  405. //
  406. // Opt <- Keyword '=' OptValue
  407. //
  408. // Parse an option, which is a keywork equals value pair.
  409. //
  410. // If the parse is successful, then return the machine name
  411. // in ppszProxy, and the port in ppszPort. These are both new
  412. // strings allocated via RpcpFarAllocate(), and are represented
  413. // in the OptValue non-terminal.
  414. //
  415. // The production ends with either the end of the string (null
  416. // terminated), the end of the port number (non-digit), or a
  417. // comma (which will start the begining of a new Opt string.
  418. //
  419. // On successful parse, return updated string position to the
  420. // next character after the end of the Opt (option) sub-string.
  421. //-------------------------------------------------------------
  422. CHAR *ParseOpt( IN CHAR *psz,
  423. OUT DWORD *pdwKid,
  424. OUT CHAR **ppszProxy,
  425. OUT CHAR **ppszPort,
  426. OUT DWORD *pdwStatus )
  427. {
  428. if (psz)
  429. {
  430. psz = ParseKeyword(psz,pdwKid,pdwStatus);
  431. if (*pdwStatus != NO_ERROR)
  432. {
  433. return psz;
  434. }
  435. }
  436. if (!psz)
  437. {
  438. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  439. return psz;
  440. }
  441. psz = ParseLiteral(psz,EQUALS,pdwStatus);
  442. if (*pdwStatus != NO_ERROR)
  443. {
  444. return psz;
  445. }
  446. if (!psz)
  447. {
  448. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  449. return psz;
  450. }
  451. psz = ParseOptValue(psz,ppszProxy,ppszPort,pdwStatus);
  452. if ((psz) && (*psz == 0))
  453. {
  454. psz = NULL;
  455. }
  456. return psz;
  457. }
  458. //-------------------------------------------------------------
  459. // ParseOptList()
  460. //
  461. // Routine Description:
  462. //
  463. // Parse ncacn_http network options strings. These are of the
  464. // following form:
  465. //
  466. // OptList <- Opt
  467. // <- Opt ',' Opt
  468. //
  469. // Opt <- Keyword '=' OptValue
  470. //
  471. // OptValue <- Machine ':' PortNumber
  472. // <- Machine ':'
  473. // <- Machine
  474. //
  475. // Keyword <- 'HttpProxy'
  476. // <- 'RpcProxy'
  477. //
  478. // Machine and PortNumber are terminal strings.
  479. //-------------------------------------------------------------
  480. DWORD ParseOptList( IN CHAR *pszOptList,
  481. OUT CHAR **ppszRpcProxy,
  482. OUT CHAR **ppszRpcProxyPort,
  483. OUT CHAR **ppszHttpProxy,
  484. OUT CHAR **ppszHttpProxyPort )
  485. {
  486. DWORD dwStatus = NO_ERROR;
  487. DWORD dwKid = KID_NONE;
  488. CHAR *psz = pszOptList;
  489. CHAR *pszProxy = NULL;
  490. CHAR *pszPort = NULL;
  491. psz = ParseOpt(psz,&dwKid,&pszProxy,&pszPort,&dwStatus);
  492. if (dwStatus != NO_ERROR)
  493. {
  494. return dwStatus;
  495. }
  496. if (dwKid == KID_RPCPROXY)
  497. {
  498. *ppszRpcProxy = pszProxy;
  499. *ppszRpcProxyPort = pszPort;
  500. }
  501. else if (dwKid == KID_HTTPPROXY)
  502. {
  503. *ppszHttpProxy = pszProxy;
  504. *ppszHttpProxyPort = pszPort;
  505. }
  506. if (psz)
  507. {
  508. psz = ParseLiteral(psz,COMMA,&dwStatus);
  509. if (dwStatus != NO_ERROR)
  510. {
  511. return dwStatus;
  512. }
  513. }
  514. if (psz)
  515. {
  516. pszProxy = pszPort = NULL;
  517. psz = ParseOpt(psz,&dwKid,&pszProxy,&pszPort,&dwStatus);
  518. if (dwStatus != NO_ERROR)
  519. {
  520. return dwStatus;
  521. }
  522. if (dwKid == KID_RPCPROXY)
  523. {
  524. *ppszRpcProxy = pszProxy;
  525. *ppszRpcProxyPort = pszPort;
  526. }
  527. else if (dwKid == KID_HTTPPROXY)
  528. {
  529. *ppszHttpProxy = pszProxy;
  530. *ppszHttpProxyPort = pszPort;
  531. }
  532. }
  533. psz = SkipWhiteSpace(psz);
  534. if (psz)
  535. {
  536. dwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  537. }
  538. return dwStatus;
  539. }
  540. BOOL
  541. HttpParseNetworkOptions(
  542. IN RPC_CHAR *pNetworkOptions,
  543. IN char *pszDefaultServer,
  544. OUT char **ppszRpcProxy,
  545. OUT char **ppszRpcProxyPort,
  546. IN BOOL UseSSLProxyPortAsDefault,
  547. OUT char **ppszHttpProxy,
  548. OUT char **ppszHttpProxyPort,
  549. OUT RPCProxyAccessType *AccessType,
  550. OUT DWORD *pdwStatus
  551. )
  552. /*++
  553. Routine Description:
  554. Parse the Http network options specified in the string binding. The
  555. options would look like:
  556. HttpProxy=<Server_Name>:<Port>,RpcProxy=<Server_Name>:<Port>
  557. That is, two separate proxy servers, each with an optional port.
  558. The HttpProxy=<> specification is optional, if not specified then use
  559. the specified default server name. Its default Port is 80.
  560. If RpcProxy is optional as well, if not specified then use the
  561. default server name and Port 80.
  562. Arguments:
  563. pNetworkOptions - Network options string
  564. pszDefaultServer - Default Server.
  565. ppszRpcProxy - RpcProxy, if specified in the options string.
  566. ppszRpcProxyPort - RpcProxyPort, if specified in the options string.
  567. UseSSLProxyPortAsDefault - if non-zero, the SSL port will be used as
  568. default if a port is not specified in the network options.
  569. ppszHttpProxy - HttpProxy, if specified in the options string.
  570. ppszHttpProxyPort- HttpProxyPort, if specified in the options string.
  571. AccessType - if we should try direct access, proxy access, or unknown yet.
  572. pdwStatus - Pointer to a DWORD where the return status will be put.
  573. Notes:
  574. Returned strings should be free'd with I_RpcFree().
  575. Return Value:
  576. TRUE, if successful.
  577. FALSE, otherwise. *pdwStatus will have the exact cause.
  578. --*/
  579. {
  580. char szNetworkOptions[MAX_NETWORK_OPTIONS_SIZE];
  581. char *pszNetworkOptions;
  582. char *DefaultRpcProxyPortToUse;
  583. // OUT variable initialization.
  584. *ppszRpcProxy = *ppszRpcProxyPort = NULL;
  585. *ppszHttpProxy = *ppszHttpProxyPort = NULL;
  586. *AccessType = rpcpatUnknown;
  587. *pdwStatus = 0;
  588. // Make sure we have and options string to parse:
  589. if ( (pNetworkOptions) && (*pNetworkOptions) )
  590. {
  591. // Make sure the Network Options is not too long.
  592. if (RpcpStringLength(pNetworkOptions) > MAX_NETWORK_OPTIONS_SIZE)
  593. {
  594. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  595. goto Cleanup;
  596. }
  597. // Convert it to ANSI, since HTTP is ANSI (actually ASCII I think...):
  598. SimplePlatformToAnsi(pNetworkOptions, szNetworkOptions);
  599. //
  600. // Parse out the options:
  601. //
  602. pszNetworkOptions = szNetworkOptions;
  603. *pdwStatus = ParseOptList(pszNetworkOptions,
  604. ppszRpcProxy,
  605. ppszRpcProxyPort,
  606. ppszHttpProxy,
  607. ppszHttpProxyPort );
  608. if (*pdwStatus != RPC_S_OK)
  609. {
  610. goto Cleanup;
  611. }
  612. #if FALSE
  613. psz = RpcStrTok(pszNetworkOptions, ",", &pszNetworkOptions);
  614. if (!ParseKeywordEqValue(
  615. psz,
  616. HTTP_PROXY_OPTION_STR,
  617. ppszHttpProxy,
  618. ppszHttpProxyPort,
  619. pdwStatus
  620. ))
  621. {
  622. if (*pdwStatus != RPC_S_OK)
  623. {
  624. goto Cleanup;
  625. }
  626. }
  627. if (*ppszHttpProxy)
  628. {
  629. psz = RpcStrTok(NULL, ",", &pszNetworkOptions);
  630. }
  631. if (!ParseKeywordEqValue(
  632. psz,
  633. RPC_PROXY_OPTION_STR,
  634. ppszRpcProxy,
  635. ppszRpcProxyPort,
  636. pdwStatus
  637. ))
  638. {
  639. if (*pdwStatus != RPC_S_OK)
  640. {
  641. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  642. goto Cleanup;
  643. }
  644. }
  645. #endif
  646. }
  647. // Make sure that we have an RPC Proxy (IIS machine):
  648. if (!*ppszRpcProxy)
  649. {
  650. *ppszRpcProxy = (char*)RpcpFarAllocate(1+strlen(pszDefaultServer));
  651. if (!*ppszRpcProxy)
  652. {
  653. *pdwStatus = RPC_S_OUT_OF_MEMORY;
  654. goto Cleanup;
  655. }
  656. strcpy(*ppszRpcProxy, pszDefaultServer);
  657. }
  658. else
  659. {
  660. // Length validation for RpcProxy name.
  661. if (strlen(*ppszRpcProxy) > MAX_HTTP_COMPUTERNAME_SIZE)
  662. {
  663. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  664. goto Cleanup;
  665. }
  666. }
  667. // Make sure we have a port for the RPC Proxy.
  668. if (!*ppszRpcProxyPort)
  669. {
  670. if (UseSSLProxyPortAsDefault)
  671. DefaultRpcProxyPortToUse = DEF_HTTP_SSL_PORT;
  672. else
  673. DefaultRpcProxyPortToUse = DEF_HTTP_PORT;
  674. *ppszRpcProxyPort = (char*)RpcpFarAllocate(1+strlen(DefaultRpcProxyPortToUse));
  675. if (!*ppszRpcProxyPort)
  676. {
  677. *pdwStatus = RPC_S_OUT_OF_MEMORY;
  678. goto Cleanup;
  679. }
  680. strcpy(*ppszRpcProxyPort, DefaultRpcProxyPortToUse);
  681. }
  682. // If no HTTP proxy was specified in the options string, check the
  683. // registry to see if IE has configured one:
  684. if (!*ppszHttpProxy)
  685. {
  686. if (!HttpCheckRegistry(
  687. *ppszRpcProxy,
  688. UseSSLProxyPortAsDefault,
  689. ppszHttpProxy,
  690. ppszHttpProxyPort,
  691. AccessType
  692. ) )
  693. {
  694. *pdwStatus = RPC_S_OUT_OF_MEMORY;
  695. goto Cleanup;
  696. }
  697. }
  698. else
  699. {
  700. if (!*ppszHttpProxyPort)
  701. {
  702. *ppszHttpProxyPort = (char*)RpcpFarAllocate(1+strlen(DEF_HTTP_PORT));
  703. if (!*ppszHttpProxyPort)
  704. {
  705. *pdwStatus = RPC_S_OUT_OF_MEMORY;
  706. goto Cleanup;
  707. }
  708. strcpy(*ppszHttpProxyPort, DEF_HTTP_PORT);
  709. }
  710. }
  711. // Length validation for HttpProxy name.
  712. if ((*ppszHttpProxy) &&
  713. (strlen(*ppszHttpProxy) > MAX_HTTP_COMPUTERNAME_SIZE))
  714. {
  715. *pdwStatus = RPC_S_INVALID_NETWORK_OPTIONS;
  716. goto Cleanup;
  717. }
  718. #ifdef MAJOR_DBG
  719. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  720. DPFLTR_WARNING_LEVEL,
  721. "ParseNetworkOptions(): RpcProxy: %s RpcProxyPort: %s\n",
  722. *ppszRpcProxy,
  723. *ppszRpcProxyPort));
  724. #endif // MAJOR_DBG
  725. if (*AccessType != rpcpatDirect)
  726. {
  727. ASSERT(*ppszHttpProxy);
  728. }
  729. return TRUE;
  730. Cleanup:
  731. if (*ppszRpcProxy)
  732. {
  733. I_RpcFree(*ppszRpcProxy);
  734. *ppszRpcProxy = NULL;
  735. }
  736. if (*ppszRpcProxyPort)
  737. {
  738. I_RpcFree(*ppszRpcProxyPort);
  739. *ppszRpcProxyPort = NULL;
  740. }
  741. if (*ppszHttpProxy)
  742. {
  743. I_RpcFree(*ppszHttpProxy);
  744. *ppszHttpProxy = NULL;
  745. }
  746. if (*ppszHttpProxyPort)
  747. {
  748. I_RpcFree(*ppszHttpProxyPort);
  749. *ppszHttpProxyPort = NULL;
  750. }
  751. return FALSE;
  752. }
  753. static BOOL
  754. HttpSetupTunnel(
  755. IN SOCKET Socket,
  756. IN char *pszConnect
  757. )
  758. /*++
  759. Routine Description:
  760. Try to setup a connection to the IIS RPC Proxy.
  761. Arguments:
  762. Socket - Socket on which to contact the IIS RPC Proxy.
  763. pszConnect - The message to send.
  764. Return Value:
  765. TRUE, if successful
  766. FALSE, otherwise
  767. --*/
  768. {
  769. int retval;
  770. DWORD dwStatus;
  771. DWORD dwSize;
  772. char szBuffer[MAX_HTTP_CHAT_BUFFER_SIZE];
  773. // Ok, try to connect to the IIS RPC proxy process:
  774. retval = send( Socket, pszConnect, 1+strlen(pszConnect), 0 );
  775. if (retval == SOCKET_ERROR)
  776. {
  777. #ifdef DBG
  778. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  779. DPFLTR_WARNING_LEVEL,
  780. "HttpSetupTunnel(): send() failed: %d\n",
  781. WSAGetLastError()));
  782. #endif // DBG
  783. return FALSE;
  784. }
  785. dwSize = sizeof(szBuffer) - 1;
  786. retval = recv( Socket, szBuffer, dwSize, 0 );
  787. if ((retval == SOCKET_ERROR)||(retval == 0))
  788. {
  789. #ifdef DBG
  790. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  791. DPFLTR_WARNING_LEVEL,
  792. "HttpSetupTunnel(): recv() failed: %d\n",
  793. WSAGetLastError()));
  794. #endif
  795. return FALSE;
  796. }
  797. szBuffer[dwSize] = 0; // Note: dwSize is already sizeof()-1.
  798. dwStatus = HttpParseResponse(szBuffer);
  799. #ifdef MAJOR_DBG
  800. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  801. DPFLTR_WARNING_LEVEL,
  802. "HttpSetupTunnel(): response: %s",
  803. szBuffer));
  804. #endif
  805. // Make sure a connection is established:
  806. if ( (dwStatus < 200) || (dwStatus > 299) )
  807. {
  808. #ifdef DBG
  809. TransDbgPrint((DPFLTR_RPCPROXY_ID,
  810. DPFLTR_WARNING_LEVEL,
  811. "HttpSetupTunnel(): Connection Failed: %d\n",
  812. dwStatus));
  813. #endif
  814. return FALSE;
  815. }
  816. return TRUE;
  817. }
  818. inline BOOL
  819. HttpTunnelToRpcProxy(
  820. IN SOCKET Socket,
  821. IN char *pszRpcProxy,
  822. IN char *pszRpcProxyPort
  823. )
  824. /*++
  825. Routine Description:
  826. This function is called to setup the HTTP chat to do a CONNECT
  827. through a proxy (like MSProxy). This will get you a tunnel to
  828. the IIS Server that you really want to get to. The call at the
  829. end, HttpSetupTunnel() does the connection.
  830. Arguments:
  831. Socket - Socket on which to contact the IIS RPC Proxy.
  832. pszRpcProxy - The RPC Proxy to connect to.
  833. pszRpcProxyPort - RPC Proxy's port.
  834. Return Value:
  835. Status from HttpSetupTunnel()
  836. --*/
  837. {
  838. char szBuffer[MAX_HTTP_CHAT_BUFFER_SIZE];
  839. // make sure strings use \r\n instead of \n only. \n goes on the wire
  840. // as LF only, and some firewalls drop packets that use LF only
  841. strcpy(szBuffer, "CONNECT ");
  842. lstrcatA(szBuffer, pszRpcProxy);
  843. lstrcatA(szBuffer, ":");
  844. lstrcatA(szBuffer, pszRpcProxyPort);
  845. lstrcatA(szBuffer, " HTTP/1.0\r\nUser-Agent: RPC\r\nConnection: Keep-Alive\r\n\r\n");
  846. // Was:
  847. //
  848. // lstrcatA(szBuffer, " HTTP/1.1\nUser-Agent: RPC\nPragma: No-Cache\n\n");
  849. //
  850. // Some proxy servers (like MSProxy2.0 don't seem to like the version
  851. // number to be greater that 1.0.
  852. ASSERT(strlen(szBuffer) < MAX_HTTP_CHAT_BUFFER_SIZE);
  853. return HttpSetupTunnel(Socket, szBuffer);
  854. }
  855. inline BOOL
  856. HttpTunnelToRpcServer(
  857. IN SOCKET Socket,
  858. IN char *pszRpcServer,
  859. IN char *pszRpcServerPort
  860. )
  861. /*++
  862. Routine Description:
  863. Open the socket to the IIS on which the RpcProxy resides.
  864. Arguments:
  865. Socket - Socket on which to contact the IIS RPC Proxy.
  866. pszRpcServer - The RPC Server to connect to.
  867. pszRpcServerPort - RPC Server's port.
  868. Return Value:
  869. Status from HttpSetupTunnel()
  870. --*/
  871. {
  872. int retval;
  873. DWORD dwStatus;
  874. char szBuffer[MAX_HTTP_CHAT_BUFFER_SIZE];
  875. strcpy(szBuffer, "RPC_CONNECT ");
  876. lstrcatA(szBuffer, pszRpcServer);
  877. lstrcatA(szBuffer, ":");
  878. lstrcatA(szBuffer, pszRpcServerPort);
  879. lstrcatA(szBuffer, " HTTP/1.1\nUser-Agent: RPC\nPragma: No-Cache\n\n");
  880. ASSERT(strlen(szBuffer) < MAX_HTTP_CHAT_BUFFER_SIZE);
  881. // Ok, try to connect to the RPC server process:
  882. return HttpSetupTunnel(Socket, szBuffer);
  883. }