diff options
Diffstat (limited to 'source3/libaddns/dnsgss.c')
-rw-r--r-- | source3/libaddns/dnsgss.c | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/source3/libaddns/dnsgss.c b/source3/libaddns/dnsgss.c new file mode 100644 index 0000000000..d710604b01 --- /dev/null +++ b/source3/libaddns/dnsgss.c @@ -0,0 +1,550 @@ +/* + Public Interface file for 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> + + +/********************************************************************* +*********************************************************************/ + +static int strupr( char *szDomainName ) +{ + if ( !szDomainName ) { + return ( 0 ); + } + while ( *szDomainName != '\0' ) { + *szDomainName = toupper( *szDomainName ); + szDomainName++; + } + return ( 0 ); +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSBuildTKeyQueryRequest( char *szKeyName, + uint8 * pKeyData, + int32 dwKeyLen, DNS_REQUEST ** ppDNSRequest ) +{ + int32 dwError = 0; + DNS_RR_RECORD *pDNSTKeyRecord = NULL; + DNS_REQUEST *pDNSRequest = NULL; + DNS_QUESTION_RECORD *pDNSQuestionRecord = NULL; + + dwError = DNSStdCreateStdRequest( &pDNSRequest ); + BAIL_ON_ERROR( dwError ); + + dwError = DNSCreateQuestionRecord( szKeyName, + QTYPE_TKEY, + DNS_CLASS_IN, + &pDNSQuestionRecord ); + BAIL_ON_ERROR( dwError ); + + dwError = DNSStdAddQuestionSection( pDNSRequest, pDNSQuestionRecord ); + BAIL_ON_ERROR( dwError ); + + dwError = DNSCreateTKeyRecord( szKeyName, + pKeyData, + ( int16 ) dwKeyLen, &pDNSTKeyRecord ); + BAIL_ON_ERROR( dwError ); + + dwError = DNSStdAddAdditionalSection( pDNSRequest, pDNSTKeyRecord ); + BAIL_ON_ERROR( dwError ); + + *ppDNSRequest = pDNSRequest; + + return dwError; + + error: + + *ppDNSRequest = NULL; + + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSVerifyResponseMessage_GSSSuccess( PCtxtHandle pGSSContext, + DNS_RR_RECORD * pClientTKeyRecord, + DNS_RESPONSE * pDNSResponse ) +{ + int32 dwError = 0; + DNS_RR_RECORD *pTKeyRecord = NULL; + DNS_RR_RECORD *pTSIGRecord = NULL; + int16 wRCode = 0; + + dwError = DNSResponseGetRCode( pDNSResponse, &wRCode ); + BAIL_ON_ERROR( dwError ); + + if ( wRCode != 0 ) { + dwError = ERROR_BAD_RESPONSE; + BAIL_ON_ERROR( dwError ); + + } + + dwError = DNSResponseGetTKeyRecord( pDNSResponse, &pTKeyRecord ); + BAIL_ON_ERROR( dwError ); + + dwError = DNSCompareTKeyRecord( pClientTKeyRecord, pTKeyRecord ); + BAIL_ON_ERROR( dwError ); + + dwError = DNSResponseGetTSIGRecord( pDNSResponse, &pTSIGRecord ); + BAIL_ON_ERROR( dwError ); + +/* + dwMajorStatus = GSS_VerifyMIC( + pDNSResponse->pDNSResponseBuffer, + pDNSResponse->dwNumBytes, + pDNSRRRecord->RData.TSIGRData.pMAC, + pDNSRRRecord->RData.TSIGRData.wMaxSize + ) + BAIL_ON_ERROR(dwMajorStatus);*/ + + error: + + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSVerifyResponseMessage_GSSContinue( PCtxtHandle pGSSContext, + DNS_RR_RECORD * pClientTKeyRecord, + DNS_RESPONSE * pDNSResponse, + uint8 ** ppServerKeyData, + int16 * pwServerKeyDataSize ) +{ + int32 dwError = 0; + DNS_RR_RECORD *pTKeyRecord = NULL; + int16 wRCode = 0; + uint8 *pServerKeyData = NULL; + int16 wServerKeyDataSize = 0; + + + dwError = DNSResponseGetRCode( pDNSResponse, &wRCode ); + BAIL_ON_ERROR( dwError ); + if ( wRCode != 0 ) { + dwError = ERROR_BAD_RESPONSE; + BAIL_ON_ERROR( dwError ); + + } + + dwError = DNSResponseGetTKeyRecord( pDNSResponse, &pTKeyRecord ); + BAIL_ON_ERROR( dwError ); + + + dwError = DNSCompareTKeyRecord( pClientTKeyRecord, pTKeyRecord ); + BAIL_ON_ERROR( dwError ); + + dwError = DNSGetTKeyData( pTKeyRecord, + &pServerKeyData, &wServerKeyDataSize ); + BAIL_ON_ERROR( dwError ); + + *ppServerKeyData = pServerKeyData; + *pwServerKeyDataSize = wServerKeyDataSize; + + return dwError; + + error: + + *ppServerKeyData = NULL; + *pwServerKeyDataSize = 0; + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSResponseGetRCode( DNS_RESPONSE * pDNSResponse, int16 * pwRCode ) +{ + int32 dwError = 0; + int16 wnParameter = 0; + uint8 uChar = 0; + + wnParameter = htons( pDNSResponse->wParameter ); + + /* Byte 0 is the most significate byte + Bit 12, 13, 14, 15 or Bit 4, 5, 6, 7 represent the RCode */ + + memcpy( &uChar, ( uint8 * ) & wnParameter + 1, 1 ); + uChar >>= 4; + *pwRCode = ( int16 ) uChar; + + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSResponseGetTKeyRecord( DNS_RESPONSE * pDNSResponse, + DNS_RR_RECORD ** ppTKeyRecord ) +{ + int32 dwError = 0; + int16 wAnswers = 0; + DNS_RR_RECORD *pDNSRecord = NULL; + int32 i = 0; + + + wAnswers = pDNSResponse->wAnswers; + if ( !wAnswers ) { + dwError = ERROR_INVALID_PARAMETER; + BAIL_ON_ERROR( dwError ); + } + + for ( i = 0; i < wAnswers; i++ ) { + pDNSRecord = *( pDNSResponse->ppAnswerRRSet + i ); + if ( pDNSRecord->RRHeader.wType == QTYPE_TKEY ) { + *ppTKeyRecord = pDNSRecord; + return dwError; + } + } + dwError = ERROR_RECORD_NOT_FOUND; + + error: + *ppTKeyRecord = NULL; + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSResponseGetTSIGRecord( DNS_RESPONSE * pDNSResponse, + DNS_RR_RECORD ** ppTSIGRecord ) +{ + int32 dwError = 0; + int16 wAdditionals = 0; + DNS_RR_RECORD *pDNSRecord = NULL; + + int32 i = 0; + + wAdditionals = pDNSResponse->wAdditionals; + if ( !wAdditionals ) { + dwError = ERROR_INVALID_PARAMETER; + BAIL_ON_ERROR( dwError ); + } + + for ( i = 0; i < wAdditionals; i++ ) { + pDNSRecord = *( pDNSResponse->ppAdditionalRRSet + i ); + if ( pDNSRecord->RRHeader.wType == QTYPE_TSIG ) { + *ppTSIGRecord = pDNSRecord; + return dwError; + } + } + dwError = ERROR_RECORD_NOT_FOUND; + + error: + *ppTSIGRecord = NULL; + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSCompareTKeyRecord( DNS_RR_RECORD * pClientTKeyRecord, + DNS_RR_RECORD * pTKeyRecord ) +{ + int32 dwError = 0; + + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSNegotiateContextAndSecureUpdate( HANDLE hDNSServer, + char *szServiceName, + char *szDomainName, + char *szHost, int32 dwIPAddress ) +{ + int32 dwError = 0; + char *pszKeyName = NULL; + CtxtHandle ContextHandle = 0; + CtxtHandle *pContextHandle = &ContextHandle; + + dwError = DNSGenerateKeyName( &pszKeyName ); + BAIL_ON_ERROR( dwError ); + + dwError = + DNSNegotiateSecureContext( hDNSServer, szDomainName, szHost, + pszKeyName, pContextHandle ); + BAIL_ON_ERROR( dwError ); + + error: + + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSGetTKeyData( DNS_RR_RECORD * pTKeyRecord, + uint8 ** ppKeyData, int16 * pwKeyDataSize ) +{ + int32 dwError = 0; + int16 wKeyDataSize = 0; + int16 wnKeyDataSize = 0; + int32 dwKeyDataSizeOffset = 0; + int32 dwKeyDataOffset = 0; + uint8 *pKeyData = NULL; + + DNSRecordGenerateOffsets( pTKeyRecord ); + dwKeyDataSizeOffset = pTKeyRecord->Offsets.TKey.wKeySizeOffset; + dwKeyDataOffset = pTKeyRecord->Offsets.TKey.wKeyDataOffset; + memcpy( &wnKeyDataSize, pTKeyRecord->pRData + dwKeyDataSizeOffset, + sizeof( int16 ) ); + wKeyDataSize = ntohs( wnKeyDataSize ); + + dwError = DNSAllocateMemory( wKeyDataSize, ( void ** ) &pKeyData ); + BAIL_ON_ERROR( dwError ); + + memcpy( pKeyData, pTKeyRecord->pRData + dwKeyDataOffset, + wKeyDataSize ); + + *ppKeyData = pKeyData; + *pwKeyDataSize = wKeyDataSize; + + return dwError; + + + error: + + *ppKeyData = NULL; + *pwKeyDataSize = 0; + return dwError; +} + +/********************************************************************* +*********************************************************************/ + +int32 DNSNegotiateSecureContext( HANDLE hDNSServer, + char *szDomain, + char *szServerName, + char *szKeyName, PCtxtHandle pGSSContext ) +{ + int32 dwError = 0; + int32 dwMajorStatus = 0; + char szUpperCaseDomain[256]; + char szTargetName[256]; + DNS_ERROR dns_status; + + gss_buffer_desc input_name; + gss_buffer_desc input_desc, output_desc; + DNS_REQUEST *pDNSRequest = NULL; + DNS_RESPONSE *pDNSResponse = NULL; + DNS_RR_RECORD *pClientTKeyRecord = NULL; + HANDLE hDNSTcpServer = ( HANDLE ) NULL; + + uint8 *pServerKeyData = NULL; + int16 wServerKeyDataSize = 0; + + OM_uint32 ret_flags = 0; + + int32 dwMinorStatus = 0; + gss_name_t targ_name; + gss_cred_id_t creds; + + krb5_principal host_principal; + krb5_context ctx = NULL; + + gss_OID_desc nt_host_oid_desc = + { 10, ( char * ) ( ( void * ) "\052\206\110\206\367\022\001\002\002\002" ) }; + gss_OID_desc krb5_oid_desc = + { 9, ( char * ) ( ( void * ) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" ) }; + + input_desc.value = NULL; + input_desc.length = 0; + + dns_status = DNSOpen( szServerName, DNS_TCP, &hDNSTcpServer ); + BAIL_ON_DNS_ERROR( dns_status ); + + + memset( szUpperCaseDomain, 0, sizeof( szUpperCaseDomain ) ); + memcpy( szUpperCaseDomain, szDomain, strlen( szDomain ) ); + strupr( szUpperCaseDomain ); + + dwMajorStatus = gss_acquire_cred( ( OM_uint32 * ) & dwMinorStatus, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + &creds, NULL, NULL ); + BAIL_ON_SEC_ERROR( dwMajorStatus ); + printf( "After gss_acquire_cred %d\n", dwMajorStatus ); + + sprintf( szTargetName, "dns/%s@%s", szServerName, szUpperCaseDomain ); + printf( "%s\n", szTargetName ); + + krb5_init_context( &ctx ); + krb5_parse_name( ctx, szTargetName, &host_principal ); + krb5_free_context( ctx ); + + input_name.value = &host_principal; + input_name.length = sizeof( host_principal ); + + dwMajorStatus = gss_import_name( ( OM_uint32 * ) & dwMinorStatus, + &input_name, + &nt_host_oid_desc, &targ_name ); + printf( "After gss_import_name %d\n", dwMajorStatus ); + BAIL_ON_SEC_ERROR( dwMajorStatus ); + printf( "After gss_import_name %d\n", dwMajorStatus ); + + memset( pGSSContext, 0, sizeof( CtxtHandle ) ); + *pGSSContext = GSS_C_NO_CONTEXT; + + do { + + dwMajorStatus = gss_init_sec_context( ( OM_uint32 * ) & + dwMinorStatus, creds, + pGSSContext, targ_name, + &krb5_oid_desc, + GSS_C_REPLAY_FLAG | + GSS_C_MUTUAL_FLAG | + GSS_C_SEQUENCE_FLAG | + GSS_C_CONF_FLAG | + GSS_C_INTEG_FLAG | + GSS_C_DELEG_FLAG, 0, + NULL, &input_desc, NULL, + &output_desc, + &ret_flags, NULL ); + display_status( "gss_init_context", dwMajorStatus, + dwMinorStatus ); + BAIL_ON_SEC_ERROR( dwMajorStatus ); + printf( "After gss_init_sec_context %d\n", dwMajorStatus ); + + switch ( dwMajorStatus ) { + + case GSS_S_COMPLETE: + if ( output_desc.length != 0 ) { + + dwError = DNSBuildTKeyQueryRequest( szKeyName, + output_desc. + value, + output_desc. + length, + &pDNSRequest ); + BAIL_ON_ERROR( dwError ); + + dwError = + DNSStdSendStdRequest2( hDNSTcpServer, + pDNSRequest ); + BAIL_ON_ERROR( dwError ); + + + dwError = + DNSStdReceiveStdResponse + ( hDNSTcpServer, &pDNSResponse ); + BAIL_ON_ERROR( dwError ); + + dwError = + DNSVerifyResponseMessage_GSSSuccess + ( pGSSContext, pClientTKeyRecord, + pDNSResponse ); + BAIL_ON_ERROR( dwError ); + } + break; + + + case GSS_S_CONTINUE_NEEDED: + if ( output_desc.length != 0 ) { + + dwError = DNSBuildTKeyQueryRequest( szKeyName, + output_desc. + value, + output_desc. + length, + &pDNSRequest ); + BAIL_ON_ERROR( dwError ); + + dwError = + DNSStdSendStdRequest2( hDNSTcpServer, + pDNSRequest ); + BAIL_ON_ERROR( dwError ); + + dwError = + DNSStdReceiveStdResponse + ( hDNSTcpServer, &pDNSResponse ); + BAIL_ON_ERROR( dwError ); + + dwError = + DNSVerifyResponseMessage_GSSContinue + ( pGSSContext, pClientTKeyRecord, + pDNSResponse, &pServerKeyData, + &wServerKeyDataSize ); + BAIL_ON_ERROR( dwError ); + + input_desc.value = pServerKeyData; + input_desc.length = wServerKeyDataSize; + } + break; + + default: + BAIL_ON_ERROR( dwError ); + } + + } while ( dwMajorStatus == GSS_S_CONTINUE_NEEDED ); + + /* If we arrive here, we have a valid security context */ + + sec_error: + error: + + return dwError; + +} + +/********************************************************************* +*********************************************************************/ + +static void display_status_1( const char *m, OM_uint32 code, int type ) +{ + OM_uint32 maj_stat, min_stat; + gss_buffer_desc msg; + OM_uint32 msg_ctx; + + msg_ctx = 0; + while ( 1 ) { + maj_stat = gss_display_status( &min_stat, code, + type, GSS_C_NULL_OID, + &msg_ctx, &msg ); + fprintf( stdout, "GSS-API error %s: %s\n", m, + ( char * ) msg.value ); + ( void ) gss_release_buffer( &min_stat, &msg ); + + if ( !msg_ctx ) + break; + } +} + +/********************************************************************* +*********************************************************************/ + +void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat ) +{ + display_status_1( msg, maj_stat, GSS_C_GSS_CODE ); + display_status_1( msg, min_stat, GSS_C_MECH_CODE ); +} |