2006-08-24 15:43:32 +00:00
/*
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>
2006-08-24 18:09:05 +00:00
# ifdef HAVE_GSSAPI_SUPPORT
2006-08-24 15:43:32 +00:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-24 18:09:05 +00:00
int32 DNSVerifyResponseMessage_GSSSuccess ( gss_ctx_id_t * pGSSContext ,
2006-08-24 15:43:32 +00:00
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 ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-08-24 18:09:05 +00:00
int32 DNSVerifyResponseMessage_GSSContinue ( gss_ctx_id_t * pGSSContext ,
2006-08-24 15:43:32 +00:00
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 ;
2006-08-24 18:09:05 +00:00
gss_ctx_id_t ContextHandle = 0 ;
gss_ctx_id_t * pContextHandle = & ContextHandle ;
2006-08-24 15:43:32 +00:00
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 ) ;
2006-08-24 20:17:59 +00:00
dwError = DNSAllocateMemory ( wKeyDataSize , ( void * ) & pKeyData ) ;
2006-08-24 15:43:32 +00:00
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 ,
2006-08-24 18:09:05 +00:00
char * szKeyName , gss_ctx_id_t * pGSSContext )
2006-08-24 15:43:32 +00:00
{
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 ) ;
2006-08-24 18:09:05 +00:00
memset ( pGSSContext , 0 , sizeof ( gss_ctx_id_t ) ) ;
2006-08-24 15:43:32 +00:00
* 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 ,
2006-08-24 20:17:59 +00:00
( uint8 * ) output_desc .
2006-08-24 15:43:32 +00:00
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 ,
2006-08-24 20:17:59 +00:00
( uint8 * ) output_desc .
2006-08-24 15:43:32 +00:00
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 ) ;
}
2006-08-24 18:09:05 +00:00
# endif /* HAVE_GSSAPI_SUPPORT */