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.

289 lines
7.1 KiB

  1. #include "stdafx.h"
  2. #include "common.h"
  3. #include "hosthead.h"
  4. #include "iisdebug.h"
  5. #include <lm.h>
  6. #include <ipexport.h>
  7. #include <ntdef.h>
  8. #ifdef _DEBUG
  9. #undef THIS_FILE
  10. static char BASED_CODE THIS_FILE[] = __FILE__;
  11. #endif
  12. #define new DEBUG_NEW
  13. #define DEFAULT_MAX_LABEL_LENGTH 63
  14. #define ANSI_HIGH_MAX 0x00ff
  15. #define IS_ANSI(c) ((unsigned) (c) <= ANSI_HIGH_MAX)
  16. #define ISDIGIT(x) ( x >= '0' && x <= '9' ? (TRUE) : FALSE )
  17. #define ISHEX(x) ( x >= '0' && x <= '9' ? (TRUE) : \
  18. x >= 'A' && x <= 'F' ? (TRUE) : \
  19. x >= 'a' && x <= 'f' ? (TRUE) : FALSE )
  20. #define IS_ILLEGAL_COMPUTERNAME_SET(x) (\
  21. x == '\"' ? (TRUE) : \
  22. x == '/' ? (TRUE) : \
  23. x == '\\' ? (TRUE) : \
  24. x == '[' ? (TRUE) : \
  25. x == ']' ? (TRUE) : \
  26. x == ':' ? (TRUE) : \
  27. x == '|' ? (TRUE) : \
  28. x == ' ' ? (TRUE) : \
  29. x == '%' ? (TRUE) : \
  30. x == '<' ? (TRUE) : \
  31. x == '>' ? (TRUE) : \
  32. x == '+' ? (TRUE) : \
  33. x == '=' ? (TRUE) : \
  34. x == ';' ? (TRUE) : \
  35. x == ',' ? (TRUE) : \
  36. x == '?' ? (TRUE) : \
  37. x == '*' ? (TRUE) : \
  38. FALSE )
  39. // returns:
  40. // S_OK if it is a valid domain or ipv4 address
  41. // E_FAIL if it is not a valid domain or ipv4 address
  42. //
  43. // comments:
  44. // This code was stolen from NT\net\http\common\C14n.c
  45. // and then modified.
  46. HRESULT IsHostHeaderDomainNameOrIPv4(LPCTSTR pHostname)
  47. {
  48. HRESULT hRes = E_FAIL;
  49. LPCTSTR pChar = NULL;
  50. LPCTSTR pLabel = NULL;
  51. LPCTSTR pEnd = pHostname + _tcslen(pHostname);
  52. BOOL AlphaLabel = FALSE;
  53. INT iPeriodCounts = 0;
  54. NTSTATUS Status;
  55. //
  56. // It must be a domain name or an IPv4 literal. We'll try to treat
  57. // it as a domain name first. If the labels turn out to be all-numeric,
  58. // we'll try decoding it as an IPv4 literal.
  59. //
  60. pLabel = pHostname;
  61. for (pChar = pHostname; pChar < pEnd; ++pChar)
  62. {
  63. // check each character...
  64. if (L'.' == *pChar)
  65. {
  66. ULONG LabelLength = DIFF(pChar - pLabel);
  67. iPeriodCounts++;
  68. // There must be at least one char in the label
  69. if (0 == LabelLength)
  70. {
  71. // Empty label, can't have that...
  72. goto IsHostHeaderDomainNameOrIPv4_Exit;
  73. }
  74. // Label can't have more than 63 chars
  75. if (LabelLength > DEFAULT_MAX_LABEL_LENGTH)
  76. {
  77. // label is too long, can't have that...
  78. goto IsHostHeaderDomainNameOrIPv4_Exit;
  79. }
  80. // Reset for the next label
  81. pLabel = pChar + _tcslen(_T("."));
  82. continue;
  83. }
  84. //
  85. // All chars above 0xFF are considered valid
  86. //
  87. if (!IS_ANSI(*pChar) || !IS_ILLEGAL_COMPUTERNAME_SET(*pChar))
  88. {
  89. if (!IS_ANSI(*pChar) || !ISDIGIT(*pChar))
  90. AlphaLabel = TRUE;
  91. if (pChar > pLabel)
  92. continue;
  93. // The first char of a label cannot be a hyphen. (Underscore?)
  94. if (L'-' == *pChar)
  95. {
  96. // um yeah.
  97. goto IsHostHeaderDomainNameOrIPv4_Exit;
  98. }
  99. continue;
  100. }
  101. // We found some invalid characters in there...
  102. goto IsHostHeaderDomainNameOrIPv4_Exit;
  103. }
  104. // if we get here then the string is either
  105. // a valid domain name or a semi valid ipv4 address
  106. // check if the label had at least one alpha character..
  107. if (AlphaLabel)
  108. {
  109. // if there was a non digit character,
  110. // then it's a domain name.
  111. // this is fine.
  112. hRes = S_OK;
  113. }
  114. else
  115. {
  116. // this could be a ipv4 address
  117. // if there are periods in there... like
  118. // 0.0.0.0 then this is acceptable
  119. // but all number is not
  120. if (iPeriodCounts > 0 )
  121. {
  122. struct in_addr IPv4Address;
  123. LPCTSTR pTerminator = NULL;
  124. // Let's see if it's a valid IPv4 address
  125. Status = RtlIpv4StringToAddressW(
  126. (LPCTSTR) pHostname,
  127. TRUE, // strict => 4 dotted decimal octets
  128. &pTerminator,
  129. &IPv4Address
  130. );
  131. if (!NT_SUCCESS(Status))
  132. {
  133. // Invalid IPv4 address
  134. //RETURN(Status);
  135. goto IsHostHeaderDomainNameOrIPv4_Exit;
  136. }
  137. hRes = S_OK;
  138. }
  139. }
  140. IsHostHeaderDomainNameOrIPv4_Exit:
  141. return hRes;
  142. }
  143. // returns:
  144. // S_OK if it is a valid IPv6 address
  145. // S_FALSE if it is a IPv6 address but something is invalid about it
  146. // E_FAIL if it is not a IPv6 address
  147. //
  148. // comments:
  149. // This code was stolen from NT\net\http\common\C14n.c
  150. // and then modified.
  151. HRESULT IsHostHeaderIPV6(LPCTSTR pHostname)
  152. {
  153. HRESULT hRes = E_FAIL;
  154. LPCTSTR pChar = NULL;
  155. LPCTSTR pEnd = pHostname + _tcslen(pHostname);
  156. NTSTATUS Status;
  157. // Is this an IPv6 literal address, per RFC 2732?
  158. if ('[' == *pHostname)
  159. {
  160. // If it starts with a [
  161. // then it's a IPv6 type
  162. hRes = S_FALSE;
  163. // Empty brackets?
  164. if (_tcslen(pHostname) < _tcslen(_T("[0]"))
  165. || _T(']') == pHostname[1])
  166. {
  167. goto IsHostHeaderIPV6_Exit;
  168. }
  169. for (pChar = pHostname + _tcslen(_T("[")); pChar < pEnd; ++pChar)
  170. {
  171. if (']' == *pChar)
  172. break;
  173. //
  174. // Dots are allowed because the last 32 bits may be represented
  175. // in IPv4 dotted-octet notation. We do not accept Scope IDs
  176. // (indicated by '%') in hostnames.
  177. //
  178. if (ISHEX(*pChar) || ':' == *pChar || '.' == *pChar)
  179. continue;
  180. // Invalid Characters between brackets...
  181. goto IsHostHeaderIPV6_Exit;
  182. }
  183. if (pChar == pEnd)
  184. {
  185. // No ending ']'
  186. goto IsHostHeaderIPV6_Exit;
  187. }
  188. {
  189. struct in6_addr IPv6Address;
  190. LPCTSTR pTerminator = NULL;
  191. // Let the RTL routine do the hard work of parsing IPv6 addrs
  192. Status = RtlIpv6StringToAddressW(
  193. (LPCTSTR) pHostname + _tcslen(_T("[")),
  194. &pTerminator,
  195. &IPv6Address
  196. );
  197. if (! NT_SUCCESS(Status))
  198. {
  199. // Invalid IPv6 address
  200. //RETURN(Status);
  201. goto IsHostHeaderIPV6_Exit;
  202. }
  203. }
  204. // if we got this far, then
  205. // it's probably a valid IPv6 literal
  206. hRes = S_OK;
  207. }
  208. IsHostHeaderIPV6_Exit:
  209. return hRes;
  210. }
  211. HRESULT IsAllNumHostHeader(LPCTSTR pHostname)
  212. {
  213. HRESULT hRes = S_OK;
  214. LPCTSTR pChar = NULL;
  215. LPCTSTR pEnd = pHostname + _tcslen(pHostname);
  216. for (pChar = pHostname; pChar < pEnd; ++pChar)
  217. {
  218. if (!IS_ANSI(*pChar) || !ISDIGIT(*pChar))
  219. {
  220. // Found an alpha label
  221. // return false, that it's not all numeric
  222. hRes = E_FAIL;
  223. break;
  224. }
  225. }
  226. return hRes;
  227. }
  228. HRESULT IsValidHostHeader(LPCTSTR pHostHeader)
  229. {
  230. HRESULT hr = E_FAIL;
  231. hr = IsHostHeaderIPV6(pHostHeader);
  232. if (S_OK == hr)
  233. {
  234. // It is a valid IPV6 address
  235. return S_OK;
  236. }
  237. if (S_FALSE == hr)
  238. {
  239. // It is a IPV6 address but there is something wrong with it
  240. return E_FAIL;
  241. }
  242. else
  243. {
  244. // it is not a IPV6 literal
  245. // Check if it's something else...
  246. hr = IsHostHeaderDomainNameOrIPv4(pHostHeader);
  247. }
  248. return hr;
  249. }