r17802: trying to fix more build farm hosts
[jra/samba/.git] / source3 / libaddns / dnsgss.c
1 /*
2   Public Interface file for Linux DNS client library implementation
3
4   Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
5   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
6
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
10
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.
15
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.
20
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
25 */
26
27 #include "dns.h"
28 #include <ctype.h>
29
30
31 #ifdef HAVE_GSSAPI_SUPPORT
32
33 /*********************************************************************
34 *********************************************************************/
35
36 static int strupr( char *szDomainName )
37 {
38         if ( !szDomainName ) {
39                 return ( 0 );
40         }
41         while ( *szDomainName != '\0' ) {
42                 *szDomainName = toupper( *szDomainName );
43                 szDomainName++;
44         }
45         return ( 0 );
46 }
47
48 /*********************************************************************
49 *********************************************************************/
50
51 int32 DNSBuildTKeyQueryRequest( char *szKeyName,
52                           uint8 * pKeyData,
53                           int32 dwKeyLen, DNS_REQUEST ** ppDNSRequest )
54 {
55         int32 dwError = 0;
56         DNS_RR_RECORD *pDNSTKeyRecord = NULL;
57         DNS_REQUEST *pDNSRequest = NULL;
58         DNS_QUESTION_RECORD *pDNSQuestionRecord = NULL;
59
60         dwError = DNSStdCreateStdRequest( &pDNSRequest );
61         BAIL_ON_ERROR( dwError );
62
63         dwError = DNSCreateQuestionRecord( szKeyName,
64                                            QTYPE_TKEY,
65                                            DNS_CLASS_IN,
66                                            &pDNSQuestionRecord );
67         BAIL_ON_ERROR( dwError );
68
69         dwError = DNSStdAddQuestionSection( pDNSRequest, pDNSQuestionRecord );
70         BAIL_ON_ERROR( dwError );
71
72         dwError = DNSCreateTKeyRecord( szKeyName,
73                                        pKeyData,
74                                        ( int16 ) dwKeyLen, &pDNSTKeyRecord );
75         BAIL_ON_ERROR( dwError );
76
77         dwError = DNSStdAddAdditionalSection( pDNSRequest, pDNSTKeyRecord );
78         BAIL_ON_ERROR( dwError );
79
80         *ppDNSRequest = pDNSRequest;
81
82         return dwError;
83
84       error:
85
86         *ppDNSRequest = NULL;
87
88         return dwError;
89 }
90
91 /*********************************************************************
92 *********************************************************************/
93
94 int32 DNSVerifyResponseMessage_GSSSuccess( gss_ctx_id_t * pGSSContext,
95                                      DNS_RR_RECORD * pClientTKeyRecord,
96                                      DNS_RESPONSE * pDNSResponse )
97 {
98         int32 dwError = 0;
99         DNS_RR_RECORD *pTKeyRecord = NULL;
100         DNS_RR_RECORD *pTSIGRecord = NULL;
101         int16 wRCode = 0;
102
103         dwError = DNSResponseGetRCode( pDNSResponse, &wRCode );
104         BAIL_ON_ERROR( dwError );
105
106         if ( wRCode != 0 ) {
107                 dwError = ERROR_BAD_RESPONSE;
108                 BAIL_ON_ERROR( dwError );
109
110         }
111
112         dwError = DNSResponseGetTKeyRecord( pDNSResponse, &pTKeyRecord );
113         BAIL_ON_ERROR( dwError );
114
115         dwError = DNSCompareTKeyRecord( pClientTKeyRecord, pTKeyRecord );
116         BAIL_ON_ERROR( dwError );
117
118         dwError = DNSResponseGetTSIGRecord( pDNSResponse, &pTSIGRecord );
119         BAIL_ON_ERROR( dwError );
120
121 /*                              
122         dwMajorStatus = GSS_VerifyMIC(
123                                                 pDNSResponse->pDNSResponseBuffer,
124                                                 pDNSResponse->dwNumBytes,
125                                                 pDNSRRRecord->RData.TSIGRData.pMAC,
126                                                 pDNSRRRecord->RData.TSIGRData.wMaxSize
127                                                 )
128         BAIL_ON_ERROR(dwMajorStatus);*/
129
130       error:
131
132         return dwError;
133 }
134
135 /*********************************************************************
136 *********************************************************************/
137
138 int32 DNSVerifyResponseMessage_GSSContinue( gss_ctx_id_t * pGSSContext,
139                                       DNS_RR_RECORD * pClientTKeyRecord,
140                                       DNS_RESPONSE * pDNSResponse,
141                                       uint8 ** ppServerKeyData,
142                                       int16 * pwServerKeyDataSize )
143 {
144         int32 dwError = 0;
145         DNS_RR_RECORD *pTKeyRecord = NULL;
146         int16 wRCode = 0;
147         uint8 *pServerKeyData = NULL;
148         int16 wServerKeyDataSize = 0;
149
150
151         dwError = DNSResponseGetRCode( pDNSResponse, &wRCode );
152         BAIL_ON_ERROR( dwError );
153         if ( wRCode != 0 ) {
154                 dwError = ERROR_BAD_RESPONSE;
155                 BAIL_ON_ERROR( dwError );
156
157         }
158
159         dwError = DNSResponseGetTKeyRecord( pDNSResponse, &pTKeyRecord );
160         BAIL_ON_ERROR( dwError );
161
162
163         dwError = DNSCompareTKeyRecord( pClientTKeyRecord, pTKeyRecord );
164         BAIL_ON_ERROR( dwError );
165
166         dwError = DNSGetTKeyData( pTKeyRecord,
167                                   &pServerKeyData, &wServerKeyDataSize );
168         BAIL_ON_ERROR( dwError );
169
170         *ppServerKeyData = pServerKeyData;
171         *pwServerKeyDataSize = wServerKeyDataSize;
172
173         return dwError;
174
175       error:
176
177         *ppServerKeyData = NULL;
178         *pwServerKeyDataSize = 0;
179         return dwError;
180 }
181
182 /*********************************************************************
183 *********************************************************************/
184
185 int32 DNSResponseGetRCode( DNS_RESPONSE * pDNSResponse, int16 * pwRCode )
186 {
187         int32 dwError = 0;
188         int16 wnParameter = 0;
189         uint8 uChar = 0;
190
191         wnParameter = htons( pDNSResponse->wParameter );
192
193         /* Byte 0 is the most significate byte
194            Bit 12, 13, 14, 15 or Bit 4, 5, 6, 7 represent the RCode */
195
196         memcpy( &uChar, ( uint8 * ) & wnParameter + 1, 1 );
197         uChar >>= 4;
198         *pwRCode = ( int16 ) uChar;
199
200         return dwError;
201 }
202
203 /*********************************************************************
204 *********************************************************************/
205
206 int32 DNSResponseGetTKeyRecord( DNS_RESPONSE * pDNSResponse,
207                           DNS_RR_RECORD ** ppTKeyRecord )
208 {
209         int32 dwError = 0;
210         int16 wAnswers = 0;
211         DNS_RR_RECORD *pDNSRecord = NULL;
212         int32 i = 0;
213
214
215         wAnswers = pDNSResponse->wAnswers;
216         if ( !wAnswers ) {
217                 dwError = ERROR_INVALID_PARAMETER;
218                 BAIL_ON_ERROR( dwError );
219         }
220
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;
226                 }
227         }
228         dwError = ERROR_RECORD_NOT_FOUND;
229
230       error:
231         *ppTKeyRecord = NULL;
232         return dwError;
233 }
234
235 /*********************************************************************
236 *********************************************************************/
237
238 int32 DNSResponseGetTSIGRecord( DNS_RESPONSE * pDNSResponse,
239                           DNS_RR_RECORD ** ppTSIGRecord )
240 {
241         int32 dwError = 0;
242         int16 wAdditionals = 0;
243         DNS_RR_RECORD *pDNSRecord = NULL;
244
245         int32 i = 0;
246
247         wAdditionals = pDNSResponse->wAdditionals;
248         if ( !wAdditionals ) {
249                 dwError = ERROR_INVALID_PARAMETER;
250                 BAIL_ON_ERROR( dwError );
251         }
252
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;
258                 }
259         }
260         dwError = ERROR_RECORD_NOT_FOUND;
261
262       error:
263         *ppTSIGRecord = NULL;
264         return dwError;
265 }
266
267 /*********************************************************************
268 *********************************************************************/
269
270 int32 DNSCompareTKeyRecord( DNS_RR_RECORD * pClientTKeyRecord,
271                       DNS_RR_RECORD * pTKeyRecord )
272 {
273         int32 dwError = 0;
274
275         return dwError;
276 }
277
278 /*********************************************************************
279 *********************************************************************/
280
281 int32 DNSNegotiateContextAndSecureUpdate( HANDLE hDNSServer,
282                                     char *szServiceName,
283                                     char *szDomainName,
284                                     char *szHost, int32 dwIPAddress )
285 {
286         int32 dwError = 0;
287         char *pszKeyName = NULL;
288         gss_ctx_id_t ContextHandle = 0;
289         gss_ctx_id_t *pContextHandle = &ContextHandle;
290
291         dwError = DNSGenerateKeyName( &pszKeyName );
292         BAIL_ON_ERROR( dwError );
293
294         dwError =
295                 DNSNegotiateSecureContext( hDNSServer, szDomainName, szHost,
296                                            pszKeyName, pContextHandle );
297         BAIL_ON_ERROR( dwError );
298
299       error:
300
301         return dwError;
302 }
303
304 /*********************************************************************
305 *********************************************************************/
306
307 int32 DNSGetTKeyData( DNS_RR_RECORD * pTKeyRecord,
308                 uint8 ** ppKeyData, int16 * pwKeyDataSize )
309 {
310         int32 dwError = 0;
311         int16 wKeyDataSize = 0;
312         int16 wnKeyDataSize = 0;
313         int32 dwKeyDataSizeOffset = 0;
314         int32 dwKeyDataOffset = 0;
315         uint8 *pKeyData = NULL;
316
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 );
323
324         dwError = DNSAllocateMemory( wKeyDataSize, ( void ** ) &pKeyData );
325         BAIL_ON_ERROR( dwError );
326
327         memcpy( pKeyData, pTKeyRecord->pRData + dwKeyDataOffset,
328                 wKeyDataSize );
329
330         *ppKeyData = pKeyData;
331         *pwKeyDataSize = wKeyDataSize;
332
333         return dwError;
334
335
336       error:
337
338         *ppKeyData = NULL;
339         *pwKeyDataSize = 0;
340         return dwError;
341 }
342
343 /*********************************************************************
344 *********************************************************************/
345
346 int32 DNSNegotiateSecureContext( HANDLE hDNSServer,
347                            char *szDomain,
348                            char *szServerName,
349                            char *szKeyName, gss_ctx_id_t * pGSSContext )
350 {
351         int32 dwError = 0;
352         int32 dwMajorStatus = 0;
353         char szUpperCaseDomain[256];
354         char szTargetName[256];
355         DNS_ERROR dns_status;
356
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;
363
364         uint8 *pServerKeyData = NULL;
365         int16 wServerKeyDataSize = 0;
366
367         OM_uint32 ret_flags = 0;
368
369         int32 dwMinorStatus = 0;
370         gss_name_t targ_name;
371         gss_cred_id_t creds;
372
373         krb5_principal host_principal;
374         krb5_context ctx = NULL;
375
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" ) };
380
381         input_desc.value = NULL;
382         input_desc.length = 0;
383
384         dns_status = DNSOpen( szServerName, DNS_TCP, &hDNSTcpServer );
385         BAIL_ON_DNS_ERROR( dns_status );
386
387
388         memset( szUpperCaseDomain, 0, sizeof( szUpperCaseDomain ) );
389         memcpy( szUpperCaseDomain, szDomain, strlen( szDomain ) );
390         strupr( szUpperCaseDomain );
391
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 );
400
401         sprintf( szTargetName, "dns/%s@%s", szServerName, szUpperCaseDomain );
402         printf( "%s\n", szTargetName );
403
404         krb5_init_context( &ctx );
405         krb5_parse_name( ctx, szTargetName, &host_principal );
406         krb5_free_context( ctx );
407
408         input_name.value = &host_principal;
409         input_name.length = sizeof( host_principal );
410
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 );
417
418         memset( pGSSContext, 0, sizeof( gss_ctx_id_t ) );
419         *pGSSContext = GSS_C_NO_CONTEXT;
420
421         do {
422
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 );
440
441                 switch ( dwMajorStatus ) {
442
443                 case GSS_S_COMPLETE:
444                         if ( output_desc.length != 0 ) {
445
446                                 dwError = DNSBuildTKeyQueryRequest( szKeyName,
447                                                                     output_desc.
448                                                                     value,
449                                                                     output_desc.
450                                                                     length,
451                                                                     &pDNSRequest );
452                                 BAIL_ON_ERROR( dwError );
453
454                                 dwError =
455                                         DNSStdSendStdRequest2( hDNSTcpServer,
456                                                                pDNSRequest );
457                                 BAIL_ON_ERROR( dwError );
458
459
460                                 dwError =
461                                         DNSStdReceiveStdResponse
462                                         ( hDNSTcpServer, &pDNSResponse );
463                                 BAIL_ON_ERROR( dwError );
464
465                                 dwError =
466                                         DNSVerifyResponseMessage_GSSSuccess
467                                         ( pGSSContext, pClientTKeyRecord,
468                                           pDNSResponse );
469                                 BAIL_ON_ERROR( dwError );
470                         }
471                         break;
472
473
474                 case GSS_S_CONTINUE_NEEDED:
475                         if ( output_desc.length != 0 ) {
476
477                                 dwError = DNSBuildTKeyQueryRequest( szKeyName,
478                                                                     output_desc.
479                                                                     value,
480                                                                     output_desc.
481                                                                     length,
482                                                                     &pDNSRequest );
483                                 BAIL_ON_ERROR( dwError );
484
485                                 dwError =
486                                         DNSStdSendStdRequest2( hDNSTcpServer,
487                                                                pDNSRequest );
488                                 BAIL_ON_ERROR( dwError );
489
490                                 dwError =
491                                         DNSStdReceiveStdResponse
492                                         ( hDNSTcpServer, &pDNSResponse );
493                                 BAIL_ON_ERROR( dwError );
494
495                                 dwError =
496                                         DNSVerifyResponseMessage_GSSContinue
497                                         ( pGSSContext, pClientTKeyRecord,
498                                           pDNSResponse, &pServerKeyData,
499                                           &wServerKeyDataSize );
500                                 BAIL_ON_ERROR( dwError );
501
502                                 input_desc.value = pServerKeyData;
503                                 input_desc.length = wServerKeyDataSize;
504                         }
505                         break;
506
507                 default:
508                         BAIL_ON_ERROR( dwError );
509                 }
510
511         } while ( dwMajorStatus == GSS_S_CONTINUE_NEEDED );
512
513         /* If we arrive here, we have a valid security context */
514
515       sec_error:
516       error:
517
518         return dwError;
519
520 }
521
522 /*********************************************************************
523 *********************************************************************/
524
525 static void display_status_1( const char *m, OM_uint32 code, int type )
526 {
527         OM_uint32 maj_stat, min_stat;
528         gss_buffer_desc msg;
529         OM_uint32 msg_ctx;
530
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 );
539
540                 if ( !msg_ctx )
541                         break;
542         }
543 }
544
545 /*********************************************************************
546 *********************************************************************/
547
548 void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
549 {
550         display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
551         display_status_1( msg, min_stat, GSS_C_MECH_CODE );
552 }
553
554 #endif  /* HAVE_GSSAPI_SUPPORT */