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

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: dnsutil.cpp
//
//--------------------------------------------------------------------------
#include "preDNSsn.h"
#include <SnapBase.h>
#include "resource.h"
#include "dnsutil.h"
#include "uiutil.h"
#ifdef DEBUG_ALLOCATOR
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif
// formatting of IPv4 address to string
LPCWSTR g_szIpStringFmt = TEXT("%d.%d.%d.%d");
#ifdef NTRAID_628931
// Wide character version of DNS_ZONE_ROOT_HINTS
CString g_zoneRootHints(L"");
HRESULT GetWideCharZoneRootHints(CString& zoneRootHints)
{
HRESULT hr = S_OK;
// Initialize the wide char version if it has
// not already been initialized.
if (g_zoneRootHints == L"")
{
// Determine how long wide string needs to be.
int wideLength = MultiByteToWideChar(
CP_ACP,
0,
DNS_ZONE_ROOT_HINTS,
-1, // Let MBtoWC() determine length.
NULL,
0);
LPWSTR lpszZoneRootHints = new WCHAR[wideLength];
if (lpszZoneRootHints)
{
// Convert ascii to wide string.
int convertedLength = MultiByteToWideChar(
CP_ACP,
0,
DNS_ZONE_ROOT_HINTS,
-1,
lpszZoneRootHints,
wideLength);
// Should never happen.
if (convertedLength != wideLength)
{
hr = E_FAIL;
ASSERT(false);
}
g_zoneRootHints = lpszZoneRootHints;
}
else
{
hr = E_OUTOFMEMORY;
}
delete [] lpszZoneRootHints;
}
if (SUCCEEDED(hr))
{
zoneRootHints = g_zoneRootHints;
}
return hr;
}
#endif //NTRAID_628931
///////////////////////////////////////////////////////////////
// General Purpose Utility Functions
BYTE HexCharToByte(WCHAR ch)
{
if (ch >= TEXT('0') && ch <= TEXT('9'))
return static_cast<BYTE>(ch-TEXT('0'));
else if (ch >= TEXT('A') && ch <= TEXT('F'))
return static_cast<BYTE>(ch-TEXT('A') + 10);
else if (ch >= TEXT('a') && ch <= TEXT('f'))
return static_cast<BYTE>(ch-TEXT('a') + 10);
else
return static_cast<BYTE>(0xFF); // marks out of range, expect 0x00 to 0x0f
}
void ReverseString(LPWSTR p, LPWSTR q)
{
WCHAR c;
while (p < q)
{
c = *p;
*p = *q;
*q = c;
p++; q--;
}
}
int ReverseIPString(LPWSTR lpsz)
{
if (!lpsz)
return 0;
// reverse the whole string
size_t nLen = wcslen(lpsz);
ReverseString(lpsz, lpsz+(nLen-1));
// reverse each octect
WCHAR *p,*q1,*q2;
p = q1 = q2 = lpsz;
int nOctects = 0;
while (TRUE)
{
if ( (*p == '.') || (*p == '\0') && (p >lpsz) )
{
q1 = p-1; // point to the digit before the dot
ReverseString(q2,q1);
nOctects++;
q2 = p+1; // for next loop, set trailing pointer
}
if (!*p)
break;
p++;
}
return nOctects;
}
BOOL IsValidIPString(LPCWSTR lpsz)
{
return IPStringToAddr(lpsz) != INADDR_NONE;
}
DWORD IPStringToAddr(LPCWSTR lpsz)
{
USES_CONVERSION;
DWORD dw = inet_addr(W2A(lpsz));
return dw;
}
/*
#define MAX_OCTECT_DIGITS (3) // IPv4 only
BOOL IsValidIPString(LPCWSTR lpsz)
{
if (!lpsz)
return FALSE; // null
int nLen = wcslen(lpsz);
if (nLen <= 0)
return FALSE; // empty
if ((lpsz[0] == TEXT('.')) || (lpsz[nLen-1] == TEXT('.')) )
return FALSE; // leading and trailing dots
for (int k=0; k<nLen; k++)
if ((lpsz[k] != TEXT('.')) && !isdigit(lpsz[k]))
return FALSE; // wrong characters
// look for octects and dots
WCHAR *p,*q1,*q2;
p = q1 = q2 = (WCHAR*)lpsz;
while (TRUE)
{
if ( (*p == TEXT('.')) || (*p == TEXT('\0')) && (p >lpsz) )
{
q1 = p-1; // point to the digit before the dot
if ((q1-q2)+1 > MAX_OCTECT_DIGITS)
return FALSE; // too many digits
q2 = p+1; // for next loop, set trailing pointer
}
if (!*p)
break;
p++;
}
return TRUE; // got at the end fine
}
*/
BOOL RemoveInAddrArpaSuffix(LPWSTR lpsz)
{
if (!lpsz)
return FALSE;
// assume NULL terminated string
size_t nSuffixLen = wcslen(INADDR_ARPA_SUFFIX);
size_t nLen = wcslen(lpsz);
// first char in the suffix, if present
WCHAR* p = lpsz + nLen - nSuffixLen;
if ((p < lpsz) || (_wcsicmp(p,INADDR_ARPA_SUFFIX) != 0))
return FALSE; // string too short or not matching suffix
// got the match, trim the suffix
ASSERT(*p == L'.');
*p = NULL;
return TRUE;
}
DNS_STATUS ValidateDnsNameAgainstServerFlags(LPCWSTR lpszName,
DNS_NAME_FORMAT format,
DWORD serverNameChecking)
{
DNS_STATUS errName = ::DnsValidateName_W(lpszName, format);
if (errName == ERROR_INVALID_NAME)
{
//
// Always fail for invalid names
// Invalid names are:
// - Longer than 255 characters
// - contains label longer than 63 characters
// - contains a space
// - contains two or more consecutive dots
// - begins with a dot
// - contains a dot if the name is submitted with format DnsNameHostDomainLabel or DnsNameHostNameLabel
//
return errName;
}
if (errName == DNS_ERROR_INVALID_NAME_CHAR)
{
if (serverNameChecking == DNS_ALLOW_MULTIBYTE_NAMES ||
serverNameChecking == DNS_ALLOW_ALL_NAMES)
{
//
// If server is set to allow UTF8 or all names let it pass
//
return 0;
}
else
{
//
// If server is set to Strict RFC or non-RFC fail
// DNS_ERROR_INVALID_NAME_CHAR will result from the following:
// - Contains any of the following invalid characters: {|}~[\]^':;<=>?@!"#$%`()+/,
// - contains an asterisk (*) unless the asterisk is the first label in the multi-labeled name
// and submitted with format DnsNameWildcard
//
return errName;
}
}
if (errName == DNS_ERROR_NUMERIC_NAME)
{
//
// Always allow numeric names
//
return 0;
}
if (errName == DNS_ERROR_NON_RFC_NAME)
{
if (serverNameChecking == DNS_ALLOW_RFC_NAMES_ONLY)
{
//
// Fail if the server is only allowing strict RFC names
// DNS_ERROR_NON_RFC_NAME will result from the following:
// - Contains at least one extended or Unicode character
// - contains underscore (_) unless the underscore is the first character in a label
// in the name submitted with format set to DnsNameSrvRecord
//
return errName;
}
else
{
//
// Allow the name for any other server settings
//
return 0;
}
}
return errName;
}
BOOL _HasSuffixAtTheEnd(LPCWSTR lpsz, int nLen, LPCWSTR lpszSuffix)
{
if (!lpsz)
return FALSE; // was NULL
// assume NULL terminated string
size_t nSuffixLen = wcslen(lpszSuffix);
// first char in the suffix, if present
WCHAR* p = (WCHAR*)(lpsz + nLen - nSuffixLen);
if (p < lpsz)
return FALSE; // string too short
if (_wcsicmp(p,lpszSuffix) != 0)
return FALSE; // not matching suffix
if (p == lpsz)
return TRUE; // exactly matching
// the suffix can be matching, but as part of a label
if (p[-1] == TEXT('.'))
return TRUE;
return FALSE;
}
BOOL _IsValidDnsFwdLookupZoneName(CString& szName)
{
int nLen = szName.GetLength();
// this is the "." (root zone)
if ( nLen == 1 && (szName[0] == TEXT('.')) )
return TRUE;
// no dots at the beginning of the name
if (szName[0] == TEXT('.'))
return FALSE;
// we can allow only one dot at the end
if ( nLen >=2 && szName[nLen-1] == TEXT('.') && szName[nLen-2] == TEXT('.') )
{
return FALSE;
}
// do not allow repeated dots
for (int k=1; k < nLen; k++)
if ( (szName[k] == TEXT('.')) && (szName[k-1] == TEXT('.')) )
return FALSE;
if (_HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int")) ||
_HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int.")) ||
_HasSuffixAtTheEnd(szName, nLen, _T("arpa")) ||
_HasSuffixAtTheEnd(szName, nLen, _T("arpa.")) ||
_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int")) ||
_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int.")))
return FALSE;
return TRUE;
}
BOOL _IsValidDnsRevLookupZoneName(CString& szName)
{
int nLen = szName.GetLength();
// do not allow dots at the beginning
if (szName[0] == TEXT('.'))
{
return FALSE;
}
// do not allow repeated dots
for (int k=1; k < nLen; k++)
{
if ( (szName[k] == TEXT('.')) && (szName[k-1] == TEXT('.')) )
{
return FALSE;
}
}
if (!_HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int")) &&
!_HasSuffixAtTheEnd(szName, nLen, _T("ipv6.int.")) &&
!_HasSuffixAtTheEnd(szName, nLen, _T("arpa")) &&
!_HasSuffixAtTheEnd(szName, nLen, _T("arpa.")) &&
!_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int")) &&
!_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int.")))
{
return FALSE;
}
// Do not allow our question mark prefix. Should have been removed.
if (szName.Find(QUESTION_MARK_PREFIX) != -1)
{
return FALSE;
}
return TRUE;
}
/*
BOOL _IsValidDnsRevLookupZoneName(CString& szName)
{
int nLen = szName.GetLength();
// do not allow dots at the end or at the beginning
if ( (szName[nLen-1] == TEXT('.')) || (szName[0] == TEXT('.')) )
return FALSE;
// do not allow repeated dots
for (int k=1; k < nLen; k++)
if ( (szName[k] == TEXT('.')) && (szName[k-1] == TEXT('.')) )
return FALSE;
if (!_HasSuffixAtTheEnd(szName, nLen, _T("ip6.int")) &&
!_HasSuffixAtTheEnd(szName, nLen, _T("arpa")))
return FALSE;
return TRUE;
}
*/
BOOL IsValidDnsZoneName(CString& szName, BOOL bFwd)
{
// check for length
int nLen = UTF8StringLen(szName);
if ( (nLen <= 0) || (nLen > MAX_DNS_NAME_LEN))
return FALSE;
// do not allow blanks inside the zone name
if (szName.Find(TEXT(' ')) != -1)
return FALSE;
return bFwd ? _IsValidDnsFwdLookupZoneName(szName) :
_IsValidDnsRevLookupZoneName(szName);
}
///////////////////////////////////////////////////////////////
// helper functions for IPv6 format
void FormatIPv6Addr(CString& szAddr, IPV6_ADDRESS* ipv6Addr)
{
szAddr.Format(_T("%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x"),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[0]),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[1]),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[2]),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[3]),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[4]),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[5]),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[6]),
REVERSE_WORD_BYTES(ipv6Addr->IP6Word[7]) );
}
//////////////////////////////////////////////////////////////////////////////
// CDNSServerInfoEx
extern LPCSTR _DnsServerRegkeyStringArr[] = {
DNS_REGKEY_NO_RECURSION,
DNS_REGKEY_BIND_SECONDARIES,
DNS_REGKEY_STRICT_FILE_PARSING,
DNS_REGKEY_ROUND_ROBIN,
DNS_REGKEY_LOCAL_NET_PRIORITY,
DNS_REGKEY_SECURE_RESPONSES,
};
CDNSServerInfoEx::CDNSServerInfoEx()
{
m_pServInfo = NULL;
m_errServInfo = 0;
}
CDNSServerInfoEx::~CDNSServerInfoEx()
{
FreeInfo();
}
DNS_STATUS CDNSServerInfoEx::Query(LPCTSTR lpszServerName)
{
DNS_RPC_SERVER_INFO* pServerInfo = NULL;
// update original struct
m_errServInfo = ::DnssrvGetServerInfo(lpszServerName, &pServerInfo);
if (m_errServInfo != 0)
{
if (pServerInfo != NULL)
::DnssrvFreeServerInfo(pServerInfo);
return m_errServInfo;
}
ASSERT(pServerInfo != NULL);
FreeInfo();
m_pServInfo = pServerInfo;
// if we succeeded and it is an NT 4.0 server, change the version info
if (m_pServInfo->dwVersion == 0)
{
m_pServInfo->dwVersion = DNS_SRV_VERSION_NT_4;
}
return m_errServInfo;
}
void CDNSServerInfoEx::FreeInfo()
{
if (m_pServInfo != NULL)
{
::DnssrvFreeServerInfo(m_pServInfo);
m_pServInfo = NULL;
}
m_errServInfo = 0;
}
//////////////////////////////////////////////////////////////////////////////
// CDNSZoneInfoEx
CDNSZoneInfoEx::CDNSZoneInfoEx()
{
m_pZoneInfo = NULL;
// m_nAllowsDynamicUpdate = ZONE_UPDATE_OFF;
m_errZoneInfo = 0;
// m_errAllowsDynamicUpdate = 0;
}
CDNSZoneInfoEx::~CDNSZoneInfoEx()
{
FreeInfo();
}
DNS_STATUS CDNSZoneInfoEx::Query(LPCTSTR lpszServerName, LPCTSTR lpszZoneName,
DWORD)
{
USES_CONVERSION;
DNS_RPC_ZONE_INFO* pZoneInfo = NULL;
LPCSTR lpszAnsiZoneName = W_TO_UTF8(lpszZoneName);
// update original struct
m_errZoneInfo = ::DnssrvGetZoneInfo(lpszServerName, lpszAnsiZoneName, &pZoneInfo);
if (m_errZoneInfo != 0)
{
if (pZoneInfo != NULL)
::DnssrvFreeZoneInfo(pZoneInfo);
return m_errZoneInfo;
}
ASSERT(pZoneInfo != NULL);
FreeInfo();
m_pZoneInfo = pZoneInfo;
// if we succeeeded and it is an NT 5.0 server,
// update additional flags not originally in the zone info struct
/*
if (DNS_SRV_MAJOR_VERSION(dwServerVersion) >= DNS_SRV_MAJOR_VERSION_NT_5)
{
DWORD dw;
m_errAllowsDynamicUpdate = ::DnssrvQueryZoneDwordProperty(lpszServerName,
lpszAnsiZoneName,
DNS_REGKEY_ZONE_ALLOW_UPDATE,
&dw);
if (m_errAllowsDynamicUpdate == 0)
m_nAllowsDynamicUpdate = (UINT)dw ;
}
return ((m_errZoneInfo == 0) && (m_errAllowsDynamicUpdate == 0)) ?
0 : (DWORD)-1;
*/
return (m_errZoneInfo == 0) ? 0 : (DWORD)-1;
}
void CDNSZoneInfoEx::FreeInfo()
{
if (m_pZoneInfo != NULL)
{
::DnssrvFreeZoneInfo(m_pZoneInfo);
m_pZoneInfo = NULL;
}
m_errZoneInfo = 0;
// m_errAllowsDynamicUpdate = 0;
}
///////////////////////////////////////////////////////////////////////////////
//////////////////// ERROR MESSAGES HANDLING //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int DNSMessageBox(LPCTSTR lpszText, UINT nType)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CThemeContextActivator activator;
return ::AfxMessageBox(lpszText, nType);
}
int DNSMessageBox(UINT nIDPrompt, UINT nType)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CThemeContextActivator activator;
return ::AfxMessageBox(nIDPrompt, nType);
}
int DNSErrorDialog(DNS_STATUS err, UINT nErrorMsgID)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CThemeContextActivator activator;
CString szMsg;
szMsg.LoadString(nErrorMsgID);
return DNSErrorDialog(err, szMsg);
}
void DNSDisplaySystemError(DWORD dwErr)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
CThemeContextActivator activator;
LPVOID lpMsgBuf = 0;
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwErr,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR) &lpMsgBuf, 0, NULL);
::AfxMessageBox ((LPWSTR) lpMsgBuf, MB_OK | MB_ICONINFORMATION);
// Free the buffer.
LocalFree (lpMsgBuf);
}
int DNSErrorDialog(DNS_STATUS err, LPCTSTR lpszErrorMsg)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CThemeContextActivator activator;
CString s;
CString szError;
if (CDNSErrorInfo::GetErrorString(err,szError))
{
s.Format(_T("%s\n%s"), lpszErrorMsg, (LPCTSTR)szError);
}
else
{
s.Format(_T("%s\n Error 0x%x"), lpszErrorMsg, err);
}
return ::AfxMessageBox(s, MB_OK | MB_ICONERROR);
}
void DNSCreateErrorMessage(DNS_STATUS err, UINT nErrorMsgID, CString& refszMessage)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString szMsg;
szMsg.LoadString(nErrorMsgID);
CString szError;
if (CDNSErrorInfo::GetErrorString(err,szError))
{
refszMessage.Format(_T("%s %s"), szMsg, (LPCTSTR)szError);
}
else
{
refszMessage.Format(_T("%s Error 0x%x"), szMsg, err);
}
}
int DNSConfirmOperation(UINT nMsgID, CTreeNode* p)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString szFmt;
szFmt.LoadString(nMsgID);
CString szConfirmMsg;
szConfirmMsg.Format((LPCWSTR)szFmt, p->GetDisplayName());
return DNSMessageBox(szConfirmMsg, MB_YESNO);
}
BOOL CDNSErrorInfo::GetErrorString(DNS_STATUS err, CString& szError)
{
if (GetErrorStringFromTable(err, szError))
return TRUE;
return GetErrorStringFromWin32(err, szError);
}
BOOL CDNSErrorInfo::GetErrorStringFromWin32(DNS_STATUS err, CString& szError)
{
szError.Empty();
PTSTR ptzSysMsg = NULL;
int nChars = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(PTSTR)&ptzSysMsg, 0, NULL);
if (nChars > 0)
{
szError = ptzSysMsg;
::LocalFree(ptzSysMsg);
}
return (nChars > 0);
}
struct DNS_ERROR_TABLE_ENTRY
{
DNS_STATUS dwErr;
DWORD dwType;
DWORD dwVal;
};
#define ERROR_ENTRY_TYPE_END ((DWORD)0)
#define ERROR_ENTRY_TYPE_STRINGID ((DWORD)1)
#define ERROR_ENTRY_STRINGID(err) { err , ERROR_ENTRY_TYPE_STRINGID , IDS_##err },
#define ERROR_ENTRY_STRINGID_EX(err, id) { err , ERROR_ENTRY_TYPE_STRINGID , id },
#define END_OF_TABLE_ERROR_ENTRY { 0 , ERROR_ENTRY_TYPE_END, NULL}
BOOL CDNSErrorInfo::GetErrorStringFromTable(DNS_STATUS err, CString& szError)
{
static DNS_ERROR_TABLE_ENTRY errorInfo[] =
{
// DNS Specific errors (from WINERROR.H, previously they were in DNS.H)
// Response codes mapped to non-colliding errors
ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_FORMAT_ERROR)
ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_SERVER_FAILURE)
ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NAME_ERROR)
ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NOT_IMPLEMENTED)
ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_REFUSED)
ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NOTAUTH)
ERROR_ENTRY_STRINGID(DNS_ERROR_RCODE_NOTZONE)
// Packet format
ERROR_ENTRY_STRINGID(DNS_INFO_NO_RECORDS)
ERROR_ENTRY_STRINGID(DNS_ERROR_BAD_PACKET)
ERROR_ENTRY_STRINGID(DNS_ERROR_NO_PACKET)
// General API errors
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_NAME)
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_DATA)
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_TYPE)
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_IP_ADDRESS)
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_PROPERTY)
// Zone errors
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_DOES_NOT_EXIST)
ERROR_ENTRY_STRINGID(DNS_ERROR_NO_ZONE_INFO)
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_ZONE_OPERATION)
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_CONFIGURATION_ERROR)
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_HAS_NO_SOA_RECORD)
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_HAS_NO_NS_RECORDS)
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_LOCKED)
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_CREATION_FAILED)
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_ALREADY_EXISTS)
ERROR_ENTRY_STRINGID(DNS_ERROR_AUTOZONE_ALREADY_EXISTS)
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_ZONE_TYPE)
ERROR_ENTRY_STRINGID(DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP)
ERROR_ENTRY_STRINGID(DNS_ERROR_ZONE_NOT_SECONDARY)
ERROR_ENTRY_STRINGID(DNS_ERROR_NEED_SECONDARY_ADDRESSES)
ERROR_ENTRY_STRINGID(DNS_ERROR_WINS_INIT_FAILED)
ERROR_ENTRY_STRINGID(DNS_ERROR_NEED_WINS_SERVERS)
// Datafile errors
ERROR_ENTRY_STRINGID(DNS_ERROR_PRIMARY_REQUIRES_DATAFILE)
ERROR_ENTRY_STRINGID(DNS_ERROR_INVALID_DATAFILE_NAME)
ERROR_ENTRY_STRINGID(DNS_ERROR_DATAFILE_OPEN_FAILURE)
ERROR_ENTRY_STRINGID(DNS_ERROR_FILE_WRITEBACK_FAILED)
ERROR_ENTRY_STRINGID(DNS_ERROR_DATAFILE_PARSING)
// Database errors
ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_DOES_NOT_EXIST)
ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_FORMAT)
ERROR_ENTRY_STRINGID(DNS_ERROR_NODE_CREATION_FAILED)
ERROR_ENTRY_STRINGID(DNS_ERROR_UNKNOWN_RECORD_TYPE)
ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_TIMED_OUT)
ERROR_ENTRY_STRINGID(DNS_ERROR_NAME_NOT_IN_ZONE)
ERROR_ENTRY_STRINGID(DNS_ERROR_CNAME_COLLISION)
ERROR_ENTRY_STRINGID(DNS_ERROR_RECORD_ALREADY_EXISTS)
ERROR_ENTRY_STRINGID(DNS_ERROR_NAME_DOES_NOT_EXIST)
ERROR_ENTRY_STRINGID(DNS_WARNING_PTR_CREATE_FAILED)
ERROR_ENTRY_STRINGID(DNS_WARNING_DOMAIN_UNDELETED)
// Operation errors
ERROR_ENTRY_STRINGID(DNS_INFO_AXFR_COMPLETE)
ERROR_ENTRY_STRINGID(DNS_ERROR_AXFR)
ERROR_ENTRY_STRINGID(DNS_ERROR_DS_UNAVAILABLE)
// Generic errors (from WINERROR.H)
ERROR_ENTRY_STRINGID(RPC_S_SERVER_UNAVAILABLE)
ERROR_ENTRY_STRINGID_EX(RPC_E_ACCESS_DENIED, IDS_ERROR_ACCESS_DENIED)
ERROR_ENTRY_STRINGID_EX(ERROR_ACCESS_DENIED, IDS_ERROR_ACCESS_DENIED)
// DS errors from WINERROR.H
ERROR_ENTRY_STRINGID(DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE)
// end of table
END_OF_TABLE_ERROR_ENTRY
};
DNS_ERROR_TABLE_ENTRY* pEntry = errorInfo;
while (pEntry->dwType != ERROR_ENTRY_TYPE_END)
{
if (pEntry->dwErr == err)
{
if (pEntry->dwType == ERROR_ENTRY_TYPE_STRINGID)
{
return szError.LoadString((UINT)pEntry->dwVal);
}
}
pEntry++;
}
szError.Empty();
return FALSE;
}
//////////////////////////////////////////////////////////////////
// Copied from ds\dns\dnslib\record.c by JeffJon on 4/27/2000
// modified to support WCHAR
//
WCHAR DnsSecurityBase64Mapping[] =
{
L'A', L'B', L'C', L'D', L'E', L'F', L'G', L'H',
L'I', L'J', L'K', L'L', L'M', L'N', L'O', L'P',
L'Q', L'R', L'S', L'T', L'U', L'V', L'W', L'X',
L'Y', L'Z', L'a', L'b', L'c', L'd', L'e', L'f',
L'g', L'h', L'i', L'j', L'k', L'l', L'm', L'n',
L'o', L'p', L'q', L'r', L's', L't', L'u', L'v',
L'w', L'x', L'y', L'z', L'0', L'1', L'2', L'3',
L'4', L'5', L'6', L'7', L'8', L'9', L'+', L'/'
};
WCHAR
Dns_SecurityBase64CharToBits(IN WCHAR wch64)
/*++
Routine Description:
Get value of security base64 character.
Arguments:
ch64 -- character in security base64
Return Value:
Value of character, only low 6-bits are significant, high bits zero.
(-1) if not a base64 character.
--*/
{
// A - Z map to 0 -25
// a - z map to 26-51
// 0 - 9 map to 52-61
// + is 62
// / is 63
// could do a lookup table
// since we can in general complete mapping with an average of three
// comparisons, just encode
if ( wch64 >= L'a' )
{
if ( wch64 <= L'z' )
{
return static_cast<WCHAR>( wch64 - L'a' + 26 );
}
}
else if ( wch64 >= L'A' )
{
if ( wch64 <= L'Z' )
{
return static_cast<WCHAR>( wch64 - L'A' );
}
}
else if ( wch64 >= L'0')
{
if ( wch64 <= L'9' )
{
return static_cast<WCHAR>( wch64 - L'0' + 52 );
}
else if ( wch64 == L'=' )
{
//*pPadCount++;
return static_cast<WCHAR>( 0 );
}
}
else if ( wch64 == L'+' )
{
return static_cast<WCHAR>( 62 );
}
else if ( wch64 == L'/' )
{
return static_cast<WCHAR>( 63 );
}
// all misses fall here
return static_cast<WCHAR>(-1);
}
DNS_STATUS
Dns_SecurityBase64StringToKey(
OUT PBYTE pKey,
OUT PDWORD pKeyLength,
IN PWCHAR pchString,
IN DWORD cchLength
)
/*++
Routine Description:
Write base64 representation of key to buffer.
Arguments:
pchString - base64 string to write
cchLength - length of string
pKey - ptr to key to write
Return Value:
None
--*/
{
DWORD blend = 0;
DWORD index = 0;
UCHAR bits;
PBYTE pkeyStart = pKey;
//
// Mapping is essentially in 24 bit quantums.
// Take 4 characters of string key and convert to 3 bytes of binary key.
//
while ( cchLength-- )
{
bits = static_cast<UCHAR>(Dns_SecurityBase64CharToBits( *pchString++ ));
if ( bits >= 64 )
{
return ERROR_INVALID_PARAMETER;
}
blend <<= 6;
blend |= bits;
index++;
if ( index == 4 )
{
index = 0;
//
// The first byte of key is top 8 bits of the 24 bit quantum.
//
*pKey++ = ( UCHAR ) ( ( blend & 0x00ff0000 ) >> 16 );
if ( cchLength || *( pchString - 1 ) != SECURITY_PAD_CHAR )
{
//
// There is no padding so the next two bytes of key
// are bottom 16 bits of the 24 bit quantum.
//
*pKey++ = ( UCHAR ) ( ( blend & 0x0000ff00 ) >> 8 );
*pKey++ = ( UCHAR ) ( blend & 0x000000ff );
}
else if ( *( pchString - 2 ) != SECURITY_PAD_CHAR )
{
//
// There is one pad character, so we need to get one
// more byte of key out of the 24 bit quantum. Make sure
// that there are no one bits in the bottom 8 bits of the
// quantum.
//
if ( blend & 0x000000ff )
{
return ERROR_INVALID_PARAMETER;
}
*pKey++ = ( UCHAR ) ( ( blend & 0x0000ff00 ) >> 8 );
}
else
{
//
// There are two pad characters. Make sure that there
// are no one bits in the bottom 16 bits of the quantum.
//
if ( blend & 0x0000ffff )
{
return ERROR_INVALID_PARAMETER;
}
}
blend = 0;
}
}
//
// Base64 representation should always be padded out to an even
// multiple of 4 characters.
//
if ( index == 0 )
{
//
// Key length does not include padding.
//
*pKeyLength = ( DWORD ) ( pKey - pkeyStart );
return ERROR_SUCCESS;
}
return ERROR_INVALID_PARAMETER;
}
PWSTR
Dns_SecurityKeyToBase64String(
IN PBYTE pKey,
IN DWORD KeyLength,
OUT PWSTR pchBuffer
)
/*++
Routine Description:
Write base64 representation of key to buffer.
Arguments:
pKey - ptr to key to write
KeyLength - length of key in bytes
pchBuffer - buffer to write to (must be adequate for key length)
Return Value:
Ptr to next byte in buffer after string.
--*/
{
DWORD blend = 0;
DWORD index = 0;
//
// mapping is essentially in 24bit blocks
// read three bytes of key and transform into four 64bit characters
//
while ( KeyLength-- )
{
blend <<= 8;
blend += *pKey++;
index++;
if ( index == 3)
{
*pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00fc0000) >> 18 ];
*pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0003f000) >> 12 ];
*pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00000fc0) >> 6 ];
*pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0000003f) ];
blend = 0;
index = 0;
}
}
//
// key terminates on byte boundary, but not necessarily 24bit block boundary
// shift to fill 24bit block filling with zeros
// if two bytes written
// => write three 6-bits chars and one pad
// if one byte written
// => write two 6-bits chars and two pads
//
if ( index )
{
blend <<= (8 * (3-index));
*pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00fc0000) >> 18 ];
*pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x0003f000) >> 12 ];
if ( index == 2 )
{
*pchBuffer++ = DnsSecurityBase64Mapping[ (blend & 0x00000fc0) >> 6 ];
}
else
{
*pchBuffer++ = SECURITY_PAD_CHAR;
}
*pchBuffer++ = SECURITY_PAD_CHAR;
}
return( pchBuffer );
}
// NOTICE-2002/04/24-artm ntraid#ntbug9-547641
// Unused functions need to be removed. I've left in comments in
// case they are later needed.
//DNS_STATUS Dns_SecurityHexToKey(OUT PBYTE pKey,
// OUT PDWORD pKeyLength,
// IN PWSTR pchString,
// IN DWORD)
//{
// DWORD byteIdx = 0;
// size_t strLength = wcslen(pchString);
// for (UINT idx = 0; idx < strLength; idx++)
// {
// CString szTemp;
// szTemp = pchString[idx++];
// szTemp += pchString[idx];
// int result = swscanf(szTemp, L"%x", &(pKey[byteIdx++]));
// ASSERT(result == 1);
// }
//
// *pKeyLength = byteIdx;
// return ERROR_SUCCESS;
//}
//
//void Dns_SecurityKeyToHexString(IN PBYTE pKey,
// IN DWORD KeyLength,
// OUT CString& strref)
//{
// strref.Empty();
// for (DWORD dwIdx = 0; dwIdx < KeyLength; dwIdx++)
// {
// CString szTemp;
// szTemp = strref;
// strref.Format(L"%s%2.2x", szTemp, pKey[dwIdx]);
// }
//}
void TimetToFileTime( time_t t, LPFILETIME pft )
{
LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
pft->dwLowDateTime = (DWORD) ll;
pft->dwHighDateTime = static_cast<DWORD>(ll >>32);
}
DWORD FileTimeToTimet(FILETIME* pft)
{
LONGLONG ll = 0;
ll = pft->dwHighDateTime;
ll = ll << 32;
ll |= pft->dwLowDateTime;
ll -= 116444736000000000;
ll /= 10000000;
return (DWORD)ll;
}
void ConvertTTLToSystemTime(TIME_ZONE_INFORMATION*,
DWORD dwTTL,
SYSTEMTIME* pSysTime)
{
time_t ttlTime = static_cast<time_t>(dwTTL);
FILETIME ftTime;
memset(&ftTime, 0, sizeof(FILETIME));
TimetToFileTime(ttlTime, &ftTime);
::FileTimeToSystemTime(&ftTime, pSysTime);
}
DWORD ConvertSystemTimeToTTL(SYSTEMTIME* pSysTime)
{
FILETIME ft;
::SystemTimeToFileTime(pSysTime, &ft);
return FileTimeToTimet(&ft);
}
BOOL ConvertTTLToLocalTimeString(const DWORD dwTTL,
CString& strref)
{
SYSTEMTIME sysLTimeStamp, sysUTimeStamp;
BOOL bRes = TRUE;
//
// Convert from seconds since Jan 1, 1970 to SystemTime
//
ConvertTTLToSystemTime(NULL, dwTTL, &sysUTimeStamp);
strref.Empty();
//
// Convert to local SystemTime
//
if (!::SystemTimeToTzSpecificLocalTime(NULL, &sysUTimeStamp, &sysLTimeStamp))
{
return FALSE;
}
//
// Format the string with respect to locale
//
PTSTR ptszDate = NULL;
int cchDate = 0;
//
// Get the date
//
cchDate = GetDateFormat(LOCALE_USER_DEFAULT, 0 ,
&sysLTimeStamp, NULL,
ptszDate, 0);
ptszDate = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
if (ptszDate)
{
if (GetDateFormat(LOCALE_USER_DEFAULT, 0,
&sysLTimeStamp, NULL,
ptszDate, cchDate))
{
strref = ptszDate;
}
else
{
strref = L"";
bRes = FALSE;
}
free(ptszDate);
}
else
{
strref = L"";
bRes = FALSE;
}
PTSTR ptszTime = NULL;
//
// Get the time
//
cchDate = GetTimeFormat(LOCALE_USER_DEFAULT, 0 ,
&sysLTimeStamp, NULL,
ptszTime, 0);
ptszTime = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
if (ptszTime)
{
if (GetTimeFormat(LOCALE_USER_DEFAULT, 0,
&sysLTimeStamp, NULL,
ptszTime, cchDate))
{
strref += _T(" ") + CString(ptszTime);
}
else
{
strref += _T("");
bRes = FALSE;
}
free(ptszTime);
}
else
{
strref += _T("");
bRes = FALSE;
}
return bRes;
}
// Converts a base64 BLOB into a string by using 4 characters to represent
// 3 bytes. Each character is 6bits of the BLOB. If the encoding doesn't
// end on a 3 byte boundary '=' is used as a pad character
CString Base64BLOBToString(PBYTE blob, DWORD blobSizeInBytes)
{
if (!blob ||
!blobSizeInBytes)
{
return L"";
}
// The largest string will have 4 characters for every 3 bytes in the string
// I have to add one more before multiplying just in case there are pad characters
// and another for NULL termination
DWORD stringSize = (((blobSizeInBytes / 3) + 1) * 4) + 1;
WCHAR* szBuffer = new WCHAR[stringSize];
if (!szBuffer)
{
return L"";
}
::ZeroMemory(szBuffer, stringSize * sizeof(WCHAR));
PWSTR pszEnd = Dns_SecurityKeyToBase64String(blob,
blobSizeInBytes,
szBuffer);
if (pszEnd != NULL)
{
//
// NULL terminate the string
//
*pszEnd = L'\0';
}
CString result = szBuffer;
delete[] szBuffer;
return result;
}
CString Base64BLOBToString(CByteBlob& blob)
{
return Base64BLOBToString(blob.GetData(), blob.GetSize());
}