summaryrefslogtreecommitdiff
path: root/source3/libaddns/dnsgss.c
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2006-08-24 15:43:32 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:38:48 -0500
commit5693e6c599a586b1bb19eea375c6b1e22526031c (patch)
tree9190fcd83791a892aaca33debd400fd0b4124fc2 /source3/libaddns/dnsgss.c
parent6717e0d467bea50cb7712e6b5278ddb403fdf828 (diff)
downloadsamba-5693e6c599a586b1bb19eea375c6b1e22526031c.tar.gz
samba-5693e6c599a586b1bb19eea375c6b1e22526031c.tar.bz2
samba-5693e6c599a586b1bb19eea375c6b1e22526031c.zip
r17798: Beginnings of a standalone libaddns library released under
the LGPL. Original code by Krishna Ganugapati <krishnag@centeris.com>. Additional work by me. It's still got some warts, but non-secure updates do currently work. There are at least four things left to really clean up. 1. Change the memory management to use talloc() rather than malloc() and cleanup the leaks. 2. Fix the error code reporting (see initial changes to dnserr.h) 3. Fix the secure updates 4. Define a public interface in addns.h 5. Move the code in libads/dns.c into the libaddns/ directory (and under the LGPL). A few notes: * Enable the new code by compiling with --with-dnsupdate * Also adds the command 'net ads dns register' * Requires -luuid (included in the e2fsprogs-devel package). * Has only been tested on Linux platforms so there may be portability issues. (This used to be commit 36f04674aeefd93c5a0408b8967dcd48b86fdbc1)
Diffstat (limited to 'source3/libaddns/dnsgss.c')
-rw-r--r--source3/libaddns/dnsgss.c550
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 );
+}