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.

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