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.

587 lines
18 KiB

  1. #include "precomp.h"
  2. #include <strsafe.h>
  3. #include <locale.h>
  4. #include "wlbsutil.h"
  5. #include "wlbsconfig.h"
  6. #include "debug.h"
  7. #define MAXIPSTRLEN 20
  8. //+----------------------------------------------------------------------------
  9. //
  10. // Function: IpAddressFromAbcdWsz
  11. //
  12. // Synopsis:Converts caller's a.b.c.d IP address string to a network byte order IP
  13. // address. 0 if formatted incorrectly.
  14. //
  15. // Arguments: IN const WCHAR* wszIpAddress - ip address in a.b.c.d unicode string
  16. //
  17. // Returns: DWORD - IPAddr, return INADDR_NONE on failure
  18. //
  19. // History: fengsun Created Header 12/8/98
  20. //
  21. //+----------------------------------------------------------------------------
  22. DWORD WINAPI IpAddressFromAbcdWsz(IN const WCHAR* wszIpAddress)
  23. {
  24. CHAR szIpAddress[MAXIPSTRLEN + 1];
  25. DWORD nboIpAddr;
  26. ASSERT(lstrlen(wszIpAddress) < MAXIPSTRLEN);
  27. WideCharToMultiByte(CP_ACP, 0, wszIpAddress, -1,
  28. szIpAddress, sizeof(szIpAddress), NULL, NULL);
  29. nboIpAddr = inet_addr(szIpAddress);
  30. return(nboIpAddr);
  31. }
  32. //+----------------------------------------------------------------------------
  33. //
  34. // Function: IpAddressToAbcdWsz
  35. //
  36. // Synopsis:
  37. // Converts IpAddr to a string in the a.b.c.d form and returns same in
  38. // caller's wszIpAddress buffer.
  39. //
  40. // The caller MUST provider a buffer that is at least MAXIPSTRLEN + 1 WCHAR long.
  41. //
  42. // Arguments: IPAddr IpAddress -
  43. // OUT WCHAR* wszIpAddress - buffer at least MAXIPSTRLEN
  44. // IN const DWORD dwBufSize - size of wszIpAddress buffer in WCHARs
  45. //
  46. // Returns: void
  47. //
  48. // History: fengsun Created Header 12/21/98
  49. // chrisdar 07-Mar-2002 - Added argument for the size of the output buffer
  50. //
  51. //+----------------------------------------------------------------------------
  52. VOID
  53. WINAPI AbcdWszFromIpAddress(
  54. IN DWORD IpAddress,
  55. OUT WCHAR* wszIpAddress,
  56. IN const DWORD dwBufSize)
  57. {
  58. ASSERT(wszIpAddress);
  59. if (dwBufSize == 0)
  60. {
  61. return;
  62. }
  63. wszIpAddress[0] = L'\0';
  64. LPSTR AnsiAddressString = inet_ntoa( *(struct in_addr *)&IpAddress );
  65. ASSERT(AnsiAddressString);
  66. if (AnsiAddressString == NULL)
  67. {
  68. return ;
  69. }
  70. int iLen = MultiByteToWideChar(CP_ACP, 0, AnsiAddressString, -1 ,
  71. wszIpAddress, dwBufSize);
  72. //
  73. // There are three states that MultiByteToWideChar can return:
  74. // 1) iLen == 0 This means the call failed
  75. // 2) iLen > 0 when dwBufSize > 0 This means the call succeeded
  76. // 3) iLen > 0 when dwBufSize == 0 This means the call succeeded, but only to inform the caller of
  77. // the required size of the out buffer in wide chars. The buffer is not modified.
  78. // This last case is prevented from occuring above by an early return if dwBufSize == 0.
  79. //
  80. // Note also that an 'int' return type is used above because that is what
  81. // MultiByteToWideChar returns. However, the returned value is always non-negative.
  82. //
  83. ASSERT(iLen >= 0);
  84. DWORD dwLen = (DWORD) iLen;
  85. if (dwLen == 0)
  86. {
  87. //
  88. // In case MultiByteToWideChar modified the buffer then failed
  89. //
  90. wszIpAddress[0] = L'\0';
  91. return;
  92. }
  93. ASSERT(dwLen < dwBufSize);
  94. }
  95. /*
  96. * Function: GetIPAddressOctets
  97. * Description: Turn an IP Address string into its 4 integer components.
  98. * Author: shouse 7.24.00
  99. */
  100. VOID GetIPAddressOctets (PCWSTR pszIpAddress, DWORD ardw[4]) {
  101. DWORD dwIpAddr = IpAddressFromAbcdWsz(pszIpAddress);
  102. const BYTE * bp = (const BYTE *)&dwIpAddr;
  103. ardw[0] = (DWORD)bp[0];
  104. ardw[1] = (DWORD)bp[1];
  105. ardw[2] = (DWORD)bp[2];
  106. ardw[3] = (DWORD)bp[3];
  107. }
  108. /*
  109. * Function: IsValidIPAddressSubnetMaskPair
  110. * Description: Checks for valid IP address/netmask pairs.
  111. * Author: Copied largely from net/config/netcfg/tcpipcfg/tcperror.cpp
  112. */
  113. BOOL IsValidMulticastIPAddress (PCWSTR szIp) {
  114. BOOL fNoError = TRUE;
  115. DWORD ardwIp[4];
  116. GetIPAddressOctets(szIp, ardwIp);
  117. if ((ardwIp[0] & 0xF0) != 0xE0)
  118. fNoError = FALSE;
  119. if (((ardwIp[0] & 0xFF) == 0xE0) &&
  120. ((ardwIp[1] & 0xFF) == 0x00) &&
  121. ((ardwIp[2] & 0xFF) == 0x00) &&
  122. ((ardwIp[3] & 0xFF) == 0x00))
  123. fNoError = FALSE;
  124. if (((ardwIp[0] & 0xFF) == 0xE0) &&
  125. ((ardwIp[1] & 0xFF) == 0x00) &&
  126. ((ardwIp[2] & 0xFF) == 0x00) &&
  127. ((ardwIp[3] & 0xFF) == 0x01))
  128. fNoError = FALSE;
  129. return fNoError;
  130. }
  131. /*
  132. * Function: IsValidIPAddressSubnetMaskPair
  133. * Description: Checks for valid IP address/netmask pairs.
  134. * Author: Copied largely from net/config/netcfg/tcpipcfg/tcperror.cpp
  135. */
  136. BOOL IsValidIPAddressSubnetMaskPair (PCWSTR szIp, PCWSTR szSubnet) {
  137. BOOL fNoError = TRUE;
  138. DWORD dwAddr = IpAddressFromAbcdWsz(szIp);
  139. DWORD dwMask = IpAddressFromAbcdWsz(szSubnet);
  140. if (( (dwMask | dwAddr) == 0xFFFFFFFF) // Is the host ID all 1's ?
  141. || (((~dwMask) & dwAddr) == 0) // Is the host ID all 0's ?
  142. || ( (dwMask & dwAddr) == 0)) // Is the network ID all 0's ?
  143. {
  144. fNoError = FALSE;
  145. return FALSE;
  146. }
  147. DWORD ardwNetID[4];
  148. DWORD ardwHostID[4];
  149. DWORD ardwIp[4];
  150. DWORD ardwMask[4];
  151. GetIPAddressOctets(szIp, ardwIp);
  152. GetIPAddressOctets(szSubnet, ardwMask);
  153. INT nFirstByte = ardwIp[0] & 0xFF;
  154. // setup Net ID
  155. ardwNetID[0] = ardwIp[0] & ardwMask[0] & 0xFF;
  156. ardwNetID[1] = ardwIp[1] & ardwMask[1] & 0xFF;
  157. ardwNetID[2] = ardwIp[2] & ardwMask[2] & 0xFF;
  158. ardwNetID[3] = ardwIp[3] & ardwMask[3] & 0xFF;
  159. // setup Host ID
  160. ardwHostID[0] = ardwIp[0] & (~(ardwMask[0]) & 0xFF);
  161. ardwHostID[1] = ardwIp[1] & (~(ardwMask[1]) & 0xFF);
  162. ardwHostID[2] = ardwIp[2] & (~(ardwMask[2]) & 0xFF);
  163. ardwHostID[3] = ardwIp[3] & (~(ardwMask[3]) & 0xFF);
  164. // check each case
  165. if( ((nFirstByte & 0xF0) == 0xE0) || // Class D
  166. ((nFirstByte & 0xF0) == 0xF0) || // Class E
  167. (ardwNetID[0] == 127) || // NetID cannot be 127...
  168. ((ardwNetID[0] == 0) && // netid cannot be 0.0.0.0
  169. (ardwNetID[1] == 0) &&
  170. (ardwNetID[2] == 0) &&
  171. (ardwNetID[3] == 0)) ||
  172. // netid cannot be equal to sub-net mask
  173. ((ardwNetID[0] == ardwMask[0]) &&
  174. (ardwNetID[1] == ardwMask[1]) &&
  175. (ardwNetID[2] == ardwMask[2]) &&
  176. (ardwNetID[3] == ardwMask[3])) ||
  177. // hostid cannot be 0.0.0.0
  178. ((ardwHostID[0] == 0) &&
  179. (ardwHostID[1] == 0) &&
  180. (ardwHostID[2] == 0) &&
  181. (ardwHostID[3] == 0)) ||
  182. // hostid cannot be 255.255.255.255
  183. ((ardwHostID[0] == 0xFF) &&
  184. (ardwHostID[1] == 0xFF) &&
  185. (ardwHostID[2] == 0xFF) &&
  186. (ardwHostID[3] == 0xFF)) ||
  187. // test for all 255
  188. ((ardwIp[0] == 0xFF) &&
  189. (ardwIp[1] == 0xFF) &&
  190. (ardwIp[2] == 0xFF) &&
  191. (ardwIp[3] == 0xFF)))
  192. {
  193. fNoError = FALSE;
  194. }
  195. return fNoError;
  196. }
  197. /*
  198. * Function: IsContiguousSubnetMask
  199. * Description: Makes sure the netmask is contiguous
  200. * Author: Copied largely from net/config/netcfg/tcpipcfg/tcputil.cpp
  201. */
  202. BOOL IsContiguousSubnetMask (PCWSTR pszSubnet) {
  203. DWORD ardwSubnet[4];
  204. GetIPAddressOctets(pszSubnet, ardwSubnet);
  205. DWORD dwMask = (ardwSubnet[0] << 24) + (ardwSubnet[1] << 16)
  206. + (ardwSubnet[2] << 8) + ardwSubnet[3];
  207. DWORD i, dwContiguousMask;
  208. // Find out where the first '1' is in binary going right to left
  209. dwContiguousMask = 0;
  210. for (i = 0; i < sizeof(dwMask)*8; i++) {
  211. dwContiguousMask |= 1 << i;
  212. if (dwContiguousMask & dwMask)
  213. break;
  214. }
  215. // At this point, dwContiguousMask is 000...0111... If we inverse it,
  216. // we get a mask that can be or'd with dwMask to fill in all of
  217. // the holes.
  218. dwContiguousMask = dwMask | ~dwContiguousMask;
  219. // If the new mask is different, correct it here
  220. if (dwMask != dwContiguousMask)
  221. return FALSE;
  222. else
  223. return TRUE;
  224. }
  225. //+----------------------------------------------------------------------------
  226. //
  227. // Function: ParamsGenerateSubnetMask
  228. //
  229. // Description:
  230. //
  231. // Arguments: PWSTR ip - Input dotted decimal IP address string
  232. // PWSTR sub - Output dotted decimal subnet mask for input IP address
  233. // const DWORD dwMaskBufSize - Size of sub output buffer in characters
  234. //
  235. // Returns: BOOL - TRUE if a subnet mask was generated. FALSE otherwise
  236. //
  237. // History: fengsun Created Header 3/2/00
  238. // chrisdar 07 Mar 2002 - Added buffer size argument and tightened error checking
  239. //
  240. //+----------------------------------------------------------------------------
  241. BOOL ParamsGenerateSubnetMask (PWSTR ip, PWSTR sub, IN const DWORD dwMaskBufSize) {
  242. DWORD b [4];
  243. ASSERT(sub != NULL);
  244. if (dwMaskBufSize < WLBS_MAX_DED_NET_MASK + 1)
  245. {
  246. return FALSE;
  247. }
  248. int iScan = swscanf (ip, L"%d.%d.%d.%d", b, b+1, b+2, b+3);
  249. //
  250. // If we didn't read the first octect of the IP address then we can't generate a subnet mask
  251. //
  252. if (iScan != EOF && iScan > 0)
  253. {
  254. if ((b [0] >= 1) && (b [0] <= 126)) {
  255. b [0] = 255;
  256. b [1] = 0;
  257. b [2] = 0;
  258. b [3] = 0;
  259. } else if ((b [0] >= 128) && (b [0] <= 191)) {
  260. b [0] = 255;
  261. b [1] = 255;
  262. b [2] = 0;
  263. b [3] = 0;
  264. } else if ((b [0] >= 192) && (b [0] <= 223)) {
  265. b [0] = 255;
  266. b [1] = 255;
  267. b [2] = 255;
  268. b [3] = 0;
  269. } else {
  270. b [0] = 0;
  271. b [1] = 0;
  272. b [2] = 0;
  273. b [3] = 0;
  274. }
  275. }
  276. else
  277. {
  278. b [0] = 0;
  279. b [1] = 0;
  280. b [2] = 0;
  281. b [3] = 0;
  282. }
  283. StringCchPrintf(sub, dwMaskBufSize, L"%d.%d.%d.%d",
  284. b [0], b [1], b [2], b [3]);
  285. return((b[0] + b[1] + b[2] + b[3]) > 0);
  286. }
  287. /*
  288. * Function: ParamsGenerateMAC
  289. * Description: Calculate the generated field in the structure
  290. * History: fengsun Created 3.27.00
  291. * shouse Modified 7.12.00
  292. */
  293. //
  294. // TODO: This function needs to be rewritten
  295. // 1. One of the first executable lines is 'if (!fConvertMAC) { return; }. No need to call this function in this case.
  296. // 2. Two buffers are OUT, but all are not touched for every call. This makes the code very fragile. If it is an out
  297. // and the pointer is non-NULL the user should expect this function to at least set the result to "no result", e.g.,
  298. // empty string. But looks like calling code has made assumptions about when these OUTs are modified. The caller has
  299. // too much knowledge of the implementation.
  300. // 3. Calls are made to IpAddressFromAbcdWsz but no check is made to determine if the result is INADDR_NONE.
  301. // 4. I suspect that this code would be much clearer if there were one input string, one output string, a buf size for
  302. // the output string and a enum telling the function how to create the MAC (unicast, multicast or IGMP)
  303. //
  304. // When rewritten, many of the checks within the 'if' branches can then be moved to the top of the function. This will clean
  305. // the code considerably.
  306. //
  307. void ParamsGenerateMAC (const WCHAR * szClusterIP,
  308. OUT WCHAR * szClusterMAC,
  309. IN const DWORD dwMACBufSize,
  310. OUT WCHAR * szMulticastIP,
  311. IN const DWORD dwIPBufSize,
  312. BOOL fConvertMAC,
  313. BOOL fMulticast,
  314. BOOL fIGMP,
  315. BOOL fUseClusterIP) {
  316. DWORD dwIp;
  317. const BYTE * bp;
  318. //
  319. // Isn't this dumb? Why call this function at all if caller passes this flag in as false???
  320. //
  321. if (!fConvertMAC) return;
  322. /* Unicast mode. */
  323. if (!fMulticast) {
  324. ASSERT(szClusterIP != NULL);
  325. ASSERT(szClusterMAC != NULL);
  326. ASSERT(dwMACBufSize > WLBS_MAX_NETWORK_ADDR);
  327. dwIp = IpAddressFromAbcdWsz(szClusterIP);
  328. bp = (const BYTE *)&dwIp;
  329. StringCchPrintf(szClusterMAC, dwMACBufSize, L"02-bf-%02x-%02x-%02x-%02x", bp[0], bp[1], bp[2], bp[3]);
  330. return;
  331. }
  332. /* Multicast without IGMP. */
  333. if (!fIGMP) {
  334. ASSERT(szClusterIP != NULL);
  335. ASSERT(szClusterMAC != NULL);
  336. ASSERT(dwMACBufSize > WLBS_MAX_NETWORK_ADDR);
  337. dwIp = IpAddressFromAbcdWsz(szClusterIP);
  338. bp = (const BYTE *)&dwIp;
  339. StringCchPrintf(szClusterMAC, dwMACBufSize, L"03-bf-%02x-%02x-%02x-%02x", bp[0], bp[1], bp[2], bp[3]);
  340. return;
  341. }
  342. /* Multicast with IGMP. */
  343. if (fUseClusterIP) {
  344. ASSERT(szClusterIP != NULL);
  345. ASSERT(szMulticastIP != NULL);
  346. ASSERT(dwIPBufSize > WLBS_MAX_CL_IP_ADDR);
  347. /* 239.255.x.x */
  348. dwIp = IpAddressFromAbcdWsz(szClusterIP);
  349. dwIp = 239 + (255 << 8) + (dwIp & 0xFFFF0000);
  350. AbcdWszFromIpAddress(dwIp, szMulticastIP, dwIPBufSize);
  351. }
  352. //
  353. // The OUT buffer szMulticastIP is used here as an input. The buffer will be uninitialized if
  354. // fUseClusterIP == FALSE && fIGMP == TRUE && fMulticast == TRUE. That doesn't sound intentional...
  355. // Looks like we shouldn't get here unless fUseClusterIP == TRUE. Perhaps caller is taking care of this
  356. // for us, but this is fragile.
  357. //
  358. ASSERT(szClusterMAC != NULL);
  359. ASSERT(szMulticastIP != NULL);
  360. ASSERT(dwMACBufSize > WLBS_MAX_NETWORK_ADDR);
  361. dwIp = IpAddressFromAbcdWsz(szMulticastIP);
  362. bp = (const BYTE*)&dwIp;
  363. StringCchPrintf(szClusterMAC, dwMACBufSize, L"01-00-5e-%02x-%02x-%02x", (bp[1] & 0x7f), bp[2], bp[3]);
  364. }
  365. VOID
  366. InitUserLocale()
  367. {
  368. HMODULE h = GetModuleHandle(L"kernel32.dll");
  369. if(h != NULL)
  370. {
  371. typedef LANGID (WINAPI * PSET_THREAD_UI_LANGUAGE)(WORD);
  372. PSET_THREAD_UI_LANGUAGE pfSetThreadUILanguage = (PSET_THREAD_UI_LANGUAGE) GetProcAddress(h, "SetThreadUILanguage");
  373. if(pfSetThreadUILanguage != NULL)
  374. {
  375. pfSetThreadUILanguage(0);
  376. }
  377. }
  378. _wsetlocale(LC_ALL, L".OCP");
  379. }
  380. /* Largely copied from ipconfig code : net\tcpip\commands\ipconfig\display.c */
  381. VOID
  382. FormatTheTime(SYSTEMTIME *pSysTime, WCHAR *TimeStr, int TimeStrLen)
  383. {
  384. int Count;
  385. TimeStr[0] = 0;
  386. Count = GetDateFormat(LOCALE_USER_DEFAULT,
  387. DATE_SHORTDATE,
  388. pSysTime,
  389. NULL,
  390. TimeStr,
  391. TimeStrLen);
  392. if ((Count == 0) || (Count == TimeStrLen))
  393. return;
  394. TimeStr += Count-1;
  395. TimeStrLen -= Count;
  396. *TimeStr++ = L' ';
  397. Count = GetTimeFormat(LOCALE_USER_DEFAULT,
  398. 0,
  399. pSysTime,
  400. NULL,
  401. TimeStr,
  402. TimeStrLen);
  403. // If GetTimeFormat failed, overwrite the ' ' with
  404. // 0 to null terminate the string
  405. if (Count == 0)
  406. {
  407. *--TimeStr = 0;
  408. }
  409. return;
  410. }
  411. VOID
  412. ConvertTimeToSystemTime(IN time_t Ttime, OUT WCHAR *TimeStr, IN int TimeStrLen)
  413. {
  414. SYSTEMTIME SysTime;
  415. struct tm *pTM;
  416. TimeStr[0] = 0;
  417. _tzset();
  418. pTM = localtime(&Ttime);
  419. if (pTM == NULL)
  420. return;
  421. SysTime.wYear = (WORD)(pTM->tm_year + 1900);
  422. SysTime.wMonth = (WORD)(pTM->tm_mon + 1);
  423. SysTime.wDayOfWeek = (WORD)(pTM->tm_wday);
  424. SysTime.wDay = (WORD)(pTM->tm_mday);
  425. SysTime.wHour = (WORD)(pTM->tm_hour);
  426. SysTime.wMinute = (WORD)(pTM->tm_min);
  427. SysTime.wSecond = (WORD)(pTM->tm_sec);
  428. SysTime.wMilliseconds = 0;
  429. FormatTheTime(&SysTime, TimeStr, TimeStrLen);
  430. return;
  431. }
  432. //+----------------------------------------------------------------------------
  433. //
  434. // Function: ConvertTimeToTimeAndDateStrings
  435. //
  436. // Description: Uses the specified locale to build strings for time-of-day and
  437. // date (short format)
  438. //
  439. // Arguments: time_t Ttime - IN time to be converted
  440. // WCHAR *TimeOfDayStr - OUT buffer for the time-of-day string
  441. // int TimeOfDayStrLen - IN size of time-of-day buffer in characters
  442. // WCHAR *DateStr - OUT buffer for the date string
  443. // int DateStrLen - IN size of date buffer in characters
  444. //
  445. // Returns: VOID
  446. //
  447. // History: chrisdar 25 Jul 2002
  448. //
  449. //+----------------------------------------------------------------------------
  450. VOID
  451. ConvertTimeToTimeAndDateStrings(IN time_t Ttime, OUT WCHAR *TimeOfDayStr, IN int TimeOfDayStrLen, OUT WCHAR *DateStr, IN int DateStrLen)
  452. {
  453. SYSTEMTIME SysTime;
  454. struct tm *pTM;
  455. //
  456. // We assume that this function will not be used to determine the size of buffer required to store these strings...
  457. //
  458. ASSERT(DateStrLen > 0);
  459. ASSERT(TimeOfDayStrLen > 0);
  460. //
  461. // ...and that the user passed us a buffer we can populate
  462. //
  463. ASSERT(DateStr != NULL);
  464. ASSERT(TimeOfDayStr != NULL);
  465. _tzset();
  466. pTM = localtime(&Ttime);
  467. if (pTM == NULL)
  468. return;
  469. SysTime.wYear = (WORD)(pTM->tm_year + 1900);
  470. SysTime.wMonth = (WORD)(pTM->tm_mon + 1);
  471. SysTime.wDayOfWeek = (WORD)(pTM->tm_wday);
  472. SysTime.wDay = (WORD)(pTM->tm_mday);
  473. SysTime.wHour = (WORD)(pTM->tm_hour);
  474. SysTime.wMinute = (WORD)(pTM->tm_min);
  475. SysTime.wSecond = (WORD)(pTM->tm_sec);
  476. SysTime.wMilliseconds = 0;
  477. *TimeOfDayStr = 0; // In case GetDateFormat fails. Assuming GetDateFormat doesn't touch the output buffer if the call fails.
  478. GetTimeFormat(LOCALE_USER_DEFAULT,
  479. 0,
  480. &SysTime,
  481. NULL,
  482. TimeOfDayStr,
  483. TimeOfDayStrLen);
  484. *DateStr = 0; // In case GetDateFormat fails. Assuming GetDateFormat doesn't touch the output buffer if the call fails.
  485. GetDateFormat(LOCALE_USER_DEFAULT,
  486. DATE_SHORTDATE,
  487. &SysTime,
  488. NULL,
  489. DateStr,
  490. DateStrLen);
  491. return;
  492. }