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.

636 lines
17 KiB

  1. //---------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation, 1997 - 1999
  3. //
  4. // httpreg.c
  5. //
  6. // HTTP/RPC Proxy Registry Functions.
  7. //
  8. // Author:
  9. // 06-16-97 Edward Reus Initial version.
  10. //
  11. //---------------------------------------------------------------------------
  12. #include <sysinc.h>
  13. #include <rpc.h>
  14. #include <rpcdce.h>
  15. #include <winsock2.h>
  16. #include <httpfilt.h>
  17. #include <httpext.h>
  18. #include <mbstring.h>
  19. #include "ecblist.h"
  20. #include "filter.h"
  21. #include "regexp.h"
  22. //-------------------------------------------------------------------------
  23. // AtoUS()
  24. //
  25. // Convert a numeric string to an unsigned short. If the conversion
  26. // fails return FALSE.
  27. //-------------------------------------------------------------------------
  28. static BOOL AtoUS( char *pszValue, unsigned short *pusValue )
  29. {
  30. int iValue;
  31. size_t iLen = strlen(pszValue);
  32. *pusValue = 0;
  33. if ((iLen == 0) || (iLen > 5) || (iLen != strspn(pszValue,"0123456789")))
  34. {
  35. return FALSE;
  36. }
  37. iValue = atoi(pszValue);
  38. if ((iValue < 0) || (iValue > 65535))
  39. {
  40. return FALSE;
  41. }
  42. *pusValue = (unsigned short) iValue;
  43. return TRUE;
  44. }
  45. //-------------------------------------------------------------------------
  46. // HttpParseServerPort()
  47. //
  48. // Parse strings of the form: <svr>:<port>[-<port>]
  49. //
  50. // Return TRUE iff we have a valid specification of a server/port range.
  51. //-------------------------------------------------------------------------
  52. static BOOL HttpParseServerPort( IN char *pszServerPortRange,
  53. OUT VALID_PORT *pValidPort )
  54. {
  55. char *psz;
  56. char *pszColon;
  57. char *pszDash;
  58. if (pszColon=_mbschr(pszServerPortRange,':'))
  59. {
  60. if (pszColon == pszServerPortRange)
  61. {
  62. return FALSE;
  63. }
  64. *pszColon = 0;
  65. psz = pszColon;
  66. psz++;
  67. pValidPort->pszMachine = (char*)MemAllocate(1+lstrlen(pszServerPortRange));
  68. if (!pValidPort->pszMachine)
  69. {
  70. return FALSE;
  71. }
  72. lstrcpy(pValidPort->pszMachine,pszServerPortRange);
  73. *pszColon = ':';
  74. if (*psz)
  75. {
  76. if (pszDash=_mbschr(psz,'-'))
  77. {
  78. *pszDash = 0;
  79. if (!AtoUS(psz,&pValidPort->usPort1))
  80. {
  81. pValidPort->pszMachine = MemFree(pValidPort->pszMachine);
  82. return FALSE;
  83. }
  84. *pszDash = '-';
  85. psz = pszDash;
  86. if (!AtoUS(++psz,&pValidPort->usPort2))
  87. {
  88. pValidPort->pszMachine = MemFree(pValidPort->pszMachine);
  89. return FALSE;
  90. }
  91. }
  92. else
  93. {
  94. if (!AtoUS(psz,&pValidPort->usPort1))
  95. {
  96. pValidPort->pszMachine = MemFree(pValidPort->pszMachine);
  97. return FALSE;
  98. }
  99. pValidPort->usPort2 = pValidPort->usPort1;
  100. }
  101. }
  102. else
  103. {
  104. pValidPort->pszMachine = MemFree(pValidPort->pszMachine);
  105. return FALSE;
  106. }
  107. }
  108. else
  109. {
  110. return FALSE;
  111. }
  112. return TRUE;
  113. }
  114. //-------------------------------------------------------------------------
  115. // HttpFreeValidPortList()
  116. //
  117. //-------------------------------------------------------------------------
  118. void HttpFreeValidPortList( IN VALID_PORT *pValidPorts )
  119. {
  120. VALID_PORT *pCurrent = pValidPorts;
  121. if (pValidPorts)
  122. {
  123. while (pCurrent->pszMachine)
  124. {
  125. MemFree(pCurrent->pszMachine);
  126. if (pCurrent->ppszDotMachineList)
  127. {
  128. FreeIpAddressList(pCurrent->ppszDotMachineList);
  129. }
  130. pCurrent++;
  131. }
  132. MemFree(pValidPorts);
  133. }
  134. }
  135. //-------------------------------------------------------------------------
  136. // HttpParseValidPortsList()
  137. //
  138. // Given a semicolon separated list of valid machine name/port ranges
  139. // string, part it and return an array of ValidPort structures. The last
  140. // entry has a NULL pszMachine field.
  141. //-------------------------------------------------------------------------
  142. static VALID_PORT *HttpParseValidPortsList( IN char *pszValidPorts )
  143. {
  144. int i;
  145. int iLen;
  146. int count = 1;
  147. DWORD dwSize = 1+lstrlen(pszValidPorts);
  148. char *pszList;
  149. char *psz;
  150. VALID_PORT *pValidPorts = NULL;
  151. if (!dwSize)
  152. {
  153. return NULL;
  154. }
  155. // Make a local copy of the machine/ports list to work with:
  156. pszList = _alloca(dwSize);
  157. if (!pszList)
  158. {
  159. // Out of memory.
  160. return NULL;
  161. }
  162. lstrcpy(pszList,pszValidPorts);
  163. // See how many separate machine/port range patterns ther are in
  164. // the list:
  165. //
  166. // NOTE: That count may be too high, if either the list contains
  167. // double semicolons or the list ends with a semicolon. If
  168. // either/both of these happen that's Ok, our array will be
  169. // just a little too long.
  170. psz = pszList;
  171. while (psz=_mbsstr(psz,";"))
  172. {
  173. count++;
  174. psz++;
  175. }
  176. pValidPorts = (VALID_PORT*)MemAllocate( (1+count)*sizeof(VALID_PORT) );
  177. if (!pValidPorts)
  178. {
  179. // Out of memory.
  180. return NULL;
  181. }
  182. memset(pValidPorts,0,(1+count)*sizeof(VALID_PORT));
  183. i = 0;
  184. while (i<count)
  185. {
  186. if (!*pszList)
  187. {
  188. // End of list. This happens when the list contained empty
  189. // patterns.
  190. break;
  191. }
  192. psz = _mbsstr(pszList,";");
  193. if (psz)
  194. {
  195. *psz = 0; // Nul where the semicolon was...
  196. if ( (iLen=lstrlen(pszList)) == 0)
  197. {
  198. // Zero length pattern.
  199. pszList = ++psz;
  200. continue;
  201. }
  202. if (!HttpParseServerPort(pszList,&(pValidPorts[i++])))
  203. {
  204. HttpFreeValidPortList(pValidPorts);
  205. return NULL;
  206. }
  207. }
  208. else
  209. {
  210. // Last one.
  211. if (!HttpParseServerPort(pszList,&(pValidPorts[i++])))
  212. {
  213. HttpFreeValidPortList(pValidPorts);
  214. return NULL;
  215. }
  216. }
  217. pszList = ++psz;
  218. }
  219. return pValidPorts;
  220. }
  221. //-------------------------------------------------------------------------
  222. // HttpProxyCheckRegistry()
  223. //
  224. // Check the registry to see if HTTP/RPC is enabled and if so, return a
  225. // list (array) of machines that the RPC Proxy is allowed to reach (may
  226. // be NULL. If the proxy is enabled but the list is NULL they you can
  227. // only do RPC to processes local to the IIS HTTP/RPC Proxy. Otherwise,
  228. // the returned list specifies specifically what machines may be reached
  229. // by the proxy.
  230. //
  231. // The following registry entries are found in:
  232. //
  233. // \HKEY_LOCAL_MACHINE
  234. // \Software
  235. // \Microsoft
  236. // \Rpc
  237. // \RpcProxy
  238. //
  239. // Enabled : REG_DWORD
  240. //
  241. // TRUE iff the RPC proxy is enabled.
  242. //
  243. // ValidPorts : REG_SZ
  244. //
  245. // Semicolon separated list of machine/port ranges used to specify
  246. // what machine are reachable from the RPC proxy. For example:
  247. //
  248. // foxtrot:1-4000;Data*:200-4000
  249. //
  250. // Will allow access to the machine foxtrot (port ranges 1 to 4000) and
  251. // to all machines whose name begins with Data (port ranges 200-4000).
  252. //
  253. //-------------------------------------------------------------------------
  254. BOOL HttpProxyCheckRegistry( OUT DWORD *pdwEnabled,
  255. OUT VALID_PORT **ppValidPorts )
  256. {
  257. int i;
  258. long lStatus;
  259. DWORD dwType;
  260. DWORD dwSize;
  261. HKEY hKey;
  262. char *pszValidPorts;
  263. struct hostent UNALIGNED *pHostEnt;
  264. struct in_addr ServerInAddr;
  265. *pdwEnabled = FALSE;
  266. *ppValidPorts = NULL;
  267. lStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,REG_PROXY_PATH_STR,0,KEY_READ,&hKey);
  268. if (lStatus != ERROR_SUCCESS)
  269. {
  270. return TRUE;
  271. }
  272. dwSize = sizeof(*pdwEnabled);
  273. lStatus = RegQueryValueEx(hKey,REG_PROXY_ENABLE_STR,0,&dwType,(LPBYTE)pdwEnabled,&dwSize);
  274. if (lStatus != ERROR_SUCCESS)
  275. {
  276. RegCloseKey(hKey);
  277. return TRUE;
  278. }
  279. if (!*pdwEnabled)
  280. {
  281. // RPC Proxy is disabled, no need to go on.
  282. RegCloseKey(hKey);
  283. return TRUE;
  284. }
  285. dwSize = 0;
  286. lStatus = RegQueryValueEx(hKey,REG_PROXY_VALID_PORTS_STR,0,&dwType,(LPBYTE)NULL,&dwSize);
  287. if ( (lStatus != ERROR_SUCCESS) || (dwSize == 0) )
  288. {
  289. // I don't care if this registry entry is missing, just won't be able to talk to
  290. // any other machines.
  291. RegCloseKey(hKey);
  292. return TRUE;
  293. }
  294. // dwSize is now how big the valid ports string is (including the trailing nul.
  295. pszValidPorts = (char*)_alloca(dwSize);
  296. lStatus = RegQueryValueEx(hKey,REG_PROXY_VALID_PORTS_STR,0,&dwType,(LPBYTE)pszValidPorts,&dwSize);
  297. if (lStatus != ERROR_SUCCESS)
  298. {
  299. RegCloseKey(hKey);
  300. return FALSE;
  301. }
  302. RegCloseKey(hKey);
  303. *ppValidPorts = HttpParseValidPortsList(pszValidPorts);
  304. return TRUE;
  305. }
  306. //-------------------------------------------------------------------------
  307. // HttpConvertToDotAddress()
  308. //
  309. // Convert the specified machine name to IP dot notation if possible.
  310. //-------------------------------------------------------------------------
  311. char *HttpConvertToDotAddress( char *pszMachineName )
  312. {
  313. struct hostent UNALIGNED *pHostEnt;
  314. struct in_addr MachineInAddr;
  315. char *pszDot = NULL;
  316. char *pszDotMachine = NULL;
  317. pHostEnt = gethostbyname(pszMachineName);
  318. if (pHostEnt)
  319. {
  320. memcpy(&MachineInAddr,pHostEnt->h_addr,pHostEnt->h_length);
  321. pszDot = inet_ntoa(MachineInAddr);
  322. }
  323. if (pszDot)
  324. {
  325. pszDotMachine = (char*)MemAllocate(1+lstrlen(pszDot));
  326. if (pszDotMachine)
  327. {
  328. lstrcpy(pszDotMachine,pszDot);
  329. }
  330. }
  331. return pszDotMachine;
  332. }
  333. //-------------------------------------------------------------------------
  334. // HttpNameToDotAddressList()
  335. //
  336. // Convert the specified machine name to IP dot notation if possible.
  337. // Return a list (null terminated) of the IP dot addresses in ascii.
  338. //
  339. // If the function fails, then retrun NULL. It can fail if gethostbyname()
  340. // fails, or memory allocation fails.
  341. //-------------------------------------------------------------------------
  342. char **HttpNameToDotAddressList( IN char *pszMachineName )
  343. {
  344. int i;
  345. int iCount = 0;
  346. struct hostent UNALIGNED *pHostEnt;
  347. struct in_addr MachineInAddr;
  348. char **ppszDotList = NULL;
  349. char *pszDot = NULL;
  350. char *pszDotMachine = NULL;
  351. pHostEnt = gethostbyname(pszMachineName);
  352. if (pHostEnt)
  353. {
  354. // Count how many addresses we have:
  355. while (pHostEnt->h_addr_list[iCount])
  356. {
  357. iCount++;
  358. }
  359. // Make sure we have at lease one address:
  360. if (iCount > 0)
  361. {
  362. ppszDotList = (char**)MemAllocate( sizeof(char*)*(1+iCount) );
  363. }
  364. // Build an array of strings, holding the addresses (ascii DOT
  365. // notation:
  366. if (ppszDotList)
  367. {
  368. for (i=0; i<iCount; i++)
  369. {
  370. memcpy(&MachineInAddr,
  371. pHostEnt->h_addr_list[i],
  372. pHostEnt->h_length);
  373. pszDot = inet_ntoa(MachineInAddr);
  374. if (pszDot)
  375. {
  376. ppszDotList[i] = (char*)MemAllocate(1+lstrlen(pszDot));
  377. if (ppszDotList[i])
  378. {
  379. strcpy(ppszDotList[i],pszDot);
  380. }
  381. else
  382. {
  383. // memory allocate failed:
  384. break;
  385. }
  386. }
  387. }
  388. ppszDotList[i] = NULL; // Null terminated list.
  389. }
  390. }
  391. return ppszDotList;
  392. }
  393. //-------------------------------------------------------------------------
  394. // CheckDotCacheTimestamp()
  395. //
  396. // Return true if the current time stamp is aged out.
  397. //-------------------------------------------------------------------------
  398. static BOOL CheckDotCacheTimestamp( DWORD dwCurrentTickCount,
  399. DWORD dwDotCacheTimestamp )
  400. {
  401. if ( (dwCurrentTickCount < dwDotCacheTimestamp)
  402. || ((dwCurrentTickCount - dwDotCacheTimestamp) > HOST_ADDR_CACHE_LIFE) )
  403. {
  404. return TRUE;
  405. }
  406. return FALSE;
  407. }
  408. //-------------------------------------------------------------------------
  409. // CheckPort()
  410. //
  411. //-------------------------------------------------------------------------
  412. static BOOL CheckPort( SERVER_CONNECTION *pConn,
  413. VALID_PORT *pValidPort )
  414. {
  415. return ( (pConn->dwPortNumber >= pValidPort->usPort1)
  416. && (pConn->dwPortNumber <= pValidPort->usPort2) );
  417. }
  418. //-------------------------------------------------------------------------
  419. // HttpProxyIsValidMachine()
  420. //
  421. //-------------------------------------------------------------------------
  422. BOOL HttpProxyIsValidMachine( SERVER_INFO *pServerInfo,
  423. SERVER_CONNECTION *pConn )
  424. {
  425. int i;
  426. char **ppszDot;
  427. DWORD dwTicks;
  428. DWORD dwSize;
  429. DWORD dwStatus;
  430. VALID_PORT *pValidPorts;
  431. // See if the machine is this (local) one, if so, then
  432. // its access is Ok.
  433. if (!_mbsicmp(pConn->pszMachine,pServerInfo->pszLocalMachineName))
  434. {
  435. return TRUE;
  436. }
  437. // Ok convert the local machine name to dot notation and
  438. // see if we have a match:
  439. dwTicks = GetTickCount();
  440. dwStatus = RtlEnterCriticalSection(&pServerInfo->cs);
  441. // We keep a cache of the IP addresses for the local machine name,
  442. // that chach ages out every ~5 minutes, to allow for dynamic change
  443. // of IP addresses. This does the age-out of the IP address list:
  444. if ( (pServerInfo->ppszLocalDotMachineList)
  445. && CheckDotCacheTimestamp(dwTicks,pServerInfo->dwDotCacheTimestamp) )
  446. {
  447. FreeIpAddressList(pServerInfo->ppszLocalDotMachineList);
  448. pServerInfo->ppszLocalDotMachineList = NULL;
  449. }
  450. // If we don't (or no longer have) a list of the IP addresses for the
  451. // local machine, then generate it:
  452. if (!pServerInfo->ppszLocalDotMachineList)
  453. {
  454. pServerInfo->dwDotCacheTimestamp = dwTicks;
  455. pServerInfo->ppszLocalDotMachineList
  456. = HttpNameToDotAddressList(pServerInfo->pszLocalMachineName);
  457. }
  458. // Go through a list of the IP addresses to see if we have a match.
  459. // Note that the machine may have more than one address associated
  460. // with it:
  461. if ( (pServerInfo->ppszLocalDotMachineList)
  462. && (pConn->pszDotMachine) )
  463. {
  464. ppszDot = pServerInfo->ppszLocalDotMachineList;
  465. while (*ppszDot)
  466. {
  467. if (!_mbsicmp(pConn->pszDotMachine,*ppszDot))
  468. {
  469. dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs);
  470. return TRUE;
  471. }
  472. else
  473. {
  474. ppszDot++;
  475. }
  476. }
  477. }
  478. dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs);
  479. // Check the machine name against those that were allowed
  480. // in the registry:
  481. dwStatus = RtlEnterCriticalSection(&pServerInfo->cs);
  482. pValidPorts = pServerInfo->pValidPorts;
  483. if (pValidPorts)
  484. {
  485. while (pValidPorts->pszMachine)
  486. {
  487. // See if we have a name match:
  488. if ( (MatchREi(pConn->pszMachine,pValidPorts->pszMachine))
  489. && (CheckPort(pConn,pValidPorts)) )
  490. {
  491. dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs);
  492. return TRUE;
  493. }
  494. // The "valid entry" in the registry might be an address
  495. // wildcard, check it:
  496. if ( (pConn->pszDotMachine)
  497. && (MatchREi(pConn->pszDotMachine,pValidPorts->pszMachine))
  498. && (CheckPort(pConn,pValidPorts)) )
  499. {
  500. dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs);
  501. return TRUE;
  502. }
  503. // If the address list is aged out then get rid of it.
  504. if ( (pValidPorts->ppszDotMachineList)
  505. && CheckDotCacheTimestamp(dwTicks,pServerInfo->dwDotCacheTimestamp))
  506. {
  507. FreeIpAddressList(pValidPorts->ppszDotMachineList);
  508. pValidPorts->ppszDotMachineList = NULL;
  509. }
  510. // Make up a new list of addresses for this machine.
  511. if (!pValidPorts->ppszDotMachineList)
  512. {
  513. // Note: that this will only work if the name in the valid
  514. // ports list is not a wildcard.
  515. //
  516. // Note: pServerInfo->dwCacheTicks will have been updated
  517. // above...
  518. //
  519. pValidPorts->ppszDotMachineList
  520. = HttpNameToDotAddressList(pValidPorts->pszMachine);
  521. }
  522. // Try a match using internet dot address:
  523. if ( (pValidPorts->ppszDotMachineList)
  524. && (pConn->pszDotMachine)
  525. && (CheckPort(pConn,pValidPorts)) )
  526. {
  527. // Note that the machine may have more than one address
  528. // associated with it:
  529. //
  530. ppszDot = pValidPorts->ppszDotMachineList;
  531. while (*ppszDot)
  532. {
  533. if (!_mbsicmp(pConn->pszDotMachine,*ppszDot))
  534. {
  535. dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs);
  536. return TRUE;
  537. }
  538. else
  539. {
  540. ppszDot++;
  541. }
  542. }
  543. }
  544. pValidPorts++;
  545. }
  546. }
  547. dwStatus = RtlLeaveCriticalSection(&pServerInfo->cs);
  548. return FALSE;
  549. }