mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
ee0e397d6f
Compiled it on systems with and without LDAP, I hope it does not break the
build farm too badly. If it does, I'll fix it tomorrow.
Volker
(This used to be commit b2ff9680eb
)
600 lines
14 KiB
C
600 lines
14 KiB
C
/*
|
|
Linux DNS client library implementation
|
|
|
|
Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
|
|
Copyright (C) 2006 Gerald Carter <jerry@samba.org>
|
|
|
|
** NOTE! The following LGPL license applies to the libaddns
|
|
** library. This does NOT imply that all of Samba is released
|
|
** under the LGPL
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301 USA
|
|
*/
|
|
|
|
#include "dns.h"
|
|
#include <ctype.h>
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#define STATE_BEGIN 0
|
|
#define STATE_LABEL 1
|
|
#define STATE_FINISH 2
|
|
|
|
#define TOKEN_LABEL 1
|
|
#define TOKEN_SEPARATOR 2
|
|
#define TOKEN_EOS 3
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
static int32 getToken( const char *pszString, char *pszToken, int32 * pdwToken,
|
|
int32 * pdwPosition )
|
|
{
|
|
int32 dwError = 0;
|
|
char c = 0;
|
|
int32 dwToken = 0;
|
|
int32 i = 0;
|
|
int32 dwState = 0;
|
|
int32 dwPosition = 0;
|
|
|
|
dwPosition = *pdwPosition;
|
|
dwState = STATE_BEGIN;
|
|
while ( dwState != STATE_FINISH ) {
|
|
c = pszString[dwPosition];
|
|
if ( c == '\0' ) {
|
|
if ( dwState == STATE_LABEL ) {
|
|
dwToken = TOKEN_LABEL;
|
|
dwState = STATE_FINISH;
|
|
continue;
|
|
} else if ( dwState == STATE_BEGIN ) {
|
|
dwToken = TOKEN_EOS;
|
|
dwState = STATE_FINISH;
|
|
continue;
|
|
}
|
|
} else if ( isalnum( c ) || c == '-' ) {
|
|
pszToken[i++] = c;
|
|
dwPosition++;
|
|
dwState = STATE_LABEL;
|
|
continue;
|
|
} else if ( c == '.' ) {
|
|
if ( dwState == STATE_LABEL ) {
|
|
dwToken = TOKEN_LABEL;
|
|
dwState = STATE_FINISH;
|
|
continue;
|
|
} else if ( dwState == STATE_BEGIN ) {
|
|
dwToken = TOKEN_SEPARATOR;
|
|
dwPosition++;
|
|
dwState = STATE_FINISH;
|
|
continue;
|
|
}
|
|
} else {
|
|
if ( dwState == STATE_LABEL ) {
|
|
dwToken = TOKEN_LABEL;
|
|
dwState = STATE_FINISH;
|
|
} else if ( dwState == 0 ) {
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
dwState = STATE_FINISH;
|
|
}
|
|
}
|
|
}
|
|
*pdwPosition = dwPosition;
|
|
*pdwToken = dwToken;
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
static int32 DNSMakeLabel( char *szLabel, DNS_DOMAIN_LABEL ** ppLabel )
|
|
{
|
|
DNS_DOMAIN_LABEL *pLabel = NULL;
|
|
char *pszLabel = NULL;
|
|
int32 dwError = 0;
|
|
|
|
dwError =
|
|
DNSAllocateMemory( sizeof( DNS_DOMAIN_LABEL ),
|
|
( void * ) &pLabel );
|
|
BAIL_ON_ERROR( dwError );
|
|
|
|
dwError = DNSAllocateString( szLabel, &pszLabel );
|
|
BAIL_ON_ERROR( dwError );
|
|
|
|
pLabel->pszLabel = pszLabel;
|
|
pLabel->dwLength = ( int32 ) strlen( pszLabel );
|
|
*ppLabel = pLabel;
|
|
return dwError;
|
|
|
|
error:
|
|
|
|
if ( pLabel ) {
|
|
DNSFreeMemory( pLabel );
|
|
}
|
|
*ppLabel = NULL;
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
static void DNSFreeLabel( DNS_DOMAIN_LABEL * pLabel )
|
|
{
|
|
if ( pLabel ) {
|
|
DNSFreeMemory( pLabel );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
void DNSFreeLabelList(DNS_DOMAIN_LABEL *pLabelList)
|
|
{
|
|
DNS_DOMAIN_LABEL *pTemp = NULL;
|
|
while(pLabelList) {
|
|
pTemp = pLabelList;
|
|
pLabelList = pLabelList->pNext;
|
|
DNSFreeLabel(pTemp);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
void DNSFreeDomainName(DNS_DOMAIN_NAME *pDomainName)
|
|
{
|
|
DNSFreeLabelList(pDomainName->pLabelList);
|
|
DNSFreeMemory(pDomainName);
|
|
|
|
return;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
static int32 LabelList( const char *pszString, int32 * pdwPosition, DNS_DOMAIN_LABEL ** ppList )
|
|
{
|
|
int32 dwError = 0;
|
|
DNS_DOMAIN_LABEL *pList = NULL;
|
|
DNS_DOMAIN_LABEL *pLabel = NULL;
|
|
int32 dwToken = 0;
|
|
char szToken[64];
|
|
|
|
memset( szToken, 0, 64 );
|
|
dwError = getToken( pszString, szToken, &dwToken, pdwPosition );
|
|
BAIL_ON_ERROR( dwError );
|
|
if ( dwToken != TOKEN_LABEL ) {
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
BAIL_ON_ERROR( dwError );
|
|
}
|
|
|
|
dwError = DNSMakeLabel( szToken, &pLabel );
|
|
BAIL_ON_ERROR( dwError );
|
|
|
|
memset( szToken, 0, 64 );
|
|
dwError = getToken( pszString, szToken, &dwToken, pdwPosition );
|
|
BAIL_ON_ERROR( dwError );
|
|
if ( dwToken == TOKEN_EOS ) {
|
|
*ppList = pLabel;
|
|
return dwError;
|
|
} else if ( dwToken == TOKEN_SEPARATOR ) {
|
|
dwError = LabelList( pszString, pdwPosition, &pList );
|
|
BAIL_ON_ERROR( dwError );
|
|
|
|
pLabel->pNext = pList;
|
|
*ppList = pLabel;
|
|
}
|
|
|
|
return dwError;
|
|
|
|
error:
|
|
if ( pLabel ) {
|
|
DNSFreeLabel( pLabel );
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
static int32 DNSGetDomainNameOffset( uint8 * pBuffer )
|
|
{
|
|
uint8 uLen = 0;
|
|
uint8 uLen1;
|
|
int32 dwOffset = 0;
|
|
|
|
uLen1 = *pBuffer;
|
|
if ( uLen1 & 0xC0 ) {
|
|
dwOffset += 2;
|
|
|
|
} else {
|
|
|
|
while ( 1 ) {
|
|
|
|
uLen = *pBuffer;
|
|
pBuffer++;
|
|
dwOffset++;
|
|
if ( uLen == 0 ) {
|
|
break;
|
|
}
|
|
dwOffset += uLen;
|
|
pBuffer += uLen;
|
|
}
|
|
}
|
|
return ( dwOffset );
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSGenerateIdentifier( int16 * pwIdentifier )
|
|
{
|
|
int32 dwError = 0;
|
|
|
|
*pwIdentifier = random( );
|
|
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSGetDomainNameLength( DNS_DOMAIN_NAME * pDomainName, int32 * pdwLength )
|
|
{
|
|
int32 dwError = 0;
|
|
int32 dwLength = 0;
|
|
DNS_DOMAIN_LABEL *pDomainLabel = NULL;
|
|
|
|
if ( !pDomainName ) {
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
BAIL_ON_ERROR( dwError );
|
|
}
|
|
pDomainLabel = pDomainName->pLabelList;
|
|
|
|
while ( pDomainLabel ) {
|
|
dwLength += pDomainLabel->dwLength;
|
|
dwLength += 1;
|
|
pDomainLabel = pDomainLabel->pNext;
|
|
}
|
|
dwLength += 1;
|
|
*pdwLength = dwLength;
|
|
|
|
return dwError;
|
|
error:
|
|
|
|
*pdwLength = 0;
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSCopyDomainName( uint8 * pBuffer,
|
|
DNS_DOMAIN_NAME * pDomainName, int32 * pdwCopied )
|
|
{
|
|
int32 dwError = 0;
|
|
DNS_DOMAIN_LABEL *pDomainLabel = NULL;
|
|
uint8 uChar = 0;
|
|
int32 dwCopied = 0;
|
|
|
|
if ( !pDomainName ) {
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
BAIL_ON_ERROR( dwError );
|
|
}
|
|
|
|
pDomainLabel = pDomainName->pLabelList;
|
|
while ( pDomainLabel ) {
|
|
uChar = ( uint8 ) pDomainLabel->dwLength;
|
|
memcpy( pBuffer + dwCopied, &uChar, sizeof( uint8 ) );
|
|
dwCopied += sizeof( uint8 );
|
|
memcpy( pBuffer + dwCopied, pDomainLabel->pszLabel,
|
|
pDomainLabel->dwLength );
|
|
dwCopied += pDomainLabel->dwLength;
|
|
pDomainLabel = pDomainLabel->pNext;
|
|
}
|
|
uChar = 0;
|
|
memcpy( pBuffer + dwCopied, &uChar, sizeof( uint8 ) );
|
|
dwCopied += sizeof( uint8 );
|
|
|
|
*pdwCopied = dwCopied;
|
|
return dwError;
|
|
|
|
error:
|
|
*pdwCopied = 0;
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSGenerateKeyName( char **ppszKeyName )
|
|
{
|
|
int32 dwError = 0;
|
|
#if defined(WITH_DNS_UPDATES)
|
|
char *pszKeyName = NULL;
|
|
char szTemp[256];
|
|
char szBuffer[256];
|
|
unsigned char uuid[16];
|
|
|
|
memset( szTemp, 0, 256 );
|
|
memset( szBuffer, 0, 256 );
|
|
memset( uuid, 0, 16 );
|
|
|
|
uuid_generate( uuid );
|
|
|
|
uuid_unparse( uuid, szBuffer );
|
|
|
|
strcpy( szTemp, szBuffer );
|
|
dwError = DNSAllocateString( szTemp, &pszKeyName );
|
|
BAIL_ON_ERROR( dwError );
|
|
|
|
*ppszKeyName = pszKeyName;
|
|
|
|
return dwError;
|
|
|
|
error:
|
|
#endif
|
|
|
|
*ppszKeyName = NULL;
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSDomainNameFromString( const char *pszDomainName,
|
|
DNS_DOMAIN_NAME ** ppDomainName )
|
|
{
|
|
int32 dwError = 0;
|
|
int32 dwPosition = 0;
|
|
DNS_DOMAIN_NAME *pDomainName = NULL;
|
|
DNS_DOMAIN_LABEL *pLabelList = NULL;
|
|
|
|
if ( !pszDomainName || !*pszDomainName ) {
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
return dwError;
|
|
}
|
|
|
|
dwError = LabelList( pszDomainName, &dwPosition, &pLabelList );
|
|
BAIL_ON_ERROR( dwError );
|
|
|
|
dwError =
|
|
DNSAllocateMemory( sizeof( DNS_DOMAIN_NAME ),
|
|
( void * ) &pDomainName );
|
|
BAIL_ON_ERROR( dwError );
|
|
|
|
pDomainName->pLabelList = pLabelList;
|
|
|
|
*ppDomainName = pDomainName;
|
|
|
|
return dwError;
|
|
|
|
error:
|
|
|
|
if ( pLabelList ) {
|
|
DNSFreeLabelList( pLabelList );
|
|
}
|
|
*ppDomainName = NULL;
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSAppendLabel( DNS_DOMAIN_LABEL * pLabelList,
|
|
DNS_DOMAIN_LABEL * pLabel,
|
|
DNS_DOMAIN_LABEL ** ppNewLabelList )
|
|
{
|
|
DNS_DOMAIN_LABEL **ppLabelList = NULL;
|
|
int32 dwError = 0;
|
|
|
|
if ( pLabelList == NULL ) {
|
|
*ppNewLabelList = pLabel;
|
|
return dwError;
|
|
}
|
|
|
|
ppLabelList = &pLabelList;
|
|
|
|
while ( ( *ppLabelList )->pNext ) {
|
|
ppLabelList = &( ( *ppLabelList )->pNext );
|
|
}
|
|
|
|
( *ppLabelList )->pNext = pLabel;
|
|
*ppNewLabelList = pLabelList;
|
|
return dwError;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 GetLastError( )
|
|
{
|
|
return ( errno );
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 WSAGetLastError( void )
|
|
{
|
|
return ( errno );
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
void DNSRecordGenerateOffsets( DNS_RR_RECORD * pDNSRecord )
|
|
{
|
|
int32 dwOffset = 0;
|
|
uint8 *pRData = NULL;
|
|
int16 wKeySize, wnKeySize = 0;
|
|
|
|
pRData = pDNSRecord->pRData;
|
|
switch ( pDNSRecord->RRHeader.wType ) {
|
|
case QTYPE_TKEY:
|
|
pDNSRecord->Offsets.TKey.wAlgorithmOffset =
|
|
( int16 ) dwOffset;
|
|
dwOffset += DNSGetDomainNameOffset( pRData );
|
|
pDNSRecord->Offsets.TKey.wInceptionOffset =
|
|
( int16 ) dwOffset;
|
|
dwOffset += sizeof( int32 );
|
|
pDNSRecord->Offsets.TKey.wExpirationOffset =
|
|
( int16 ) dwOffset;
|
|
dwOffset += sizeof( int32 );
|
|
pDNSRecord->Offsets.TKey.wModeOffset = ( int16 ) dwOffset;
|
|
dwOffset += sizeof( int16 );
|
|
pDNSRecord->Offsets.TKey.wErrorOffset = ( int16 ) dwOffset;
|
|
dwOffset += sizeof( int16 );
|
|
pDNSRecord->Offsets.TKey.wKeySizeOffset = ( int16 ) dwOffset;
|
|
dwOffset += sizeof( int16 );
|
|
pDNSRecord->Offsets.TKey.wKeyDataOffset = ( int16 ) dwOffset;
|
|
|
|
memcpy( &wnKeySize,
|
|
pRData + pDNSRecord->Offsets.TKey.wKeySizeOffset,
|
|
sizeof( int16 ) );
|
|
wKeySize = ntohs( wnKeySize );
|
|
|
|
dwOffset += wKeySize;
|
|
pDNSRecord->Offsets.TKey.wOtherSizeOffset =
|
|
( int16 ) dwOffset;
|
|
dwOffset += sizeof( int16 );
|
|
pDNSRecord->Offsets.TKey.wOtherDataOffset =
|
|
( int16 ) dwOffset;
|
|
break;
|
|
|
|
case QTYPE_TSIG:
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 MapDNSResponseCodes( int16 wResponseCode )
|
|
{
|
|
int16 wnResponseCode = 0;
|
|
uint8 *pByte = NULL;
|
|
|
|
wnResponseCode = htons( wResponseCode );
|
|
pByte = ( uint8 * ) & wnResponseCode;
|
|
|
|
#if 0
|
|
printf( "Byte 0 - %.2x\n", pByte[0] );
|
|
printf( "Byte 1 - %.2x\n", pByte[1] );
|
|
#endif
|
|
/* Bit 3, 2, 1, 0 of Byte 2 represent the RCode */
|
|
|
|
return ( ( int32 ) pByte[1] );
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSAllocateMemory(int32 dwSize, void * _ppMemory)
|
|
{
|
|
void **ppMemory = (void **)_ppMemory;
|
|
int32 dwError = 0;
|
|
void * pMemory = NULL;
|
|
|
|
pMemory = malloc(dwSize);
|
|
if (!pMemory){
|
|
dwError = ERROR_OUTOFMEMORY;
|
|
*ppMemory = NULL;
|
|
}else {
|
|
memset(pMemory,0, dwSize);
|
|
*ppMemory = pMemory;
|
|
}
|
|
return (dwError);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSReallocMemory(void * pMemory, void * _ppNewMemory, int32 dwSize)
|
|
{
|
|
void **ppNewMemory = (void **)_ppNewMemory;
|
|
int32 dwError = 0;
|
|
void * pNewMemory = NULL;
|
|
|
|
if (pMemory == NULL) {
|
|
pNewMemory = malloc(dwSize);
|
|
memset(pNewMemory, 0, dwSize);
|
|
}else {
|
|
pNewMemory = realloc(pMemory, dwSize);
|
|
}
|
|
if (!pNewMemory){
|
|
dwError = ERROR_OUTOFMEMORY;
|
|
*ppNewMemory = NULL;
|
|
}else {
|
|
*ppNewMemory = pNewMemory;
|
|
}
|
|
|
|
return(dwError);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
void DNSFreeMemory( void * pMemory )
|
|
{
|
|
free(pMemory);
|
|
return;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
int32 DNSAllocateString(char *pszInputString, char **ppszOutputString)
|
|
{
|
|
int32 dwError = 0;
|
|
int32 dwLen = 0;
|
|
char * pszOutputString = NULL;
|
|
|
|
if (!pszInputString || !*pszInputString){
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
BAIL_ON_ERROR(dwError);
|
|
}
|
|
dwLen = (int32)strlen(pszInputString);
|
|
dwError = DNSAllocateMemory(dwLen+1, (void *)&pszOutputString);
|
|
BAIL_ON_ERROR(dwError);
|
|
|
|
strcpy(pszOutputString, pszInputString);
|
|
|
|
*ppszOutputString = pszOutputString;
|
|
|
|
return(dwError);
|
|
error:
|
|
*ppszOutputString = pszOutputString;
|
|
return(dwError);
|
|
}
|
|
|
|
/*********************************************************************
|
|
*********************************************************************/
|
|
|
|
void DNSFreeString(char * pszString)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
|