2 Public Interface file for Linux DNS client library implementation
4 Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
7 ** NOTE! The following LGPL license applies to the libaddns
8 ** library. This does NOT imply that all of Samba is released
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31 #ifdef HAVE_GSSAPI_SUPPORT
33 /*********************************************************************
34 *********************************************************************/
36 static int strupr( char *szDomainName
)
38 if ( !szDomainName
) {
41 while ( *szDomainName
!= '\0' ) {
42 *szDomainName
= toupper( *szDomainName
);
48 /*********************************************************************
49 *********************************************************************/
51 int32
DNSBuildTKeyQueryRequest( char *szKeyName
,
53 int32 dwKeyLen
, DNS_REQUEST
** ppDNSRequest
)
56 DNS_RR_RECORD
*pDNSTKeyRecord
= NULL
;
57 DNS_REQUEST
*pDNSRequest
= NULL
;
58 DNS_QUESTION_RECORD
*pDNSQuestionRecord
= NULL
;
60 dwError
= DNSStdCreateStdRequest( &pDNSRequest
);
61 BAIL_ON_ERROR( dwError
);
63 dwError
= DNSCreateQuestionRecord( szKeyName
,
66 &pDNSQuestionRecord
);
67 BAIL_ON_ERROR( dwError
);
69 dwError
= DNSStdAddQuestionSection( pDNSRequest
, pDNSQuestionRecord
);
70 BAIL_ON_ERROR( dwError
);
72 dwError
= DNSCreateTKeyRecord( szKeyName
,
74 ( int16
) dwKeyLen
, &pDNSTKeyRecord
);
75 BAIL_ON_ERROR( dwError
);
77 dwError
= DNSStdAddAdditionalSection( pDNSRequest
, pDNSTKeyRecord
);
78 BAIL_ON_ERROR( dwError
);
80 *ppDNSRequest
= pDNSRequest
;
91 /*********************************************************************
92 *********************************************************************/
94 int32
DNSVerifyResponseMessage_GSSSuccess( gss_ctx_id_t
* pGSSContext
,
95 DNS_RR_RECORD
* pClientTKeyRecord
,
96 DNS_RESPONSE
* pDNSResponse
)
99 DNS_RR_RECORD
*pTKeyRecord
= NULL
;
100 DNS_RR_RECORD
*pTSIGRecord
= NULL
;
103 dwError
= DNSResponseGetRCode( pDNSResponse
, &wRCode
);
104 BAIL_ON_ERROR( dwError
);
107 dwError
= ERROR_BAD_RESPONSE
;
108 BAIL_ON_ERROR( dwError
);
112 dwError
= DNSResponseGetTKeyRecord( pDNSResponse
, &pTKeyRecord
);
113 BAIL_ON_ERROR( dwError
);
115 dwError
= DNSCompareTKeyRecord( pClientTKeyRecord
, pTKeyRecord
);
116 BAIL_ON_ERROR( dwError
);
118 dwError
= DNSResponseGetTSIGRecord( pDNSResponse
, &pTSIGRecord
);
119 BAIL_ON_ERROR( dwError
);
122 dwMajorStatus = GSS_VerifyMIC(
123 pDNSResponse->pDNSResponseBuffer,
124 pDNSResponse->dwNumBytes,
125 pDNSRRRecord->RData.TSIGRData.pMAC,
126 pDNSRRRecord->RData.TSIGRData.wMaxSize
128 BAIL_ON_ERROR(dwMajorStatus);*/
135 /*********************************************************************
136 *********************************************************************/
138 int32
DNSVerifyResponseMessage_GSSContinue( gss_ctx_id_t
* pGSSContext
,
139 DNS_RR_RECORD
* pClientTKeyRecord
,
140 DNS_RESPONSE
* pDNSResponse
,
141 uint8
** ppServerKeyData
,
142 int16
* pwServerKeyDataSize
)
145 DNS_RR_RECORD
*pTKeyRecord
= NULL
;
147 uint8
*pServerKeyData
= NULL
;
148 int16 wServerKeyDataSize
= 0;
151 dwError
= DNSResponseGetRCode( pDNSResponse
, &wRCode
);
152 BAIL_ON_ERROR( dwError
);
154 dwError
= ERROR_BAD_RESPONSE
;
155 BAIL_ON_ERROR( dwError
);
159 dwError
= DNSResponseGetTKeyRecord( pDNSResponse
, &pTKeyRecord
);
160 BAIL_ON_ERROR( dwError
);
163 dwError
= DNSCompareTKeyRecord( pClientTKeyRecord
, pTKeyRecord
);
164 BAIL_ON_ERROR( dwError
);
166 dwError
= DNSGetTKeyData( pTKeyRecord
,
167 &pServerKeyData
, &wServerKeyDataSize
);
168 BAIL_ON_ERROR( dwError
);
170 *ppServerKeyData
= pServerKeyData
;
171 *pwServerKeyDataSize
= wServerKeyDataSize
;
177 *ppServerKeyData
= NULL
;
178 *pwServerKeyDataSize
= 0;
182 /*********************************************************************
183 *********************************************************************/
185 int32
DNSResponseGetRCode( DNS_RESPONSE
* pDNSResponse
, int16
* pwRCode
)
188 int16 wnParameter
= 0;
191 wnParameter
= htons( pDNSResponse
->wParameter
);
193 /* Byte 0 is the most significate byte
194 Bit 12, 13, 14, 15 or Bit 4, 5, 6, 7 represent the RCode */
196 memcpy( &uChar
, ( uint8
* ) & wnParameter
+ 1, 1 );
198 *pwRCode
= ( int16
) uChar
;
203 /*********************************************************************
204 *********************************************************************/
206 int32
DNSResponseGetTKeyRecord( DNS_RESPONSE
* pDNSResponse
,
207 DNS_RR_RECORD
** ppTKeyRecord
)
211 DNS_RR_RECORD
*pDNSRecord
= NULL
;
215 wAnswers
= pDNSResponse
->wAnswers
;
217 dwError
= ERROR_INVALID_PARAMETER
;
218 BAIL_ON_ERROR( dwError
);
221 for ( i
= 0; i
< wAnswers
; i
++ ) {
222 pDNSRecord
= *( pDNSResponse
->ppAnswerRRSet
+ i
);
223 if ( pDNSRecord
->RRHeader
.wType
== QTYPE_TKEY
) {
224 *ppTKeyRecord
= pDNSRecord
;
228 dwError
= ERROR_RECORD_NOT_FOUND
;
231 *ppTKeyRecord
= NULL
;
235 /*********************************************************************
236 *********************************************************************/
238 int32
DNSResponseGetTSIGRecord( DNS_RESPONSE
* pDNSResponse
,
239 DNS_RR_RECORD
** ppTSIGRecord
)
242 int16 wAdditionals
= 0;
243 DNS_RR_RECORD
*pDNSRecord
= NULL
;
247 wAdditionals
= pDNSResponse
->wAdditionals
;
248 if ( !wAdditionals
) {
249 dwError
= ERROR_INVALID_PARAMETER
;
250 BAIL_ON_ERROR( dwError
);
253 for ( i
= 0; i
< wAdditionals
; i
++ ) {
254 pDNSRecord
= *( pDNSResponse
->ppAdditionalRRSet
+ i
);
255 if ( pDNSRecord
->RRHeader
.wType
== QTYPE_TSIG
) {
256 *ppTSIGRecord
= pDNSRecord
;
260 dwError
= ERROR_RECORD_NOT_FOUND
;
263 *ppTSIGRecord
= NULL
;
267 /*********************************************************************
268 *********************************************************************/
270 int32
DNSCompareTKeyRecord( DNS_RR_RECORD
* pClientTKeyRecord
,
271 DNS_RR_RECORD
* pTKeyRecord
)
278 /*********************************************************************
279 *********************************************************************/
281 int32
DNSNegotiateContextAndSecureUpdate( HANDLE hDNSServer
,
284 char *szHost
, int32 dwIPAddress
)
287 char *pszKeyName
= NULL
;
288 gss_ctx_id_t ContextHandle
= 0;
289 gss_ctx_id_t
*pContextHandle
= &ContextHandle
;
291 dwError
= DNSGenerateKeyName( &pszKeyName
);
292 BAIL_ON_ERROR( dwError
);
295 DNSNegotiateSecureContext( hDNSServer
, szDomainName
, szHost
,
296 pszKeyName
, pContextHandle
);
297 BAIL_ON_ERROR( dwError
);
304 /*********************************************************************
305 *********************************************************************/
307 int32
DNSGetTKeyData( DNS_RR_RECORD
* pTKeyRecord
,
308 uint8
** ppKeyData
, int16
* pwKeyDataSize
)
311 int16 wKeyDataSize
= 0;
312 int16 wnKeyDataSize
= 0;
313 int32 dwKeyDataSizeOffset
= 0;
314 int32 dwKeyDataOffset
= 0;
315 uint8
*pKeyData
= NULL
;
317 DNSRecordGenerateOffsets( pTKeyRecord
);
318 dwKeyDataSizeOffset
= pTKeyRecord
->Offsets
.TKey
.wKeySizeOffset
;
319 dwKeyDataOffset
= pTKeyRecord
->Offsets
.TKey
.wKeyDataOffset
;
320 memcpy( &wnKeyDataSize
, pTKeyRecord
->pRData
+ dwKeyDataSizeOffset
,
322 wKeyDataSize
= ntohs( wnKeyDataSize
);
324 dwError
= DNSAllocateMemory( wKeyDataSize
, ( void * ) &pKeyData
);
325 BAIL_ON_ERROR( dwError
);
327 memcpy( pKeyData
, pTKeyRecord
->pRData
+ dwKeyDataOffset
,
330 *ppKeyData
= pKeyData
;
331 *pwKeyDataSize
= wKeyDataSize
;
343 /*********************************************************************
344 *********************************************************************/
346 int32
DNSNegotiateSecureContext( HANDLE hDNSServer
,
349 char *szKeyName
, gss_ctx_id_t
* pGSSContext
)
352 int32 dwMajorStatus
= 0;
353 char szUpperCaseDomain
[256];
354 char szTargetName
[256];
355 DNS_ERROR dns_status
;
357 gss_buffer_desc input_name
;
358 gss_buffer_desc input_desc
, output_desc
;
359 DNS_REQUEST
*pDNSRequest
= NULL
;
360 DNS_RESPONSE
*pDNSResponse
= NULL
;
361 DNS_RR_RECORD
*pClientTKeyRecord
= NULL
;
362 HANDLE hDNSTcpServer
= ( HANDLE
) NULL
;
364 uint8
*pServerKeyData
= NULL
;
365 int16 wServerKeyDataSize
= 0;
367 OM_uint32 ret_flags
= 0;
369 int32 dwMinorStatus
= 0;
370 gss_name_t targ_name
;
373 krb5_principal host_principal
;
374 krb5_context ctx
= NULL
;
376 gss_OID_desc nt_host_oid_desc
=
377 { 10, ( char * ) ( ( void * ) "\052\206\110\206\367\022\001\002\002\002" ) };
378 gss_OID_desc krb5_oid_desc
=
379 { 9, ( char * ) ( ( void * ) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" ) };
381 input_desc
.value
= NULL
;
382 input_desc
.length
= 0;
384 dns_status
= DNSOpen( szServerName
, DNS_TCP
, &hDNSTcpServer
);
385 BAIL_ON_DNS_ERROR( dns_status
);
388 memset( szUpperCaseDomain
, 0, sizeof( szUpperCaseDomain
) );
389 memcpy( szUpperCaseDomain
, szDomain
, strlen( szDomain
) );
390 strupr( szUpperCaseDomain
);
392 dwMajorStatus
= gss_acquire_cred( ( OM_uint32
* ) & dwMinorStatus
,
397 &creds
, NULL
, NULL
);
398 BAIL_ON_SEC_ERROR( dwMajorStatus
);
399 printf( "After gss_acquire_cred %d\n", dwMajorStatus
);
401 sprintf( szTargetName
, "dns/%s@%s", szServerName
, szUpperCaseDomain
);
402 printf( "%s\n", szTargetName
);
404 krb5_init_context( &ctx
);
405 krb5_parse_name( ctx
, szTargetName
, &host_principal
);
406 krb5_free_context( ctx
);
408 input_name
.value
= &host_principal
;
409 input_name
.length
= sizeof( host_principal
);
411 dwMajorStatus
= gss_import_name( ( OM_uint32
* ) & dwMinorStatus
,
413 &nt_host_oid_desc
, &targ_name
);
414 printf( "After gss_import_name %d\n", dwMajorStatus
);
415 BAIL_ON_SEC_ERROR( dwMajorStatus
);
416 printf( "After gss_import_name %d\n", dwMajorStatus
);
418 memset( pGSSContext
, 0, sizeof( gss_ctx_id_t
) );
419 *pGSSContext
= GSS_C_NO_CONTEXT
;
423 dwMajorStatus
= gss_init_sec_context( ( OM_uint32
* ) &
424 dwMinorStatus
, creds
,
425 pGSSContext
, targ_name
,
429 GSS_C_SEQUENCE_FLAG
|
433 NULL
, &input_desc
, NULL
,
436 display_status( "gss_init_context", dwMajorStatus
,
438 BAIL_ON_SEC_ERROR( dwMajorStatus
);
439 printf( "After gss_init_sec_context %d\n", dwMajorStatus
);
441 switch ( dwMajorStatus
) {
444 if ( output_desc
.length
!= 0 ) {
446 dwError
= DNSBuildTKeyQueryRequest( szKeyName
,
447 (uint8
*)output_desc
.
452 BAIL_ON_ERROR( dwError
);
455 DNSStdSendStdRequest2( hDNSTcpServer
,
457 BAIL_ON_ERROR( dwError
);
461 DNSStdReceiveStdResponse
462 ( hDNSTcpServer
, &pDNSResponse
);
463 BAIL_ON_ERROR( dwError
);
466 DNSVerifyResponseMessage_GSSSuccess
467 ( pGSSContext
, pClientTKeyRecord
,
469 BAIL_ON_ERROR( dwError
);
474 case GSS_S_CONTINUE_NEEDED
:
475 if ( output_desc
.length
!= 0 ) {
477 dwError
= DNSBuildTKeyQueryRequest( szKeyName
,
478 (uint8
*)output_desc
.
483 BAIL_ON_ERROR( dwError
);
486 DNSStdSendStdRequest2( hDNSTcpServer
,
488 BAIL_ON_ERROR( dwError
);
491 DNSStdReceiveStdResponse
492 ( hDNSTcpServer
, &pDNSResponse
);
493 BAIL_ON_ERROR( dwError
);
496 DNSVerifyResponseMessage_GSSContinue
497 ( pGSSContext
, pClientTKeyRecord
,
498 pDNSResponse
, &pServerKeyData
,
499 &wServerKeyDataSize
);
500 BAIL_ON_ERROR( dwError
);
502 input_desc
.value
= pServerKeyData
;
503 input_desc
.length
= wServerKeyDataSize
;
508 BAIL_ON_ERROR( dwError
);
511 } while ( dwMajorStatus
== GSS_S_CONTINUE_NEEDED
);
513 /* If we arrive here, we have a valid security context */
522 /*********************************************************************
523 *********************************************************************/
525 static void display_status_1( const char *m
, OM_uint32 code
, int type
)
527 OM_uint32 maj_stat
, min_stat
;
533 maj_stat
= gss_display_status( &min_stat
, code
,
534 type
, GSS_C_NULL_OID
,
536 fprintf( stdout
, "GSS-API error %s: %s\n", m
,
537 ( char * ) msg
.value
);
538 ( void ) gss_release_buffer( &min_stat
, &msg
);
545 /*********************************************************************
546 *********************************************************************/
548 void display_status( const char *msg
, OM_uint32 maj_stat
, OM_uint32 min_stat
)
550 display_status_1( msg
, maj_stat
, GSS_C_GSS_CODE
);
551 display_status_1( msg
, min_stat
, GSS_C_MECH_CODE
);
554 #endif /* HAVE_GSSAPI_SUPPORT */