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.

1303 lines
36 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: dnsutil.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "preDNSsn.h"
  11. #include <SnapBase.h>
  12. #include "resource.h"
  13. #include "dnsutil.h"
  14. #include "uiutil.h"
  15. #ifdef DEBUG_ALLOCATOR
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21. #endif
  22. // formatting of IPv4 address to string
  23. LPCWSTR g_szIpStringFmt = TEXT("%d.%d.%d.%d");
  24. #ifdef NTRAID_628931
  25. // Wide character version of DNS_ZONE_ROOT_HINTS
  26. CString g_zoneRootHints(L"");
  27. HRESULT GetWideCharZoneRootHints(CString& zoneRootHints)
  28. {
  29. HRESULT hr = S_OK;
  30. // Initialize the wide char version if it has
  31. // not already been initialized.
  32. if (g_zoneRootHints == L"")
  33. {
  34. // Determine how long wide string needs to be.
  35. int wideLength = MultiByteToWideChar(
  36. CP_ACP,
  37. 0,
  38. DNS_ZONE_ROOT_HINTS,
  39. -1, // Let MBtoWC() determine length.
  40. NULL,
  41. 0);
  42. LPWSTR lpszZoneRootHints = new WCHAR[wideLength];
  43. if (lpszZoneRootHints)
  44. {
  45. // Convert ascii to wide string.
  46. int convertedLength = MultiByteToWideChar(
  47. CP_ACP,
  48. 0,
  49. DNS_ZONE_ROOT_HINTS,
  50. -1,
  51. lpszZoneRootHints,
  52. wideLength);
  53. // Should never happen.
  54. if (convertedLength != wideLength)
  55. {
  56. hr = E_FAIL;
  57. ASSERT(false);
  58. }
  59. g_zoneRootHints = lpszZoneRootHints;
  60. }
  61. else
  62. {
  63. hr = E_OUTOFMEMORY;
  64. }
  65. delete [] lpszZoneRootHints;
  66. }
  67. if (SUCCEEDED(hr))
  68. {
  69. zoneRootHints = g_zoneRootHints;
  70. }
  71. return hr;
  72. }
  73. #endif //NTRAID_628931
  74. ///////////////////////////////////////////////////////////////
  75. // General Purpose Utility Functions
  76. BYTE HexCharToByte(WCHAR ch)
  77. {
  78. if (ch >= TEXT('0') && ch <= TEXT('9'))
  79. return static_cast<BYTE>(ch-TEXT('0'));
  80. else if (ch >= TEXT('A') && ch <= TEXT('F'))
  81. return static_cast<BYTE>(ch-TEXT('A') + 10);
  82. else if (ch >= TEXT('a') && ch <= TEXT('f'))
  83. return static_cast<BYTE>(ch-TEXT('a') + 10);
  84. else
  85. return static_cast<BYTE>(0xFF); // marks out of range, expect 0x00 to 0x0f
  86. }
  87. void ReverseString(LPWSTR p, LPWSTR q)
  88. {
  89. WCHAR c;
  90. while (p < q)
  91. {
  92. c = *p;
  93. *p = *q;
  94. *q = c;
  95. p++; q--;
  96. }
  97. }
  98. int ReverseIPString(LPWSTR lpsz)
  99. {
  100. if (!lpsz)
  101. return 0;
  102. // reverse the whole string
  103. size_t nLen = wcslen(lpsz);
  104. ReverseString(lpsz, lpsz+(nLen-1));
  105. // reverse each octect
  106. WCHAR *p,*q1,*q2;
  107. p = q1 = q2 = lpsz;
  108. int nOctects = 0;
  109. while (TRUE)
  110. {
  111. if ( (*p == '.') || (*p == '\0') && (p >lpsz) )
  112. {
  113. q1 = p-1; // point to the digit before the dot
  114. ReverseString(q2,q1);
  115. nOctects++;
  116. q2 = p+1; // for next loop, set trailing pointer
  117. }
  118. if (!*p)
  119. break;
  120. p++;
  121. }
  122. return nOctects;
  123. }
  124. BOOL IsValidIPString(LPCWSTR lpsz)
  125. {
  126. return IPStringToAddr(lpsz) != INADDR_NONE;
  127. }
  128. DWORD IPStringToAddr(LPCWSTR lpsz)
  129. {
  130. USES_CONVERSION;
  131. DWORD dw = inet_addr(W2A(lpsz));
  132. return dw;
  133. }
  134. /*
  135. #define MAX_OCTECT_DIGITS (3) // IPv4 only
  136. BOOL IsValidIPString(LPCWSTR lpsz)
  137. {
  138. if (!lpsz)
  139. return FALSE; // null
  140. int nLen = wcslen(lpsz);
  141. if (nLen <= 0)
  142. return FALSE; // empty
  143. if ((lpsz[0] == TEXT('.')) || (lpsz[nLen-1] == TEXT('.')) )
  144. return FALSE; // leading and trailing dots
  145. for (int k=0; k<nLen; k++)
  146. if ((lpsz[k] != TEXT('.')) && !isdigit(lpsz[k]))
  147. return FALSE; // wrong characters
  148. // look for octects and dots
  149. WCHAR *p,*q1,*q2;
  150. p = q1 = q2 = (WCHAR*)lpsz;
  151. while (TRUE)
  152. {
  153. if ( (*p == TEXT('.')) || (*p == TEXT('\0')) && (p >lpsz) )
  154. {
  155. q1 = p-1; // point to the digit before the dot
  156. if ((q1-q2)+1 > MAX_OCTECT_DIGITS)
  157. return FALSE; // too many digits
  158. q2 = p+1; // for next loop, set trailing pointer
  159. }
  160. if (!*p)
  161. break;
  162. p++;
  163. }
  164. return TRUE; // got at the end fine
  165. }
  166. */
  167. BOOL RemoveInAddrArpaSuffix(LPWSTR lpsz)
  168. {
  169. if (!lpsz)
  170. return FALSE;
  171. // assume NULL terminated string
  172. size_t nSuffixLen = wcslen(INADDR_ARPA_SUFFIX);
  173. size_t nLen = wcslen(lpsz);
  174. // first char in the suffix, if present
  175. WCHAR* p = lpsz + nLen - nSuffixLen;
  176. if ((p < lpsz) || (_wcsicmp(p,INADDR_ARPA_SUFFIX) != 0))
  177. return FALSE; // string too short or not matching suffix
  178. // got the match, trim the suffix
  179. ASSERT(*p == L'.');
  180. *p = NULL;
  181. return TRUE;
  182. }
  183. DNS_STATUS ValidateDnsNameAgainstServerFlags(LPCWSTR lpszName,
  184. DNS_NAME_FORMAT format,
  185. DWORD serverNameChecking)
  186. {
  187. DNS_STATUS errName = ::DnsValidateName_W(lpszName, format);
  188. if (errName == ERROR_INVALID_NAME)
  189. {
  190. //
  191. // Always fail for invalid names
  192. // Invalid names are:
  193. // - Longer than 255 characters
  194. // - contains label longer than 63 characters
  195. // - contains a space
  196. // - contains two or more consecutive dots
  197. // - begins with a dot
  198. // - contains a dot if the name is submitted with format DnsNameHostDomainLabel or DnsNameHostNameLabel
  199. //
  200. return errName;
  201. }
  202. if (errName == DNS_ERROR_INVALID_NAME_CHAR)
  203. {
  204. if (serverNameChecking == DNS_ALLOW_MULTIBYTE_NAMES ||
  205. serverNameChecking == DNS_ALLOW_ALL_NAMES)
  206. {
  207. //
  208. // If server is set to allow UTF8 or all names let it pass
  209. //
  210. return 0;
  211. }
  212. else
  213. {
  214. //
  215. // If server is set to Strict RFC or non-RFC fail
  216. // DNS_ERROR_INVALID_NAME_CHAR will result from the following:
  217. // - Contains any of the following invalid characters: {|}~[\]^':;<=>?@!"#$%`()+/,
  218. // - contains an asterisk (*) unless the asterisk is the first label in the multi-labeled name
  219. // and submitted with format DnsNameWildcard
  220. //
  221. return errName;
  222. }
  223. }
  224. if (errName == DNS_ERROR_NUMERIC_NAME)
  225. {
  226. //
  227. // Always allow numeric names
  228. //
  229. return 0;
  230. }
  231. if (errName == DNS_ERROR_NON_RFC_NAME)
  232. {
  233. if (serverNameChecking == DNS_ALLOW_RFC_NAMES_ONLY)
  234. {
  235. //
  236. // Fail if the server is only allowing strict RFC names
  237. // DNS_ERROR_NON_RFC_NAME will result from the following:
  238. // - Contains at least one extended or Unicode character
  239. // - contains underscore (_) unless the underscore is the first character in a label
  240. // in the name submitted with format set to DnsNameSrvRecord
  241. //
  242. return errName;
  243. }
  244. else
  245. {
  246. //
  247. // Allow the name for any other server settings
  248. //
  249. return 0;
  250. }
  251. }
  252. return errName;
  253. }
  254. BOOL _HasSuffixAtTheEnd(LPCWSTR lpsz, int nLen, LPCWSTR lpszSuffix)
  255. {
  256. if (!lpsz)
  257. return FALSE; // was NULL
  258. // assume NULL terminated string
  259. size_t nSuffixLen = wcslen(lpszSuffix);
  260. // first char in the suffix, if present
  261. WCHAR* p = (WCHAR*)(lpsz + nLen - nSuffixLen);
  262. if (p < lpsz)
  263. return FALSE; // string too short
  264. if (_wcsicmp(p,lpszSuffix) != 0)
  265. return FALSE; // not matching suffix
  266. if (p == lpsz)
  267. return TRUE; // exactly matching
  268. // the suffix can be matching, but as part of a label
  269. if (p[-1] == TEXT('.'))
  270. return TRUE;
  271. return FALSE;
  272. }
  273. BOOL _IsValidDnsFwdLookupZoneName(CString& szName)
  274. {
  275. int nLen = szName.GetLength();
  276. // this is the "." (root zone)
  277. if ( nLen == 1 && (szName[0] == TEXT('.')) )
  278. return TRUE;
  279. // no dots at the beginning of the name
  280. if (szName[0] == TEXT('.'))
  281. return FALSE;
  282. // we can allow only one dot at the end
  283. if ( nLen >=2 && szName[nLen-1] == TEXT('.') && szName[nLen-2] == TEXT('.') )
  284. {
  285. return FALSE;
  286. }
  287. // do not allow repeated dots
  288. for (int k=1; k < nLen; k++)
  289. if ( (szName[k] == TEXT('.')) && (szName[k-1] == TEXT('.')) )
  290. return FALSE;
  291. if (_HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int")) ||
  292. _HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int.")) ||
  293. _HasSuffixAtTheEnd(szName, nLen, _T("arpa")) ||
  294. _HasSuffixAtTheEnd(szName, nLen, _T("arpa.")) ||
  295. _HasSuffixAtTheEnd(szName, nLen, _T("ip6.int")) ||
  296. _HasSuffixAtTheEnd(szName, nLen, _T("ip6.int.")))
  297. return FALSE;
  298. return TRUE;
  299. }
  300. BOOL _IsValidDnsRevLookupZoneName(CString& szName)
  301. {
  302. int nLen = szName.GetLength();
  303. // do not allow dots at the beginning
  304. if (szName[0] == TEXT('.'))
  305. {
  306. return FALSE;
  307. }
  308. // do not allow repeated dots
  309. for (int k=1; k < nLen; k++)
  310. {
  311. if ( (szName[k] == TEXT('.')) && (szName[k-1] == TEXT('.')) )
  312. {
  313. return FALSE;
  314. }
  315. }
  316. if (!_HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int")) &&
  317. !_HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int.")) &&
  318. !_HasSuffixAtTheEnd(szName, nLen, _T("arpa")) &&
  319. !_HasSuffixAtTheEnd(szName, nLen, _T("arpa.")) &&
  320. !_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int")) &&
  321. !_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int.")))
  322. {
  323. return FALSE;
  324. }
  325. // Do not allow our question mark prefix. Should have been removed.
  326. if (szName.Find(QUESTION_MARK_PREFIX) != -1)
  327. {
  328. return FALSE;
  329. }
  330. return TRUE;
  331. }
  332. /*
  333. BOOL _IsValidDnsRevLookupZoneName(CString& szName)
  334. {
  335. int nLen = szName.GetLength();
  336. // do not allow dots at the end or at the beginning
  337. if ( (szName[nLen-1] == TEXT('.')) || (szName[0] == TEXT('.')) )
  338. return FALSE;
  339. // do not allow repeated dots
  340. for (int k=1; k < nLen; k++)
  341. if ( (szName[k] == TEXT('.')) && (szName[k-1] == TEXT('.')) )
  342. return FALSE;
  343. if (!_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int")) &&
  344. !_HasSuffixAtTheEnd(szName, nLen, _T("arpa")))
  345. return FALSE;
  346. return TRUE;
  347. }
  348. */
  349. BOOL IsValidDnsZoneName(CString& szName, BOOL bFwd)
  350. {
  351. // check for length
  352. int nLen = UTF8StringLen(szName);
  353. if ( (nLen <= 0) || (nLen > MAX_DNS_NAME_LEN))
  354. return FALSE;
  355. // do not allow blanks inside the zone name
  356. if (szName.Find(TEXT(' ')) != -1)
  357. return FALSE;
  358. return bFwd ? _IsValidDnsFwdLookupZoneName(szName) :
  359. _IsValidDnsRevLookupZoneName(szName);
  360. }
  361. ///////////////////////////////////////////////////////////////
  362. // helper functions for IPv6 format
  363. void FormatIPv6Addr(CString& szAddr, IPV6_ADDRESS* ipv6Addr)
  364. {
  365. szAddr.Format(_T("%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x"),
  366. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[0]),
  367. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[1]),
  368. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[2]),
  369. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[3]),
  370. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[4]),
  371. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[5]),
  372. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[6]),
  373. REVERSE_WORD_BYTES(ipv6Addr->IP6Word[7]) );
  374. }
  375. //////////////////////////////////////////////////////////////////////////////
  376. // CDNSServerInfoEx
  377. extern LPCSTR _DnsServerRegkeyStringArr[] = {
  378. DNS_REGKEY_NO_RECURSION,
  379. DNS_REGKEY_BIND_SECONDARIES,
  380. DNS_REGKEY_STRICT_FILE_PARSING,
  381. DNS_REGKEY_ROUND_ROBIN,
  382. DNS_REGKEY_LOCAL_NET_PRIORITY,
  383. DNS_REGKEY_SECURE_RESPONSES,
  384. };
  385. CDNSServerInfoEx::CDNSServerInfoEx()
  386. {
  387. m_pServInfo = NULL;
  388. m_errServInfo = 0;
  389. }
  390. CDNSServerInfoEx::~CDNSServerInfoEx()
  391. {
  392. FreeInfo();
  393. }
  394. DNS_STATUS CDNSServerInfoEx::Query(LPCTSTR lpszServerName)
  395. {
  396. DNS_RPC_SERVER_INFO* pServerInfo = NULL;
  397. // update original struct
  398. m_errServInfo = ::DnssrvGetServerInfo(lpszServerName, &pServerInfo);
  399. if (m_errServInfo != 0)
  400. {
  401. if (pServerInfo != NULL)
  402. ::DnssrvFreeServerInfo(pServerInfo);
  403. return m_errServInfo;
  404. }
  405. ASSERT(pServerInfo != NULL);
  406. FreeInfo();
  407. m_pServInfo = pServerInfo;
  408. // if we succeeded and it is an NT 4.0 server, change the version info
  409. if (m_pServInfo->dwVersion == 0)
  410. {
  411. m_pServInfo->dwVersion = DNS_SRV_VERSION_NT_4;
  412. }
  413. return m_errServInfo;
  414. }
  415. void CDNSServerInfoEx::FreeInfo()
  416. {
  417. if (m_pServInfo != NULL)
  418. {
  419. ::DnssrvFreeServerInfo(m_pServInfo);
  420. m_pServInfo = NULL;
  421. }
  422. m_errServInfo = 0;
  423. }
  424. //////////////////////////////////////////////////////////////////////////////
  425. // CDNSZoneInfoEx
  426. CDNSZoneInfoEx::CDNSZoneInfoEx()
  427. {
  428. m_pZoneInfo = NULL;
  429. // m_nAllowsDynamicUpdate = ZONE_UPDATE_OFF;
  430. m_errZoneInfo = 0;
  431. // m_errAllowsDynamicUpdate = 0;
  432. }
  433. CDNSZoneInfoEx::~CDNSZoneInfoEx()
  434. {
  435. FreeInfo();
  436. }
  437. DNS_STATUS CDNSZoneInfoEx::Query(LPCTSTR lpszServerName, LPCTSTR lpszZoneName,
  438. DWORD)
  439. {
  440. USES_CONVERSION;
  441. DNS_RPC_ZONE_INFO* pZoneInfo = NULL;
  442. LPCSTR lpszAnsiZoneName = W_TO_UTF8(lpszZoneName);
  443. // update original struct
  444. m_errZoneInfo = ::DnssrvGetZoneInfo(lpszServerName, lpszAnsiZoneName, &pZoneInfo);
  445. if (m_errZoneInfo != 0)
  446. {
  447. if (pZoneInfo != NULL)
  448. ::DnssrvFreeZoneInfo(pZoneInfo);
  449. return m_errZoneInfo;
  450. }
  451. ASSERT(pZoneInfo != NULL);
  452. FreeInfo();
  453. m_pZoneInfo = pZoneInfo;
  454. // if we succeeeded and it is an NT 5.0 server,
  455. // update additional flags not originally in the zone info struct
  456. /*
  457. if (DNS_SRV_MAJOR_VERSION(dwServerVersion) >= DNS_SRV_MAJOR_VERSION_NT_5)
  458. {
  459. DWORD dw;
  460. m_errAllowsDynamicUpdate = ::DnssrvQueryZoneDwordProperty(lpszServerName,
  461. lpszAnsiZoneName,
  462. DNS_REGKEY_ZONE_ALLOW_UPDATE,
  463. &dw);
  464. if (m_errAllowsDynamicUpdate == 0)
  465. m_nAllowsDynamicUpdate = (UINT)dw ;
  466. }
  467. return ((m_errZoneInfo == 0) && (m_errAllowsDynamicUpdate == 0)) ?
  468. 0 : (DWORD)-1;
  469. */
  470. return (m_errZoneInfo == 0) ? 0 : (DWORD)-1;
  471. }
  472. void CDNSZoneInfoEx::FreeInfo()
  473. {
  474. if (m_pZoneInfo != NULL)
  475. {
  476. ::DnssrvFreeZoneInfo(m_pZoneInfo);
  477. m_pZoneInfo = NULL;
  478. }
  479. m_errZoneInfo = 0;
  480. // m_errAllowsDynamicUpdate = 0;
  481. }
  482. ///////////////////////////////////////////////////////////////////////////////
  483. //////////////////// ERROR MESSAGES HANDLING //////////////////////////////////
  484. ///////////////////////////////////////////////////////////////////////////////
  485. int DNSMessageBox(LPCTSTR lpszText, UINT nType)
  486. {
  487. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  488. CThemeContextActivator activator;
  489. return ::AfxMessageBox(lpszText, nType);
  490. }
  491. int DNSMessageBox(UINT nIDPrompt, UINT nType)
  492. {
  493. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  494. CThemeContextActivator activator;
  495. return ::AfxMessageBox(nIDPrompt, nType);
  496. }
  497. int DNSErrorDialog(DNS_STATUS err, UINT nErrorMsgID)
  498. {
  499. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  500. CThemeContextActivator activator;
  501. CString szMsg;
  502. szMsg.LoadString(nErrorMsgID);
  503. return DNSErrorDialog(err, szMsg);
  504. }
  505. void DNSDisplaySystemError(DWORD dwErr)
  506. {
  507. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  508. CThemeContextActivator activator;
  509. LPVOID lpMsgBuf = 0;
  510. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  511. NULL,
  512. dwErr,
  513. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  514. (LPWSTR) &lpMsgBuf, 0, NULL);
  515. ::AfxMessageBox ((LPWSTR) lpMsgBuf, MB_OK | MB_ICONINFORMATION);
  516. // Free the buffer.
  517. LocalFree (lpMsgBuf);
  518. }
  519. int DNSErrorDialog(DNS_STATUS err, LPCTSTR lpszErrorMsg)
  520. {
  521. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  522. CThemeContextActivator activator;
  523. CString s;
  524. CString szError;
  525. if (CDNSErrorInfo::GetErrorString(err,szError))
  526. {
  527. s.Format(_T("%s\n%s"), lpszErrorMsg, (LPCTSTR)szError);
  528. }
  529. else
  530. {
  531. s.Format(_T("%s\n Error 0x%x"), lpszErrorMsg, err);
  532. }
  533. return ::AfxMessageBox(s, MB_OK | MB_ICONERROR);
  534. }
  535. void DNSCreateErrorMessage(DNS_STATUS err, UINT nErrorMsgID, CString& refszMessage)
  536. {
  537. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  538. CString szMsg;
  539. szMsg.LoadString(nErrorMsgID);
  540. CString szError;
  541. if (CDNSErrorInfo::GetErrorString(err,szError))
  542. {
  543. refszMessage.Format(_T("%s %s"), szMsg, (LPCTSTR)szError);
  544. }
  545. else
  546. {
  547. refszMessage.Format(_T("%s Error 0x%x"), szMsg, err);
  548. }
  549. }
  550. int DNSConfirmOperation(UINT nMsgID, CTreeNode* p)
  551. {
  552. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  553. CString szFmt;
  554. szFmt.LoadString(nMsgID);
  555. CString szConfirmMsg;
  556. szConfirmMsg.Format((LPCWSTR)szFmt, p->GetDisplayName());
  557. return DNSMessageBox(szConfirmMsg, MB_YESNO);
  558. }
  559. BOOL CDNSErrorInfo::GetErrorString(DNS_STATUS err, CString& szError)
  560. {
  561. if (GetErrorStringFromTable(err, szError))
  562. return TRUE;
  563. return GetErrorStringFromWin32(err, szError);
  564. }
  565. BOOL CDNSErrorInfo::GetErrorStringFromWin32(DNS_STATUS err, CString& szError)
  566. {
  567. szError.Empty();
  568. PTSTR ptzSysMsg = NULL;
  569. int nChars = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  570. | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
  571. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  572. (PTSTR)&ptzSysMsg, 0, NULL);
  573. if (nChars > 0)
  574. {
  575. szError = ptzSysMsg;
  576. ::LocalFree(ptzSysMsg);
  577. }
  578. return (nChars > 0);
  579. }
  580. struct DNS_ERROR_TABLE_ENTRY
  581. {
  582. DNS_STATUS dwErr;
  583. DWORD dwType;
  584. DWORD dwVal;
  585. };
  586. #define ERROR_ENTRY_TYPE_END ((DWORD)0)
  587. #define ERROR_ENTRY_TYPE_STRINGID ((DWORD)1)
  588. #define ERROR_ENTRY_STRINGID(err) { err , ERROR_ENTRY_TYPE_STRINGID , IDS_##err },
  589. #define ERROR_ENTRY_STRINGID_EX(err, id) { err , ERROR_ENTRY_TYPE_STRINGID , id },
  590. #define END_OF_TABLE_ERROR_ENTRY { 0 , ERROR_ENTRY_TYPE_END, NULL}
  591. BOOL CDNSErrorInfo::GetErrorStringFromTable(DNS_STATUS err, CString& szError)
  592. {
  593. static DNS_ERROR_TABLE_ENTRY errorInfo[] =
  594. {
  595. // DNS Specific errors (from WINERROR.H, previously they were in DNS.H)
  596. // Response codes mapped to non-colliding errors
  597. ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_FORMAT_ERROR)
  598. ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_SERVER_FAILURE)
  599. ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NAME_ERROR)
  600. ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NOT_IMPLEMENTED)
  601. ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_REFUSED)
  602. ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NOTAUTH)
  603. ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NOTZONE)
  604. // Packet format
  605. ERROR_ENTRY_STRINGID(DNS_INFO_NO_RECORDS)
  606. ERROR_ENTRY_STRINGID(DNS_ERROR_BAD_PACKET)
  607. ERROR_ENTRY_STRINGID(DNS_ERROR_NO_PACKET)
  608. // General API errors
  609. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_NAME)
  610. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_DATA)
  611. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_TYPE)
  612. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_IP_ADDRESS)
  613. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_PROPERTY)
  614. // Zone errors
  615. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_DOES_NOT_EXIST)
  616. ERROR_ENTRY_STRINGID(DNS_ERROR_NO_ZONE_INFO)
  617. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_ZONE_OPERATION)
  618. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_CONFIGURATION_ERROR)
  619. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_HAS_NO_SOA_RECORD)
  620. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_HAS_NO_NS_RECORDS)
  621. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_LOCKED)
  622. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_CREATION_FAILED)
  623. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_ALREADY_EXISTS)
  624. ERROR_ENTRY_STRINGID(DNS_ERROR_AUTOZONE_ALREADY_EXISTS)
  625. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_ZONE_TYPE)
  626. ERROR_ENTRY_STRINGID(DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP)
  627. ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_NOT_SECONDARY)
  628. ERROR_ENTRY_STRINGID(DNS_ERROR_NEED_SECONDARY_ADDRESSES)
  629. ERROR_ENTRY_STRINGID(DNS_ERROR_WINS_INIT_FAILED)
  630. ERROR_ENTRY_STRINGID(DNS_ERROR_NEED_WINS_SERVERS)
  631. // Datafile errors
  632. ERROR_ENTRY_STRINGID(DNS_ERROR_PRIMARY_REQUIRES_DATAFILE)
  633. ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_DATAFILE_NAME)
  634. ERROR_ENTRY_STRINGID(DNS_ERROR_DATAFILE_OPEN_FAILURE)
  635. ERROR_ENTRY_STRINGID(DNS_ERROR_FILE_WRITEBACK_FAILED)
  636. ERROR_ENTRY_STRINGID(DNS_ERROR_DATAFILE_PARSING)
  637. // Database errors
  638. ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_DOES_NOT_EXIST)
  639. ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_FORMAT)
  640. ERROR_ENTRY_STRINGID(DNS_ERROR_NODE_CREATION_FAILED)
  641. ERROR_ENTRY_STRINGID(DNS_ERROR_UNKNOWN_RECORD_TYPE)
  642. ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_TIMED_OUT)
  643. ERROR_ENTRY_STRINGID(DNS_ERROR_NAME_NOT_IN_ZONE)
  644. ERROR_ENTRY_STRINGID(DNS_ERROR_CNAME_COLLISION)
  645. ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_ALREADY_EXISTS)
  646. ERROR_ENTRY_STRINGID(DNS_ERROR_NAME_DOES_NOT_EXIST)
  647. ERROR_ENTRY_STRINGID(DNS_WARNING_PTR_CREATE_FAILED)
  648. ERROR_ENTRY_STRINGID(DNS_WARNING_DOMAIN_UNDELETED)
  649. // Operation errors
  650. ERROR_ENTRY_STRINGID(DNS_INFO_AXFR_COMPLETE)
  651. ERROR_ENTRY_STRINGID(DNS_ERROR_AXFR)
  652. ERROR_ENTRY_STRINGID(DNS_ERROR_DS_UNAVAILABLE)
  653. // Generic errors (from WINERROR.H)
  654. ERROR_ENTRY_STRINGID(RPC_S_SERVER_UNAVAILABLE)
  655. ERROR_ENTRY_STRINGID_EX(RPC_E_ACCESS_DENIED, IDS_ERROR_ACCESS_DENIED)
  656. ERROR_ENTRY_STRINGID_EX(ERROR_ACCESS_DENIED, IDS_ERROR_ACCESS_DENIED)
  657. // DS errors from WINERROR.H
  658. ERROR_ENTRY_STRINGID(DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE)
  659. // end of table
  660. END_OF_TABLE_ERROR_ENTRY
  661. };
  662. DNS_ERROR_TABLE_ENTRY* pEntry = errorInfo;
  663. while (pEntry->dwType != ERROR_ENTRY_TYPE_END)
  664. {
  665. if (pEntry->dwErr == err)
  666. {
  667. if (pEntry->dwType == ERROR_ENTRY_TYPE_STRINGID)
  668. {
  669. return szError.LoadString((UINT)pEntry->dwVal);
  670. }
  671. }
  672. pEntry++;
  673. }
  674. szError.Empty();
  675. return FALSE;
  676. }
  677. //////////////////////////////////////////////////////////////////
  678. // Copied from ds\dns\dnslib\record.c by JeffJon on 4/27/2000
  679. // modified to support WCHAR
  680. //
  681. WCHAR DnsSecurityBase64Mapping[] =
  682. {
  683. L'A', L'B', L'C', L'D', L'E', L'F', L'G', L'H',
  684. L'I', L'J', L'K', L'L', L'M', L'N', L'O', L'P',
  685. L'Q', L'R', L'S', L'T', L'U', L'V', L'W', L'X',
  686. L'Y', L'Z', L'a', L'b', L'c', L'd', L'e', L'f',
  687. L'g', L'h', L'i', L'j', L'k', L'l', L'm', L'n',
  688. L'o', L'p', L'q', L'r', L's', L't', L'u', L'v',
  689. L'w', L'x', L'y', L'z', L'0', L'1', L'2', L'3',
  690. L'4', L'5', L'6', L'7', L'8', L'9', L'+', L'/'
  691. };
  692. WCHAR
  693. Dns_SecurityBase64CharToBits(IN WCHAR wch64)
  694. /*++
  695. Routine Description:
  696. Get value of security base64 character.
  697. Arguments:
  698. ch64 -- character in security base64
  699. Return Value:
  700. Value of character, only low 6-bits are significant, high bits zero.
  701. (-1) if not a base64 character.
  702. --*/
  703. {
  704. // A - Z map to 0 -25
  705. // a - z map to 26-51
  706. // 0 - 9 map to 52-61
  707. // + is 62
  708. // / is 63
  709. // could do a lookup table
  710. // since we can in general complete mapping with an average of three
  711. // comparisons, just encode
  712. if ( wch64 >= L'a' )
  713. {
  714. if ( wch64 <= L'z' )
  715. {
  716. return static_cast<WCHAR>( wch64 - L'a' + 26 );
  717. }
  718. }
  719. else if ( wch64 >= L'A' )
  720. {
  721. if ( wch64 <= L'Z' )
  722. {
  723. return static_cast<WCHAR>( wch64 - L'A' );
  724. }
  725. }
  726. else if ( wch64 >= L'0')
  727. {
  728. if ( wch64 <= L'9' )
  729. {
  730. return static_cast<WCHAR>( wch64 - L'0' + 52 );
  731. }
  732. else if ( wch64 == L'=' )
  733. {
  734. //*pPadCount++;
  735. return static_cast<WCHAR>( 0 );
  736. }
  737. }
  738. else if ( wch64 == L'+' )
  739. {
  740. return static_cast<WCHAR>( 62 );
  741. }
  742. else if ( wch64 == L'/' )
  743. {
  744. return static_cast<WCHAR>( 63 );
  745. }
  746. // all misses fall here
  747. return static_cast<WCHAR>(-1);
  748. }
  749. DNS_STATUS
  750. Dns_SecurityBase64StringToKey(
  751. OUT PBYTE pKey,
  752. OUT PDWORD pKeyLength,
  753. IN PWCHAR pchString,
  754. IN DWORD cchLength
  755. )
  756. /*++
  757. Routine Description:
  758. Write base64 representation of key to buffer.
  759. Arguments:
  760. pchString - base64 string to write
  761. cchLength - length of string
  762. pKey - ptr to key to write
  763. Return Value:
  764. None
  765. --*/
  766. {
  767. DWORD blend = 0;
  768. DWORD index = 0;
  769. UCHAR bits;
  770. PBYTE pkeyStart = pKey;
  771. //
  772. // Mapping is essentially in 24 bit quantums.
  773. // Take 4 characters of string key and convert to 3 bytes of binary key.
  774. //
  775. while ( cchLength-- )
  776. {
  777. bits = static_cast<UCHAR>(Dns_SecurityBase64CharToBits( *pchString++ ));
  778. if ( bits >= 64 )
  779. {
  780. return ERROR_INVALID_PARAMETER;
  781. }
  782. blend <<= 6;
  783. blend |= bits;
  784. index++;
  785. if ( index == 4 )
  786. {
  787. index = 0;
  788. //
  789. // The first byte of key is top 8 bits of the 24 bit quantum.
  790. //
  791. *pKey++ = ( UCHAR ) ( ( blend & 0x00ff0000 ) >> 16 );
  792. if ( cchLength || *( pchString - 1 ) != SECURITY_PAD_CHAR )
  793. {
  794. //
  795. // There is no padding so the next two bytes of key
  796. // are bottom 16 bits of the 24 bit quantum.
  797. //
  798. *pKey++ = ( UCHAR ) ( ( blend & 0x0000ff00 ) >> 8 );
  799. *pKey++ = ( UCHAR ) ( blend & 0x000000ff );
  800. }
  801. else if ( *( pchString - 2 ) != SECURITY_PAD_CHAR )
  802. {
  803. //
  804. // There is one pad character, so we need to get one
  805. // more byte of key out of the 24 bit quantum. Make sure
  806. // that there are no one bits in the bottom 8 bits of the
  807. // quantum.
  808. //
  809. if ( blend & 0x000000ff )
  810. {
  811. return ERROR_INVALID_PARAMETER;
  812. }
  813. *pKey++ = ( UCHAR ) ( ( blend & 0x0000ff00 ) >> 8 );
  814. }
  815. else
  816. {
  817. //
  818. // There are two pad characters. Make sure that there
  819. // are no one bits in the bottom 16 bits of the quantum.
  820. //
  821. if ( blend & 0x0000ffff )
  822. {
  823. return ERROR_INVALID_PARAMETER;
  824. }
  825. }
  826. blend = 0;
  827. }
  828. }
  829. //
  830. // Base64 representation should always be padded out to an even
  831. // multiple of 4 characters.
  832. //
  833. if ( index == 0 )
  834. {
  835. //
  836. // Key length does not include padding.
  837. //
  838. *pKeyLength = ( DWORD ) ( pKey - pkeyStart );
  839. return ERROR_SUCCESS;
  840. }
  841. return ERROR_INVALID_PARAMETER;
  842. }
  843. PWSTR
  844. Dns_SecurityKeyToBase64String(
  845. IN PBYTE pKey,
  846. IN DWORD KeyLength,
  847. OUT PWSTR pchBuffer
  848. )
  849. /*++
  850. Routine Description:
  851. Write base64 representation of key to buffer.
  852. Arguments:
  853. pKey - ptr to key to write
  854. KeyLength - length of key in bytes
  855. pchBuffer - buffer to write to (must be adequate for key length)
  856. Return Value:
  857. Ptr to next byte in buffer after string.
  858. --*/
  859. {
  860. DWORD blend = 0;
  861. DWORD index = 0;
  862. //
  863. // mapping is essentially in 24bit blocks
  864. // read three bytes of key and transform into four 64bit characters
  865. //
  866. while ( KeyLength-- )
  867. {
  868. blend <<= 8;
  869. blend += *pKey++;
  870. index++;
  871. if ( index == 3)
  872. {
  873. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00fc0000) >> 18 ];
  874. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0003f000) >> 12 ];
  875. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00000fc0) >> 6 ];
  876. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0000003f) ];
  877. blend = 0;
  878. index = 0;
  879. }
  880. }
  881. //
  882. // key terminates on byte boundary, but not necessarily 24bit block boundary
  883. // shift to fill 24bit block filling with zeros
  884. // if two bytes written
  885. // => write three 6-bits chars and one pad
  886. // if one byte written
  887. // => write two 6-bits chars and two pads
  888. //
  889. if ( index )
  890. {
  891. blend <<= (8 * (3-index));
  892. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00fc0000) >> 18 ];
  893. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0003f000) >> 12 ];
  894. if ( index == 2 )
  895. {
  896. *pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00000fc0) >> 6 ];
  897. }
  898. else
  899. {
  900. *pchBuffer++ = SECURITY_PAD_CHAR;
  901. }
  902. *pchBuffer++ = SECURITY_PAD_CHAR;
  903. }
  904. return( pchBuffer );
  905. }
  906. // NOTICE-2002/04/24-artm ntraid#ntbug9-547641
  907. // Unused functions need to be removed. I've left in comments in
  908. // case they are later needed.
  909. //DNS_STATUS Dns_SecurityHexToKey(OUT PBYTE pKey,
  910. // OUT PDWORD pKeyLength,
  911. // IN PWSTR pchString,
  912. // IN DWORD)
  913. //{
  914. // DWORD byteIdx = 0;
  915. // size_t strLength = wcslen(pchString);
  916. // for (UINT idx = 0; idx < strLength; idx++)
  917. // {
  918. // CString szTemp;
  919. // szTemp = pchString[idx++];
  920. // szTemp += pchString[idx];
  921. // int result = swscanf(szTemp, L"%x", &(pKey[byteIdx++]));
  922. // ASSERT(result == 1);
  923. // }
  924. //
  925. // *pKeyLength = byteIdx;
  926. // return ERROR_SUCCESS;
  927. //}
  928. //
  929. //void Dns_SecurityKeyToHexString(IN PBYTE pKey,
  930. // IN DWORD KeyLength,
  931. // OUT CString& strref)
  932. //{
  933. // strref.Empty();
  934. // for (DWORD dwIdx = 0; dwIdx < KeyLength; dwIdx++)
  935. // {
  936. // CString szTemp;
  937. // szTemp = strref;
  938. // strref.Format(L"%s%2.2x", szTemp, pKey[dwIdx]);
  939. // }
  940. //}
  941. void TimetToFileTime( time_t t, LPFILETIME pft )
  942. {
  943. LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
  944. pft->dwLowDateTime = (DWORD) ll;
  945. pft->dwHighDateTime = static_cast<DWORD>(ll >>32);
  946. }
  947. DWORD FileTimeToTimet(FILETIME* pft)
  948. {
  949. LONGLONG ll = 0;
  950. ll = pft->dwHighDateTime;
  951. ll = ll << 32;
  952. ll |= pft->dwLowDateTime;
  953. ll -= 116444736000000000;
  954. ll /= 10000000;
  955. return (DWORD)ll;
  956. }
  957. void ConvertTTLToSystemTime(TIME_ZONE_INFORMATION*,
  958. DWORD dwTTL,
  959. SYSTEMTIME* pSysTime)
  960. {
  961. time_t ttlTime = static_cast<time_t>(dwTTL);
  962. FILETIME ftTime;
  963. memset(&ftTime, 0, sizeof(FILETIME));
  964. TimetToFileTime(ttlTime, &ftTime);
  965. ::FileTimeToSystemTime(&ftTime, pSysTime);
  966. }
  967. DWORD ConvertSystemTimeToTTL(SYSTEMTIME* pSysTime)
  968. {
  969. FILETIME ft;
  970. ::SystemTimeToFileTime(pSysTime, &ft);
  971. return FileTimeToTimet(&ft);
  972. }
  973. BOOL ConvertTTLToLocalTimeString(const DWORD dwTTL,
  974. CString& strref)
  975. {
  976. SYSTEMTIME sysLTimeStamp, sysUTimeStamp;
  977. BOOL bRes = TRUE;
  978. //
  979. // Convert from seconds since Jan 1, 1970 to SystemTime
  980. //
  981. ConvertTTLToSystemTime(NULL, dwTTL, &sysUTimeStamp);
  982. strref.Empty();
  983. //
  984. // Convert to local SystemTime
  985. //
  986. if (!::SystemTimeToTzSpecificLocalTime(NULL, &sysUTimeStamp, &sysLTimeStamp))
  987. {
  988. return FALSE;
  989. }
  990. //
  991. // Format the string with respect to locale
  992. //
  993. PTSTR ptszDate = NULL;
  994. int cchDate = 0;
  995. //
  996. // Get the date
  997. //
  998. cchDate = GetDateFormat(LOCALE_USER_DEFAULT, 0 ,
  999. &sysLTimeStamp, NULL,
  1000. ptszDate, 0);
  1001. ptszDate = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
  1002. if (ptszDate)
  1003. {
  1004. if (GetDateFormat(LOCALE_USER_DEFAULT, 0,
  1005. &sysLTimeStamp, NULL,
  1006. ptszDate, cchDate))
  1007. {
  1008. strref = ptszDate;
  1009. }
  1010. else
  1011. {
  1012. strref = L"";
  1013. bRes = FALSE;
  1014. }
  1015. free(ptszDate);
  1016. }
  1017. else
  1018. {
  1019. strref = L"";
  1020. bRes = FALSE;
  1021. }
  1022. PTSTR ptszTime = NULL;
  1023. //
  1024. // Get the time
  1025. //
  1026. cchDate = GetTimeFormat(LOCALE_USER_DEFAULT, 0 ,
  1027. &sysLTimeStamp, NULL,
  1028. ptszTime, 0);
  1029. ptszTime = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
  1030. if (ptszTime)
  1031. {
  1032. if (GetTimeFormat(LOCALE_USER_DEFAULT, 0,
  1033. &sysLTimeStamp, NULL,
  1034. ptszTime, cchDate))
  1035. {
  1036. strref += _T(" ") + CString(ptszTime);
  1037. }
  1038. else
  1039. {
  1040. strref += _T("");
  1041. bRes = FALSE;
  1042. }
  1043. free(ptszTime);
  1044. }
  1045. else
  1046. {
  1047. strref += _T("");
  1048. bRes = FALSE;
  1049. }
  1050. return bRes;
  1051. }
  1052. // Converts a base64 BLOB into a string by using 4 characters to represent
  1053. // 3 bytes. Each character is 6bits of the BLOB. If the encoding doesn't
  1054. // end on a 3 byte boundary '=' is used as a pad character
  1055. CString Base64BLOBToString(PBYTE blob, DWORD blobSizeInBytes)
  1056. {
  1057. if (!blob ||
  1058. !blobSizeInBytes)
  1059. {
  1060. return L"";
  1061. }
  1062. // The largest string will have 4 characters for every 3 bytes in the string
  1063. // I have to add one more before multiplying just in case there are pad characters
  1064. // and another for NULL termination
  1065. DWORD stringSize = (((blobSizeInBytes / 3) + 1) * 4) + 1;
  1066. WCHAR* szBuffer = new WCHAR[stringSize];
  1067. if (!szBuffer)
  1068. {
  1069. return L"";
  1070. }
  1071. ::ZeroMemory(szBuffer, stringSize * sizeof(WCHAR));
  1072. PWSTR pszEnd = Dns_SecurityKeyToBase64String(blob,
  1073. blobSizeInBytes,
  1074. szBuffer);
  1075. if (pszEnd != NULL)
  1076. {
  1077. //
  1078. // NULL terminate the string
  1079. //
  1080. *pszEnd = L'\0';
  1081. }
  1082. CString result = szBuffer;
  1083. delete[] szBuffer;
  1084. return result;
  1085. }
  1086. CString Base64BLOBToString(CByteBlob& blob)
  1087. {
  1088. return Base64BLOBToString(blob.GetData(), blob.GetSize());
  1089. }