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.
 
 
 
 
 
 

1218 lines
22 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
local.c
Abstract:
Domain Name System (DNS) Server -- Admin Client API
DNS Admin API calls that do not use RPC.
Completely executed in client library.
Author:
Jim Gilroy (jamesg) 14-Oct-1995
Environment:
User Mode - Win32
Revision History:
--*/
#include "dnsclip.h"
//
// Debug globals
//
DWORD LocalDebugFlag;
//
// Buffer size for building WKS services string
//
#define WKS_SERVICES_BUFFER_SIZE (0x1000) // 4k
VOID
DNS_API_FUNCTION
DnssrvInitializeDebug(
VOID
)
/*++
Routine Description:
Initialize debugging -- use dnslib debugging.
Only purpose is generic interface that hides file flag
and name info so no need to put in header.
--*/
{
#if DBG
Dns_StartDebug(
0,
DNSRPC_DEBUG_FLAG_FILE,
& LocalDebugFlag,
DNSRPC_DEBUG_FILE_NAME,
1000000 // 1mb wrap
);
DNS_PRINT(( "LocalDebugFlag = %p\n", LocalDebugFlag ));
#endif
}
PVOID
DnssrvMidlAllocZero(
IN DWORD dwSize
)
/*++
Routine Description:
MIDL allocate and zero memory.
Arguments:
Return Value:
Ptr to allocated and zeroed memory.
--*/
{
PVOID ptr;
ptr = MIDL_user_allocate( dwSize );
if ( !ptr )
{
return( NULL );
}
RtlZeroMemory(
ptr,
dwSize );
return( ptr );
}
VOID
DNS_API_FUNCTION
DnssrvFreeRpcBuffer(
IN OUT PDNS_RPC_BUFFER pBuf
)
/*++
Routine Description:
Free generic (no substructures) RPC buffer.
Arguments:
pBuf -- ptr to buf to free
Return Value:
None
--*/
{
if ( !pBuf )
{
return;
}
MIDL_user_free( pBuf );
}
VOID
DNS_API_FUNCTION
DnssrvFreeServerInfo(
IN OUT PDNS_RPC_SERVER_INFO pServerInfo
)
/*++
Routine Description:
Deep free of DNS_SERVER_INFO structure.
Arguments:
pServerInfo -- ptr to server info to free
Return Value:
None
--*/
{
if ( !pServerInfo )
{
return;
}
//
// free allocated items inside the server info blob
//
if ( pServerInfo->pszServerName )
{
MIDL_user_free( pServerInfo->pszServerName );
}
if ( pServerInfo->aipServerAddrs )
{
MIDL_user_free( pServerInfo->aipServerAddrs );
}
if ( pServerInfo->aipListenAddrs )
{
MIDL_user_free( pServerInfo->aipListenAddrs );
}
if ( pServerInfo->aipForwarders )
{
MIDL_user_free( pServerInfo->aipForwarders );
}
if ( pServerInfo->aipLogFilter )
{
MIDL_user_free( pServerInfo->aipLogFilter );
}
if ( pServerInfo->pwszLogFilePath )
{
MIDL_user_free( pServerInfo->pwszLogFilePath );
}
if ( pServerInfo->pszDsContainer )
{
MIDL_user_free( pServerInfo->pszDsContainer );
}
if ( pServerInfo->pszDomainName )
{
MIDL_user_free( pServerInfo->pszDomainName );
}
if ( pServerInfo->pszForestName )
{
MIDL_user_free( pServerInfo->pszForestName );
}
if ( pServerInfo->pszDomainDirectoryPartition )
{
MIDL_user_free( pServerInfo->pszDomainDirectoryPartition );
}
if ( pServerInfo->pszForestDirectoryPartition )
{
MIDL_user_free( pServerInfo->pszForestDirectoryPartition );
}
//
// free DNS_SERVER_INFO struct itself
//
MIDL_user_free( pServerInfo );
}
VOID
DNS_API_FUNCTION
DnssrvFreeZoneInfo(
IN OUT PDNS_RPC_ZONE_INFO pZoneInfo
)
/*++
Routine Description:
Deep free of DNS_ZONE_INFO structure.
Arguments:
pZoneInfo -- ptr to zone info to free
Return Value:
None
--*/
{
if ( !pZoneInfo )
{
return;
}
//
// free substructures
// - name string
// - data file string
// - secondary IP array
// - WINS server array
//
if ( pZoneInfo->pszZoneName )
{
MIDL_user_free( pZoneInfo->pszZoneName );
}
if ( pZoneInfo->pszDataFile )
{
MIDL_user_free( pZoneInfo->pszDataFile );
}
if ( pZoneInfo->aipMasters )
{
MIDL_user_free( pZoneInfo->aipMasters );
}
if ( pZoneInfo->aipSecondaries )
{
MIDL_user_free( pZoneInfo->aipSecondaries );
}
if ( pZoneInfo->pszDpFqdn )
{
MIDL_user_free( pZoneInfo->pszDpFqdn );
}
if ( pZoneInfo->pwszZoneDn )
{
MIDL_user_free( pZoneInfo->pwszZoneDn );
}
//
// free DNS_ZONE_INFO struct itself
//
MIDL_user_free( pZoneInfo );
}
VOID
DNS_API_FUNCTION
DnssrvFreeNode(
IN OUT PDNS_NODE pNode,
IN BOOLEAN fFreeRecords
)
{
if ( pNode->pRecord )
{
Dns_RecordListFree(
pNode->pRecord,
TRUE );
}
if ( pNode->Flags.S.FreeOwner )
{
FREE_HEAP( pNode->pName );
}
FREE_HEAP( pNode );
}
VOID
DNS_API_FUNCTION
DnssrvFreeNodeList(
IN OUT PDNS_NODE pNode,
IN BOOLEAN fFreeRecords
)
{
PDNS_NODE pnext;
// free all nodes in list
while ( pNode )
{
pnext = pNode->pNext;
DnssrvFreeNode(
pNode,
fFreeRecords );
pNode = pnext;
}
}
VOID
DNS_API_FUNCTION
DnssrvFreeZone(
IN OUT PDNS_RPC_ZONE pZone
)
/*++
Routine Description:
Deep free of DNS_RPC_ZONE structure.
Arguments:
pZone -- ptr to zone to free
Return Value:
None
--*/
{
if ( !pZone )
{
return;
}
// free zone name, then zone itself
if ( pZone->pszZoneName )
{
MIDL_user_free( pZone->pszZoneName );
}
if ( pZone->pszDpFqdn )
{
MIDL_user_free( pZone->pszDpFqdn );
}
MIDL_user_free( pZone );
}
VOID
DNS_API_FUNCTION
DnssrvFreeZoneList(
IN OUT PDNS_RPC_ZONE_LIST pZoneList
)
/*++
Routine Description:
Deep free of list of DNS_RPC_ZONE structures.
Arguments:
pZoneList -- ptr RPC_ZONE_LIST structure to free
Return Value:
None
--*/
{
DWORD i;
PDNS_RPC_ZONE pzone;
if ( !pZoneList )
{
return;
}
for( i=0; i< pZoneList->dwZoneCount; i++ )
{
// zone name is only sub-structure
pzone = pZoneList->ZoneArray[i];
MIDL_user_free( pzone->pszZoneName );
MIDL_user_free( pzone );
}
MIDL_user_free( pZoneList );
}
VOID
DNS_API_FUNCTION
DnssrvFreeDirectoryPartitionEnum(
IN OUT PDNS_RPC_DP_ENUM pDp
)
/*++
Routine Description:
Deep free of PDNS_RPC_DP_ENUM structure.
Arguments:
pDp -- ptr to directory partition to free
Return Value:
None
--*/
{
if ( !pDp )
{
return;
}
if ( pDp->pszDpFqdn )
{
MIDL_user_free( pDp->pszDpFqdn );
}
MIDL_user_free( pDp );
}
VOID
DNS_API_FUNCTION
DnssrvFreeDirectoryPartitionInfo(
IN OUT PDNS_RPC_DP_INFO pDp
)
/*++
Routine Description:
Deep free of PDNS_RPC_DP_INFO structure.
Arguments:
pDp -- ptr to directory partition to free
Return Value:
None
--*/
{
DWORD i;
if ( !pDp )
{
return;
}
if ( pDp->pszDpFqdn )
{
MIDL_user_free( pDp->pszDpFqdn );
}
if ( pDp->pszDpDn )
{
MIDL_user_free( pDp->pszDpDn );
}
if ( pDp->pszCrDn )
{
MIDL_user_free( pDp->pszCrDn );
}
for( i = 0; i < pDp->dwReplicaCount; i++ )
{
PDNS_RPC_DP_REPLICA p = pDp->ReplicaArray[ i ];
if ( p )
{
if ( p->pszReplicaDn )
{
MIDL_user_free( p->pszReplicaDn );
}
MIDL_user_free( p );
}
}
MIDL_user_free( pDp );
}
VOID
DNS_API_FUNCTION
DnssrvFreeDirectoryPartitionList(
IN OUT PDNS_RPC_DP_LIST pDpList
)
/*++
Routine Description:
Deep free of list of PDNS_RPC_DP_LIST structures.
Arguments:
pZoneList -- ptr PDNS_RPC_DP_LIST structure to free
Return Value:
None
--*/
{
DWORD i;
PDNS_RPC_DP_ENUM pDp;
if ( !pDpList )
{
return;
}
for( i=0; i < pDpList->dwDpCount; ++i )
{
pDp = pDpList->DpArray[ i ];
DnssrvFreeDirectoryPartitionEnum( pDp );
}
MIDL_user_free( pDpList );
}
PCHAR
DnssrvGetWksServicesInRecord(
IN PDNS_FLAT_RECORD pRR
)
/*++
Routine Description:
Get list of services in WKS record.
Arguments:
pRR - flat WKS record being written
Return Value:
Ptr to services string, caller MUST free.
NULL on error.
--*/
{
struct servent * pServent;
struct protoent * pProtoent;
INT i;
DWORD length;
USHORT port;
UCHAR bBitmask;
CHAR buffer[ WKS_SERVICES_BUFFER_SIZE ];
PCHAR pch = buffer;
PCHAR pchstart;
PCHAR pchstop;
// protocol
pProtoent = getprotobynumber( (INT) pRR->Data.WKS.chProtocol );
if ( ! pProtoent )
{
DNS_PRINT((
"ERROR: Unable to find protocol %d, writing WKS record.\n",
(INT) pRR->Data.WKS.chProtocol
));
return( NULL );
}
//
// services
//
// find each bit set in bitmask, lookup and write service
// corresponding to that port
//
// note, that since that port zero is the front of port bitmask,
// lowest ports are the highest bits in each byte
//
pchstart = pch;
pchstop = pch + WKS_SERVICES_BUFFER_SIZE;
for ( i = 0;
i < (INT)(pRR->wDataLength - SIZEOF_WKS_FIXED_DATA);
i++ )
{
bBitmask = (UCHAR) pRR->Data.WKS.bBitMask[i];
port = i * 8;
// write service name for each bit set in byte
// - get out as soon byte is empty of ports
// - terminate each name with blank (until last)
while ( bBitmask )
{
if ( bBitmask & 0x80 )
{
pServent = getservbyport(
(INT) htons(port),
pProtoent->p_name );
if ( pServent )
{
INT copyCount = strlen(pServent->s_name);
pch++;
if ( pchstop - pch <= copyCount+1 )
{
return( NULL );
}
RtlCopyMemory(
pch,
pServent->s_name,
copyCount );
pch += copyCount;
*pch = ' ';
}
else
{
DNS_PRINT((
"ERROR: Unable to find service for port %d, "
"writing WKS record.\n",
port
));
pch += sprintf( pch, "%d", port );
}
}
port++; // next service port
bBitmask <<= 1; // shift mask up to read next port
}
}
// NULL terminate services string
// and determine length
*pch++ = 0;
length = (DWORD) (pch - pchstart);
// allocate copy of this string
pch = ALLOCATE_HEAP( length );
if ( !pch )
{
SetLastError( DNS_ERROR_NO_MEMORY );
return( NULL );
}
RtlCopyMemory(
pch,
pchstart,
length );
return( pch );
}
//
// Build LDAP \ DS names for objects
//
//
// Build Unicode LDAP paths
//
#define DN_TEXT(string) (L##string)
LPWSTR
DNS_API_FUNCTION
DnssrvCreateDsNodeName(
IN PDNS_RPC_SERVER_INFO pServerInfo,
IN LPWSTR pszZone,
IN LPWSTR pszNode
)
/*++
Routine Description:
Build node DS name.
Arguments:
pServerInfo -- server info for server
pszZone -- zone name
pszNode -- node name RELATIVE to zone root
Return Value:
Ptr to node's DS name. Caller must free.
NULL on error.
--*/
{
PWCHAR psznodeDN;
DWORD length;
// if not DS integrated, bail
if ( !pServerInfo->pszDsContainer )
{
return( NULL );
}
// special case zone root
if ( !pszNode )
{
pszNode = DN_TEXT("@");
}
// allocate required space
length = sizeof(DN_TEXT("dc=,dc=, "));
length += sizeof(WCHAR) * wcslen( pszNode );
length += sizeof(WCHAR) * wcslen( pszZone );
length += sizeof(WCHAR) * wcslen( (LPWSTR)pServerInfo->pszDsContainer );
psznodeDN = (PWCHAR) ALLOCATE_HEAP( length );
if ( !psznodeDN )
{
return( psznodeDN );
}
// build DN
wcscpy( psznodeDN, DN_TEXT("dc=") );
wcscat( psznodeDN, pszNode );
length = wcslen(psznodeDN);
ASSERT ( length > 3 );
if ( length != 4 && // "dc=." case
psznodeDN[ length - 1 ] == '.' )
{
//
// we have a dot terminated node name, strip it out
//
psznodeDN[ length - 1 ] = '\0';
}
wcscat( psznodeDN, DN_TEXT(",dc=") );
wcscat( psznodeDN, pszZone );
length = wcslen(psznodeDN);
ASSERT ( length > 1 );
if ( 1 != wcslen ( pszZone ) && // zone = "." case
psznodeDN[ length - 1 ] == '.' )
{
//
// we have a dot terminated zone name, strip it out
//
psznodeDN[ length - 1 ] = '\0';
}
wcscat( psznodeDN, DN_TEXT(",") );
wcscat( psznodeDN, (LPWSTR)pServerInfo->pszDsContainer );
DNSDBG( STUB, (
"Node DN built: %s\n",
psznodeDN ));
return( psznodeDN );
}
LPWSTR
DNS_API_FUNCTION
DnssrvCreateDsZoneName(
IN PDNS_RPC_SERVER_INFO pServerInfo,
IN LPWSTR pszZone
)
/*++
Routine Description:
Build zone DS name.
This routine should only be used for legacy zones on W2K servers.
For Whistler+ servers the zone info structure has the zone object DN.
Arguments:
pServerInfo -- server info for server
pszZone -- zone name
Return Value:
Ptr to zone's DS name. Caller must free.
NULL on error.
--*/
{
PWCHAR pszzoneDN;
DWORD length;
// if not DS integrated, bail
if ( !(LPWSTR)pServerInfo->pszDsContainer )
{
return( NULL );
}
// allocate required space
length = sizeof(DN_TEXT("dc=, "));
length += sizeof(WCHAR) * wcslen( pszZone );
length += sizeof(WCHAR) * wcslen( (LPWSTR)pServerInfo->pszDsContainer );
pszzoneDN = (PWCHAR) ALLOCATE_HEAP( length );
if ( !pszzoneDN )
{
return( pszzoneDN );
}
// build DN
wcscpy( pszzoneDN, DN_TEXT("dc=") );
wcscat( pszzoneDN, pszZone );
length = wcslen(pszzoneDN);
ASSERT ( length > 1 );
if ( length != 4 && // "dc=." case
pszzoneDN[ length - 1 ] == '.' )
{
//
// we have a dot terminated zone name, strip it out
//
pszzoneDN[ length - 1 ] = '\0';
}
wcscat( pszzoneDN, DN_TEXT(",") );
wcscat( pszzoneDN, (LPWSTR)pServerInfo->pszDsContainer );
DNSDBG( STUB, (
"Zone DN built: %s\n",
pszzoneDN ));
return( pszzoneDN );
}
LPWSTR
DNS_API_FUNCTION
DnssrvCreateDsServerName(
IN PDNS_RPC_SERVER_INFO pServerInfo
)
/*++
Routine Description:
Build zone DS name.
Arguments:
pServerInfo -- server info for server
Return Value:
Ptr to server's DS name. Caller must free.
NULL on error.
--*/
{
PWCHAR pszserverDN;
DWORD length;
//
// DEVNOTE: need investigation here,
// may just be able to use DNS folder in DS
//
// if not DS integrated, bail
if ( !(LPWSTR)pServerInfo->pszDsContainer )
{
return( NULL );
}
// allocate space
length = sizeof(DN_TEXT(" "));
length += sizeof(WCHAR) * wcslen( (LPWSTR)pServerInfo->pszDsContainer );
pszserverDN = (PWCHAR) ALLOCATE_HEAP( length );
if ( !pszserverDN )
{
return( pszserverDN );
}
// build DN
wcscpy( pszserverDN, (LPWSTR)pServerInfo->pszDsContainer );
DNSDBG( STUB, (
"Server DN built: %s\n",
pszserverDN ));
return( pszserverDN );
}
//
// End local.c
//
#if 0
VOID
convertRpcUnionTypeToUnicode(
IN DWORD dwTypeId,
IN OUT DNS_RPC_UNION pData
)
/*++
Routine Description:
Convert RPC union types to unicode.
Arguments:
Return Value:
None
--*/
{
switch ( dwTypeId )
{
case DNSSRV_TYPEID_LPSTR:
pwideString = DnsStringCopyAllocateEx(
pData.String,
0,
FALSE, // UTF8 in
TRUE // Unicode out
);
if ( !pwideString )
{
ASSERT( FALSE );
return;
}
MIDL_user_free( pData.String );
pData.String = (LPSTR) pwideString;
case DNSSRV_TYPEID_SERVER_INFO:
DnsPrint_RpcServerInfo(
PrintRoutine,
pszHeader,
(PDNS_RPC_SERVER_INFO) pData );
break;
case DNSSRV_TYPEID_ZONE:
DnsPrint_RpcZone(
PrintRoutine,
pszHeader,
(PDNS_RPC_ZONE) pData );
break;
case DNSSRV_TYPEID_ZONE_INFO:
DnsPrint_RpcZoneInfo(
PrintRoutine,
pszHeader,
(PDNS_RPC_ZONE_INFO) pData );
break;
case DNSSRV_TYPEID_ZONE_DBASE_INFO:
PrintRoutine(
"%sZone Dbase Info:\n"
"\tDS Integrated = %d\n"
"\tFile Name = %s\n",
pszHeader,
((PDNS_RPC_ZONE_DBASE_INFO)pData)->fDsIntegrated,
((PDNS_RPC_ZONE_DBASE_INFO)pData)->pszFileName );
break;
}
VOID
convertStringToUnicodeInPlace(
IN LPSTR * ppszString
)
/*++
Routine Description:
Convert string to unicode and return it to its current
position in structure.
Arguments:
Return Value:
None
--*/
{
switch ( dwTypeId )
{
case DNSSRV_TYPEID_LPSTR:
pwideString = Dns_StringCopyAllocateEx(
pData.String,
0,
FALSE, // UTF8 in
TRUE // Unicode out
);
if ( !pwideString )
{
ASSERT( FALSE );
return;
}
MIDL_user_free( pData.String );
pData.String = (LPSTR) pwideString;
case DNSSRV_TYPEID_SERVER_INFO:
DnsPrint_RpcServerInfo(
PrintRoutine,
pszHeader,
(PDNS_RPC_SERVER_INFO) pData );
break;
case DNSSRV_TYPEID_STATS:
DnsPrint_RpcStatistics(
PrintRoutine,
pszHeader,
(PDNS_RPC_STATISTICS) pData );
break;
case DNSSRV_TYPEID_ZONE:
DnsPrint_RpcZone(
PrintRoutine,
pszHeader,
(PDNS_RPC_ZONE) pData );
break;
case DNSSRV_TYPEID_FORWARDERS:
DnsPrint_RpcIpArrayPlusParameters(
PrintRoutine,
pszHeader,
"Forwarders Info:",
"Slave",
((PDNS_RPC_FORWARDERS)pData)->fSlave,
"Timeout",
((PDNS_RPC_FORWARDERS)pData)->dwForwardTimeout,
"\tForwarders:\n",
((PDNS_RPC_FORWARDERS)pData)->aipForwarders );
break;
case DNSSRV_TYPEID_ZONE_INFO:
DnsPrint_RpcZoneInfo(
PrintRoutine,
pszHeader,
(PDNS_RPC_ZONE_INFO) pData );
break;
case DNSSRV_TYPEID_ZONE_SECONDARIES:
DnsPrint_RpcIpArrayPlusParameters(
PrintRoutine,
pszHeader,
"Zone Secondary Info:",
"Secure Secondaries",
((PDNS_RPC_ZONE_SECONDARIES)pData)->fSecureSecondaries,
NULL,
0,
"\tSecondaries:\n",
((PDNS_RPC_ZONE_SECONDARIES)pData)->aipSecondaries );
break;
case DNSSRV_TYPEID_ZONE_TYPE_RESET:
DnsPrint_RpcIpArrayPlusParameters(
PrintRoutine,
pszHeader,
"Zone Type Reset Info:",
"ZoneType",
((PDNS_RPC_ZONE_TYPE_RESET)pData)->dwZoneType,
NULL,
0,
"\tMasters:\n",
((PDNS_RPC_ZONE_TYPE_RESET)pData)->aipMasters );
break;
case DNSSRV_TYPEID_ZONE_DBASE_INFO:
PrintRoutine(
"%sZone Dbase Info:\n"
"\tDS Integrated = %d\n"
"\tFile Name = %s\n",
pszHeader,
((PDNS_RPC_ZONE_DBASE_INFO)pData)->fDsIntegrated,
((PDNS_RPC_ZONE_DBASE_INFO)pData)->pszFileName );
break;
default:
PrintRoutine(
"%s\n"
"WARNING: Unknown RPC structure typeid = %d at %p\n",
dwTypeId,
pData );
break;
}
}
#endif
PDNSSRV_STAT
DNS_API_FUNCTION
DnssrvFindStatisticsInBuffer(
IN PDNS_RPC_BUFFER pBuffer,
IN DWORD StatId
)
/*++
Routine Description:
Finds desired statistics in stats buffer.
Arguments:
pStatsBuf -- stats buffer
StatId -- ID of desired stats
Return Value:
Ptr to desired stats in buffer.
--*/
{
PDNSSRV_STAT pstat;
PCHAR pch;
PCHAR pchstop;
pch = pBuffer->Buffer;
pchstop = pch + pBuffer->dwLength;
//
// check all stat blobs within buffer
//
while ( pch < pchstop )
{
pstat = (PDNSSRV_STAT) pch;
pch = (PCHAR) GET_NEXT_STAT_IN_BUFFER( pstat );
if ( pch > pchstop )
{
DNS_PRINT(( "ERROR: invalid stats buffer\n" ));
break;
}
// found matching stats
// - verify correct length
// - return
if ( pstat->Header.StatId == StatId )
{
if ( DnssrvValidityCheckStatistic(pstat) != ERROR_SUCCESS )
{
DNS_PRINT(( "WARNING: Mismatched stats length.\n" ));
break;
}
return( pstat );
}
}
return( NULL );
}