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.

453 lines
15 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. #include <winsock2.h>
  4. #include <stdio.h>
  5. #include "utils.h"
  6. #include <ncxbase.h> // Needed in order to use SzLoadIds
  7. #include <setupapi.h>
  8. #include <strsafe.h>
  9. #include "wlbsconfig.h"
  10. //#include "utils.tmh"
  11. #define MAXIPSTRLEN 20
  12. //+----------------------------------------------------------------------------
  13. //
  14. // Function: IpAddressFromAbcdWsz
  15. //
  16. // Synopsis:Converts caller's a.b.c.d IP address string to a network byte order IP
  17. // address. 0 if formatted incorrectly.
  18. //
  19. // Arguments: IN const WCHAR* wszIpAddress - ip address in a.b.c.d unicode string
  20. //
  21. // Returns: DWORD - IPAddr, return INADDR_NONE on failure
  22. //
  23. // History: fengsun Created Header 12/8/98
  24. //
  25. //+----------------------------------------------------------------------------
  26. DWORD WINAPI IpAddressFromAbcdWsz(IN const WCHAR* wszIpAddress)
  27. {
  28. CHAR szIpAddress[MAXIPSTRLEN + 1];
  29. DWORD nboIpAddr;
  30. ASSERT(lstrlen(wszIpAddress) < MAXIPSTRLEN);
  31. WideCharToMultiByte(CP_ACP, 0, wszIpAddress, -1,
  32. szIpAddress, sizeof(szIpAddress), NULL, NULL);
  33. nboIpAddr = inet_addr(szIpAddress);
  34. return(nboIpAddr);
  35. }
  36. //+----------------------------------------------------------------------------
  37. //
  38. // Function: IpAddressToAbcdWsz
  39. //
  40. // Synopsis:
  41. // Converts IpAddr to a string in the a.b.c.d form and returns same in
  42. // caller's wszIpAddress buffer.
  43. //
  44. // The caller MUST provider a buffer that is at least MAXIPSTRLEN + 1 WCHAR long.
  45. //
  46. // Arguments: IPAddr IpAddress -
  47. // OUT WCHAR* wszIpAddress - buffer at least MAXIPSTRLEN
  48. // IN const DWORD dwBufSize - size of wszIpAddress buffer in WCHARs
  49. //
  50. // Returns: void
  51. //
  52. // History: fengsun Created Header 12/21/98
  53. // chrisdar 07-Mar-2002 - Added argument for the size of the output buffer
  54. //
  55. //+----------------------------------------------------------------------------
  56. VOID
  57. WINAPI AbcdWszFromIpAddress(
  58. IN DWORD IpAddress,
  59. OUT WCHAR* wszIpAddress,
  60. IN const DWORD dwBufSize)
  61. {
  62. ASSERT(wszIpAddress);
  63. if (dwBufSize == 0)
  64. {
  65. return;
  66. }
  67. wszIpAddress[0] = L'\0';
  68. LPSTR AnsiAddressString = inet_ntoa( *(struct in_addr *)&IpAddress );
  69. ASSERT(AnsiAddressString);
  70. if (AnsiAddressString == NULL)
  71. {
  72. return ;
  73. }
  74. int iLen = MultiByteToWideChar(CP_ACP, 0, AnsiAddressString, -1 ,
  75. wszIpAddress, dwBufSize);
  76. //
  77. // There are three states that MultiByteToWideChar can return:
  78. // 1) iLen == 0 This means the call failed
  79. // 2) iLen > 0 when dwBufSize > 0 This means the call succeeded
  80. // 3) iLen > 0 when dwBufSize == 0 This means the call succeeded, but only to inform the caller of
  81. // the required size of the out buffer in wide chars. The buffer is not modified.
  82. // This last case is prevented from occuring above by an early return if dwBufSize == 0.
  83. //
  84. // Note also that an 'int' return type is used above because that is what
  85. // MultiByteToWideChar returns. However, the returned value is always non-negative.
  86. //
  87. ASSERT(iLen >= 0);
  88. DWORD dwLen = (DWORD) iLen;
  89. if (dwLen == 0)
  90. {
  91. //
  92. // In case MultiByteToWideChar modified the buffer then failed
  93. //
  94. wszIpAddress[0] = L'\0';
  95. return;
  96. }
  97. ASSERT(dwLen < dwBufSize);
  98. }
  99. /*
  100. * Function: GetIPAddressOctets
  101. * Description: Turn an IP Address string into its 4 integer components.
  102. * Author: shouse 7.24.00
  103. */
  104. VOID GetIPAddressOctets (PCWSTR pszIpAddress, DWORD ardw[4]) {
  105. DWORD dwIpAddr = IpAddressFromAbcdWsz(pszIpAddress);
  106. const BYTE * bp = (const BYTE *)&dwIpAddr;
  107. ardw[0] = (DWORD)bp[0];
  108. ardw[1] = (DWORD)bp[1];
  109. ardw[2] = (DWORD)bp[2];
  110. ardw[3] = (DWORD)bp[3];
  111. }
  112. /*
  113. * Function: IsValidIPAddressSubnetMaskPair
  114. * Description: Checks for valid IP address/netmask pairs.
  115. * Author: Copied largely from net/config/netcfg/tcpipcfg/tcperror.cpp
  116. */
  117. BOOL IsValidIPAddressSubnetMaskPair (PCWSTR szIp, PCWSTR szSubnet) {
  118. BOOL fNoError = TRUE;
  119. DWORD dwAddr = IpAddressFromAbcdWsz(szIp);
  120. DWORD dwMask = IpAddressFromAbcdWsz(szSubnet);
  121. if (( (dwMask | dwAddr) == 0xFFFFFFFF) // Is the host ID all 1's ?
  122. || (((~dwMask) & dwAddr) == 0) // Is the host ID all 0's ?
  123. || ( (dwMask & dwAddr) == 0)) // Is the network ID all 0's ?
  124. {
  125. fNoError = FALSE;
  126. return FALSE;
  127. }
  128. DWORD ardwNetID[4];
  129. DWORD ardwHostID[4];
  130. DWORD ardwIp[4];
  131. DWORD ardwMask[4];
  132. GetIPAddressOctets(szIp, ardwIp);
  133. GetIPAddressOctets(szSubnet, ardwMask);
  134. INT nFirstByte = ardwIp[0] & 0xFF;
  135. // setup Net ID
  136. ardwNetID[0] = ardwIp[0] & ardwMask[0] & 0xFF;
  137. ardwNetID[1] = ardwIp[1] & ardwMask[1] & 0xFF;
  138. ardwNetID[2] = ardwIp[2] & ardwMask[2] & 0xFF;
  139. ardwNetID[3] = ardwIp[3] & ardwMask[3] & 0xFF;
  140. // setup Host ID
  141. ardwHostID[0] = ardwIp[0] & (~(ardwMask[0]) & 0xFF);
  142. ardwHostID[1] = ardwIp[1] & (~(ardwMask[1]) & 0xFF);
  143. ardwHostID[2] = ardwIp[2] & (~(ardwMask[2]) & 0xFF);
  144. ardwHostID[3] = ardwIp[3] & (~(ardwMask[3]) & 0xFF);
  145. // check each case
  146. if( ((nFirstByte & 0xF0) == 0xE0) || // Class D
  147. ((nFirstByte & 0xF0) == 0xF0) || // Class E
  148. (ardwNetID[0] == 127) || // NetID cannot be 127...
  149. ((ardwNetID[0] == 0) && // netid cannot be 0.0.0.0
  150. (ardwNetID[1] == 0) &&
  151. (ardwNetID[2] == 0) &&
  152. (ardwNetID[3] == 0)) ||
  153. // netid cannot be equal to sub-net mask
  154. ((ardwNetID[0] == ardwMask[0]) &&
  155. (ardwNetID[1] == ardwMask[1]) &&
  156. (ardwNetID[2] == ardwMask[2]) &&
  157. (ardwNetID[3] == ardwMask[3])) ||
  158. // hostid cannot be 0.0.0.0
  159. ((ardwHostID[0] == 0) &&
  160. (ardwHostID[1] == 0) &&
  161. (ardwHostID[2] == 0) &&
  162. (ardwHostID[3] == 0)) ||
  163. // hostid cannot be 255.255.255.255
  164. ((ardwHostID[0] == 0xFF) &&
  165. (ardwHostID[1] == 0xFF) &&
  166. (ardwHostID[2] == 0xFF) &&
  167. (ardwHostID[3] == 0xFF)) ||
  168. // test for all 255
  169. ((ardwIp[0] == 0xFF) &&
  170. (ardwIp[1] == 0xFF) &&
  171. (ardwIp[2] == 0xFF) &&
  172. (ardwIp[3] == 0xFF)))
  173. {
  174. fNoError = FALSE;
  175. }
  176. return fNoError;
  177. }
  178. /*
  179. * Function: IsContiguousSubnetMask
  180. * Description: Makes sure the netmask is contiguous
  181. * Author: Copied largely from net/config/netcfg/tcpipcfg/tcputil.cpp
  182. */
  183. BOOL IsContiguousSubnetMask (PCWSTR pszSubnet) {
  184. DWORD ardwSubnet[4];
  185. GetIPAddressOctets(pszSubnet, ardwSubnet);
  186. DWORD dwMask = (ardwSubnet[0] << 24) + (ardwSubnet[1] << 16)
  187. + (ardwSubnet[2] << 8) + ardwSubnet[3];
  188. DWORD i, dwContiguousMask;
  189. // Find out where the first '1' is in binary going right to left
  190. dwContiguousMask = 0;
  191. for (i = 0; i < sizeof(dwMask)*8; i++) {
  192. dwContiguousMask |= 1 << i;
  193. if (dwContiguousMask & dwMask)
  194. break;
  195. }
  196. // At this point, dwContiguousMask is 000...0111... If we inverse it,
  197. // we get a mask that can be or'd with dwMask to fill in all of
  198. // the holes.
  199. dwContiguousMask = dwMask | ~dwContiguousMask;
  200. // If the new mask is different, correct it here
  201. if (dwMask != dwContiguousMask)
  202. return FALSE;
  203. else
  204. return TRUE;
  205. }
  206. //+----------------------------------------------------------------------------
  207. //
  208. // Function: ParamsGenerateSubnetMask
  209. //
  210. // Description:
  211. //
  212. // Arguments: PWSTR ip - Input dotted decimal IP address string
  213. // PWSTR sub - Output dotted decimal subnet mask for input IP address
  214. // const DWORD dwMaskBufSize - Size of sub output buffer in characters
  215. //
  216. // Returns: BOOL - TRUE if a subnet mask was generated. FALSE otherwise
  217. //
  218. // History: fengsun Created Header 3/2/00
  219. // chrisdar 07 Mar 2002 - Added buffer size argument and tightened error checking
  220. //
  221. //+----------------------------------------------------------------------------
  222. BOOL ParamsGenerateSubnetMask (PWSTR ip, PWSTR sub, IN const DWORD dwMaskBufSize) {
  223. DWORD b [4];
  224. ASSERT(sub != NULL);
  225. if (dwMaskBufSize < WLBS_MAX_DED_NET_MASK + 1)
  226. {
  227. return FALSE;
  228. }
  229. int iScan = swscanf (ip, L"%d.%d.%d.%d", b, b+1, b+2, b+3);
  230. //
  231. // If we didn't read the first octect of the IP address then we can't generate a subnet mask
  232. //
  233. if (iScan != EOF && iScan > 0)
  234. {
  235. if ((b [0] >= 1) && (b [0] <= 126)) {
  236. b [0] = 255;
  237. b [1] = 0;
  238. b [2] = 0;
  239. b [3] = 0;
  240. } else if ((b [0] >= 128) && (b [0] <= 191)) {
  241. b [0] = 255;
  242. b [1] = 255;
  243. b [2] = 0;
  244. b [3] = 0;
  245. } else if ((b [0] >= 192) && (b [0] <= 223)) {
  246. b [0] = 255;
  247. b [1] = 255;
  248. b [2] = 255;
  249. b [3] = 0;
  250. } else {
  251. b [0] = 0;
  252. b [1] = 0;
  253. b [2] = 0;
  254. b [3] = 0;
  255. }
  256. }
  257. else
  258. {
  259. b [0] = 0;
  260. b [1] = 0;
  261. b [2] = 0;
  262. b [3] = 0;
  263. }
  264. StringCchPrintf(sub, dwMaskBufSize, L"%d.%d.%d.%d",
  265. b [0], b [1], b [2], b [3]);
  266. return((b[0] + b[1] + b[2] + b[3]) > 0);
  267. }
  268. /*
  269. * Function: ParamsGenerateMAC
  270. * Description: Calculate the generated field in the structure
  271. * History: fengsun Created 3.27.00
  272. * shouse Modified 7.12.00
  273. */
  274. //
  275. // TODO: This function needs to be rewritten
  276. // 1. One of the first executable lines is 'if (!fConvertMAC) { return; }. No need to call this function in this case.
  277. // 2. Two buffers are OUT, but all are not touched for every call. This makes the code very fragile. If it is an out
  278. // and the pointer is non-NULL the user should expect this function to at least set the result to "no result", e.g.,
  279. // empty string. But looks like calling code has made assumptions about when these OUTs are modified. The caller has
  280. // too much knowledge of the implementation.
  281. // 3. Calls are made to IpAddressFromAbcdWsz but no check is made to determine if the result is INADDR_NONE.
  282. // 4. I suspect that this code would be much clearer if there were one input string, one output string, a buf size for
  283. // the output string and a enum telling the function how to create the MAC (unicast, multicast or IGMP)
  284. //
  285. // When rewritten, many of the checks within the 'if' branches can then be moved to the top of the function. This will clean
  286. // the code considerably.
  287. //
  288. void ParamsGenerateMAC (const WCHAR * szClusterIP,
  289. OUT WCHAR * szClusterMAC,
  290. IN const DWORD dwMACBufSize,
  291. OUT WCHAR * szMulticastIP,
  292. IN const DWORD dwIPBufSize,
  293. BOOL fConvertMAC,
  294. BOOL fMulticast,
  295. BOOL fIGMP,
  296. BOOL fUseClusterIP) {
  297. DWORD dwIp;
  298. const BYTE * bp;
  299. //
  300. // Isn't this dumb? Why call this function at all if caller passes this flag in as false???
  301. //
  302. if (!fConvertMAC) return;
  303. /* Unicast mode. */
  304. if (!fMulticast) {
  305. ASSERT(szClusterIP != NULL);
  306. ASSERT(szClusterMAC != NULL);
  307. ASSERT(dwMACBufSize > WLBS_MAX_NETWORK_ADDR);
  308. dwIp = IpAddressFromAbcdWsz(szClusterIP);
  309. bp = (const BYTE *)&dwIp;
  310. StringCchPrintf(szClusterMAC, dwMACBufSize, L"02-bf-%02x-%02x-%02x-%02x", bp[0], bp[1], bp[2], bp[3]);
  311. return;
  312. }
  313. /* Multicast without IGMP. */
  314. if (!fIGMP) {
  315. ASSERT(szClusterIP != NULL);
  316. ASSERT(szClusterMAC != NULL);
  317. ASSERT(dwMACBufSize > WLBS_MAX_NETWORK_ADDR);
  318. dwIp = IpAddressFromAbcdWsz(szClusterIP);
  319. bp = (const BYTE *)&dwIp;
  320. StringCchPrintf(szClusterMAC, dwMACBufSize, L"03-bf-%02x-%02x-%02x-%02x", bp[0], bp[1], bp[2], bp[3]);
  321. return;
  322. }
  323. /* Multicast with IGMP. */
  324. if (fUseClusterIP) {
  325. ASSERT(szClusterIP != NULL);
  326. ASSERT(szMulticastIP != NULL);
  327. ASSERT(dwIPBufSize > WLBS_MAX_CL_IP_ADDR);
  328. /* 239.255.x.x */
  329. dwIp = IpAddressFromAbcdWsz(szClusterIP);
  330. dwIp = 239 + (255 << 8) + (dwIp & 0xFFFF0000);
  331. AbcdWszFromIpAddress(dwIp, szMulticastIP, dwIPBufSize);
  332. }
  333. //
  334. // The OUT buffer szMulticastIP is used here as an input. The buffer will be uninitialized if
  335. // fUseClusterIP == FALSE && fIGMP == TRUE && fMulticast == TRUE. That doesn't sound intentional...
  336. // Looks like we shouldn't get here unless fUseClusterIP == TRUE. Perhaps caller is taking care of this
  337. // for us, but this is fragile.
  338. //
  339. ASSERT(szClusterMAC != NULL);
  340. ASSERT(szMulticastIP != NULL);
  341. ASSERT(dwMACBufSize > WLBS_MAX_NETWORK_ADDR);
  342. dwIp = IpAddressFromAbcdWsz(szMulticastIP);
  343. bp = (const BYTE*)&dwIp;
  344. StringCchPrintf(szClusterMAC, dwMACBufSize, L"01-00-5e-%02x-%02x-%02x", (bp[1] & 0x7f), bp[2], bp[3]);
  345. }
  346. //+----------------------------------------------------------------------------
  347. //
  348. // Function: WriteNlbSetupErrorLog
  349. //
  350. // Description: Writes a log message to setuperr.log. Used for logging during
  351. // GUI mode setup.
  352. //
  353. // Arguments: UINT uiIdErrorFormat - string resourse identifier
  354. // <variable length list of variable args>
  355. //
  356. // Returns: None
  357. //
  358. // History: chrisdar Created: 01.06.20
  359. //
  360. //+----------------------------------------------------------------------------
  361. void WriteNlbSetupErrorLog(UINT uiIdErrorFormat, ...)
  362. {
  363. // TRACE_VERB("->%!FUNC! error code string: %ui", uiIdErrorFormat);
  364. PCWSTR pszFormat = SzLoadIds(uiIdErrorFormat);
  365. PWSTR pszText = NULL;
  366. DWORD dwRet;
  367. va_list val;
  368. va_start(val, uiIdErrorFormat);
  369. dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  370. pszFormat, 0, 0, (PWSTR)&pszText, 0, &val);
  371. va_end(val);
  372. if (dwRet && pszText)
  373. {
  374. if (!SetupLogError(pszText, LogSevError))
  375. {
  376. // TRACE_CRIT("%!FUNC! write to setup error log failed with %d", HRESULT_FROM_WIN32(GetLastError()));
  377. }
  378. LocalFree(pszText);
  379. }
  380. else
  381. {
  382. // TRACE_CRIT("%!FUNC! format message failed with %d", HRESULT_FROM_WIN32(GetLastError()));
  383. }
  384. // TRACE_VERB("<-%!FUNC!");
  385. }