r17805: Sorry Jerry, I could not stand the warnings... :-)
[Samba.git] / source / libaddns / dnsgss.c
blob862f5e7b58195f7cd29d8ee44995af2a3e6cb1c4
1 /*
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
9 ** under the LGPL
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
24 02110-1301 USA
27 #include "dns.h"
28 #include <ctype.h>
31 #ifdef HAVE_GSSAPI_SUPPORT
33 /*********************************************************************
34 *********************************************************************/
36 static int strupr( char *szDomainName )
38 if ( !szDomainName ) {
39 return ( 0 );
41 while ( *szDomainName != '\0' ) {
42 *szDomainName = toupper( *szDomainName );
43 szDomainName++;
45 return ( 0 );
48 /*********************************************************************
49 *********************************************************************/
51 int32 DNSBuildTKeyQueryRequest( char *szKeyName,
52 uint8 * pKeyData,
53 int32 dwKeyLen, DNS_REQUEST ** ppDNSRequest )
55 int32 dwError = 0;
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,
64 QTYPE_TKEY,
65 DNS_CLASS_IN,
66 &pDNSQuestionRecord );
67 BAIL_ON_ERROR( dwError );
69 dwError = DNSStdAddQuestionSection( pDNSRequest, pDNSQuestionRecord );
70 BAIL_ON_ERROR( dwError );
72 dwError = DNSCreateTKeyRecord( szKeyName,
73 pKeyData,
74 ( int16 ) dwKeyLen, &pDNSTKeyRecord );
75 BAIL_ON_ERROR( dwError );
77 dwError = DNSStdAddAdditionalSection( pDNSRequest, pDNSTKeyRecord );
78 BAIL_ON_ERROR( dwError );
80 *ppDNSRequest = pDNSRequest;
82 return dwError;
84 error:
86 *ppDNSRequest = NULL;
88 return dwError;
91 /*********************************************************************
92 *********************************************************************/
94 int32 DNSVerifyResponseMessage_GSSSuccess( gss_ctx_id_t * pGSSContext,
95 DNS_RR_RECORD * pClientTKeyRecord,
96 DNS_RESPONSE * pDNSResponse )
98 int32 dwError = 0;
99 DNS_RR_RECORD *pTKeyRecord = NULL;
100 DNS_RR_RECORD *pTSIGRecord = NULL;
101 int16 wRCode = 0;
103 dwError = DNSResponseGetRCode( pDNSResponse, &wRCode );
104 BAIL_ON_ERROR( dwError );
106 if ( wRCode != 0 ) {
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);*/
130 error:
132 return dwError;
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 )
144 int32 dwError = 0;
145 DNS_RR_RECORD *pTKeyRecord = NULL;
146 int16 wRCode = 0;
147 uint8 *pServerKeyData = NULL;
148 int16 wServerKeyDataSize = 0;
151 dwError = DNSResponseGetRCode( pDNSResponse, &wRCode );
152 BAIL_ON_ERROR( dwError );
153 if ( wRCode != 0 ) {
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;
173 return dwError;
175 error:
177 *ppServerKeyData = NULL;
178 *pwServerKeyDataSize = 0;
179 return dwError;
182 /*********************************************************************
183 *********************************************************************/
185 int32 DNSResponseGetRCode( DNS_RESPONSE * pDNSResponse, int16 * pwRCode )
187 int32 dwError = 0;
188 int16 wnParameter = 0;
189 uint8 uChar = 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 );
197 uChar >>= 4;
198 *pwRCode = ( int16 ) uChar;
200 return dwError;
203 /*********************************************************************
204 *********************************************************************/
206 int32 DNSResponseGetTKeyRecord( DNS_RESPONSE * pDNSResponse,
207 DNS_RR_RECORD ** ppTKeyRecord )
209 int32 dwError = 0;
210 int16 wAnswers = 0;
211 DNS_RR_RECORD *pDNSRecord = NULL;
212 int32 i = 0;
215 wAnswers = pDNSResponse->wAnswers;
216 if ( !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;
225 return dwError;
228 dwError = ERROR_RECORD_NOT_FOUND;
230 error:
231 *ppTKeyRecord = NULL;
232 return dwError;
235 /*********************************************************************
236 *********************************************************************/
238 int32 DNSResponseGetTSIGRecord( DNS_RESPONSE * pDNSResponse,
239 DNS_RR_RECORD ** ppTSIGRecord )
241 int32 dwError = 0;
242 int16 wAdditionals = 0;
243 DNS_RR_RECORD *pDNSRecord = NULL;
245 int32 i = 0;
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;
257 return dwError;
260 dwError = ERROR_RECORD_NOT_FOUND;
262 error:
263 *ppTSIGRecord = NULL;
264 return dwError;
267 /*********************************************************************
268 *********************************************************************/
270 int32 DNSCompareTKeyRecord( DNS_RR_RECORD * pClientTKeyRecord,
271 DNS_RR_RECORD * pTKeyRecord )
273 int32 dwError = 0;
275 return dwError;
278 /*********************************************************************
279 *********************************************************************/
281 int32 DNSNegotiateContextAndSecureUpdate( HANDLE hDNSServer,
282 char *szServiceName,
283 char *szDomainName,
284 char *szHost, int32 dwIPAddress )
286 int32 dwError = 0;
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 );
294 dwError =
295 DNSNegotiateSecureContext( hDNSServer, szDomainName, szHost,
296 pszKeyName, pContextHandle );
297 BAIL_ON_ERROR( dwError );
299 error:
301 return dwError;
304 /*********************************************************************
305 *********************************************************************/
307 int32 DNSGetTKeyData( DNS_RR_RECORD * pTKeyRecord,
308 uint8 ** ppKeyData, int16 * pwKeyDataSize )
310 int32 dwError = 0;
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,
321 sizeof( int16 ) );
322 wKeyDataSize = ntohs( wnKeyDataSize );
324 dwError = DNSAllocateMemory( wKeyDataSize, ( void * ) &pKeyData );
325 BAIL_ON_ERROR( dwError );
327 memcpy( pKeyData, pTKeyRecord->pRData + dwKeyDataOffset,
328 wKeyDataSize );
330 *ppKeyData = pKeyData;
331 *pwKeyDataSize = wKeyDataSize;
333 return dwError;
336 error:
338 *ppKeyData = NULL;
339 *pwKeyDataSize = 0;
340 return dwError;
343 /*********************************************************************
344 *********************************************************************/
346 int32 DNSNegotiateSecureContext( HANDLE hDNSServer,
347 char *szDomain,
348 char *szServerName,
349 char *szKeyName, gss_ctx_id_t * pGSSContext )
351 int32 dwError = 0;
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;
371 gss_cred_id_t creds;
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,
393 GSS_C_NO_NAME,
394 GSS_C_INDEFINITE,
395 GSS_C_NO_OID_SET,
396 GSS_C_INITIATE,
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,
412 &input_name,
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;
421 do {
423 dwMajorStatus = gss_init_sec_context( ( OM_uint32 * ) &
424 dwMinorStatus, creds,
425 pGSSContext, targ_name,
426 &krb5_oid_desc,
427 GSS_C_REPLAY_FLAG |
428 GSS_C_MUTUAL_FLAG |
429 GSS_C_SEQUENCE_FLAG |
430 GSS_C_CONF_FLAG |
431 GSS_C_INTEG_FLAG |
432 GSS_C_DELEG_FLAG, 0,
433 NULL, &input_desc, NULL,
434 &output_desc,
435 &ret_flags, NULL );
436 display_status( "gss_init_context", dwMajorStatus,
437 dwMinorStatus );
438 BAIL_ON_SEC_ERROR( dwMajorStatus );
439 printf( "After gss_init_sec_context %d\n", dwMajorStatus );
441 switch ( dwMajorStatus ) {
443 case GSS_S_COMPLETE:
444 if ( output_desc.length != 0 ) {
446 dwError = DNSBuildTKeyQueryRequest( szKeyName,
447 (uint8 *)output_desc.
448 value,
449 output_desc.
450 length,
451 &pDNSRequest );
452 BAIL_ON_ERROR( dwError );
454 dwError =
455 DNSStdSendStdRequest2( hDNSTcpServer,
456 pDNSRequest );
457 BAIL_ON_ERROR( dwError );
460 dwError =
461 DNSStdReceiveStdResponse
462 ( hDNSTcpServer, &pDNSResponse );
463 BAIL_ON_ERROR( dwError );
465 dwError =
466 DNSVerifyResponseMessage_GSSSuccess
467 ( pGSSContext, pClientTKeyRecord,
468 pDNSResponse );
469 BAIL_ON_ERROR( dwError );
471 break;
474 case GSS_S_CONTINUE_NEEDED:
475 if ( output_desc.length != 0 ) {
477 dwError = DNSBuildTKeyQueryRequest( szKeyName,
478 (uint8 *)output_desc.
479 value,
480 output_desc.
481 length,
482 &pDNSRequest );
483 BAIL_ON_ERROR( dwError );
485 dwError =
486 DNSStdSendStdRequest2( hDNSTcpServer,
487 pDNSRequest );
488 BAIL_ON_ERROR( dwError );
490 dwError =
491 DNSStdReceiveStdResponse
492 ( hDNSTcpServer, &pDNSResponse );
493 BAIL_ON_ERROR( dwError );
495 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;
505 break;
507 default:
508 BAIL_ON_ERROR( dwError );
511 } while ( dwMajorStatus == GSS_S_CONTINUE_NEEDED );
513 /* If we arrive here, we have a valid security context */
515 sec_error:
516 error:
518 return dwError;
522 /*********************************************************************
523 *********************************************************************/
525 static void display_status_1( const char *m, OM_uint32 code, int type )
527 OM_uint32 maj_stat, min_stat;
528 gss_buffer_desc msg;
529 OM_uint32 msg_ctx;
531 msg_ctx = 0;
532 while ( 1 ) {
533 maj_stat = gss_display_status( &min_stat, code,
534 type, GSS_C_NULL_OID,
535 &msg_ctx, &msg );
536 fprintf( stdout, "GSS-API error %s: %s\n", m,
537 ( char * ) msg.value );
538 ( void ) gss_release_buffer( &min_stat, &msg );
540 if ( !msg_ctx )
541 break;
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 */