LCOV - code coverage report
Current view: top level - lib/addns - dnsgss.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 106 147 72.1 %
Date: 2024-02-28 12:06:22 Functions: 4 4 100.0 %

          Line data    Source code
       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, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "dns.h"
      26             : #include <ctype.h>
      27             : 
      28             : 
      29             : #ifdef HAVE_GSSAPI
      30             : 
      31             : /*********************************************************************
      32             : *********************************************************************/
      33             : 
      34             : #ifndef HAVE_STRUPR
      35          42 : static int strupr( char *szDomainName )
      36             : {
      37          42 :         if ( !szDomainName ) {
      38           0 :                 return ( 0 );
      39             :         }
      40         968 :         while ( *szDomainName != '\0' ) {
      41         926 :                 *szDomainName = toupper( *szDomainName );
      42         926 :                 szDomainName++;
      43             :         }
      44          42 :         return ( 0 );
      45             : }
      46             : #endif
      47             : 
      48             : #if 0
      49             : /*********************************************************************
      50             : *********************************************************************/
      51             : 
      52             : static void display_status_1( const char *m, OM_uint32 code, int type )
      53             : {
      54             :         OM_uint32 maj_stat, min_stat;
      55             :         gss_buffer_desc msg;
      56             :         OM_uint32 msg_ctx;
      57             : 
      58             :         msg_ctx = 0;
      59             :         while ( 1 ) {
      60             :                 maj_stat = gss_display_status( &min_stat, code,
      61             :                                                type, GSS_C_NULL_OID,
      62             :                                                &msg_ctx, &msg );
      63             :                 fprintf( stdout, "GSS-API error %s: %s\n", m,
      64             :                          ( char * ) msg.value );
      65             :                 ( void ) gss_release_buffer( &min_stat, &msg );
      66             : 
      67             :                 if ( !msg_ctx )
      68             :                         break;
      69             :         }
      70             : }
      71             : 
      72             : /*********************************************************************
      73             : *********************************************************************/
      74             : 
      75             : void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
      76             : {
      77             :         display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
      78             :         display_status_1( msg, min_stat, GSS_C_MECH_CODE );
      79             : }
      80             : #endif
      81             : 
      82          42 : static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx,
      83             :                                             struct dns_connection *conn,
      84             :                                             const char *keyname,
      85             :                                             const gss_name_t target_name,
      86             :                                             gss_ctx_id_t *ctx, 
      87             :                                             enum dns_ServerType srv_type )
      88             : {
      89           0 :         struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
      90           0 :         OM_uint32 major, minor;
      91           0 :         OM_uint32 ret_flags;
      92          42 :         struct dns_request *req = NULL;
      93          42 :         struct dns_buffer *buf = NULL;
      94           0 :         DNS_ERROR err;
      95             : 
      96          42 :         gss_OID_desc krb5_oid_desc =
      97             :                 { 9, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") };
      98             : 
      99          42 :         *ctx = GSS_C_NO_CONTEXT;
     100          42 :         input_ptr = NULL;
     101             : 
     102           0 :         do {
     103          84 :                 major = gss_init_sec_context(
     104             :                         &minor, NULL, ctx, target_name, &krb5_oid_desc,
     105             :                         GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
     106             :                         GSS_C_CONF_FLAG |
     107             :                         GSS_C_INTEG_FLAG,
     108             :                         0, NULL, input_ptr, NULL, &output_desc,
     109             :                         &ret_flags, NULL );
     110             : 
     111          84 :                 if (input_ptr != NULL) {
     112          42 :                         TALLOC_FREE(input_desc.value);
     113             :                 }
     114             : 
     115          84 :                 if (output_desc.length != 0) {
     116             : 
     117           0 :                         struct dns_rrec *rec;
     118             : 
     119          42 :                         time_t t = time(NULL);
     120             : 
     121          42 :                         err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
     122             :                                                DNS_CLASS_IN, &req);
     123          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     124             : 
     125          42 :                         err = dns_create_tkey_record(
     126             :                                 req, keyname, "gss.microsoft.com", t,
     127             :                                 t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
     128          42 :                                 output_desc.length, (uint8_t *)output_desc.value,
     129             :                                 &rec );
     130          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     131             : 
     132             :                         /* Windows 2000 DNS is broken and requires the
     133             :                            TKEY payload in the Answer section instead
     134             :                            of the Additional section like Windows 2003 */
     135             : 
     136          42 :                         if ( srv_type == DNS_SRV_WIN2000 ) {
     137           0 :                                 err = dns_add_rrec(req, rec, &req->num_answers,
     138           0 :                                                    &req->answers);
     139             :                         } else {
     140          42 :                                 err = dns_add_rrec(req, rec, &req->num_additionals,
     141          42 :                                                    &req->additional);
     142             :                         }
     143             :                         
     144          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     145             : 
     146          42 :                         err = dns_marshall_request(mem_ctx, req, &buf);
     147          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     148             : 
     149          42 :                         err = dns_send(conn, buf);
     150          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     151             : 
     152          42 :                         TALLOC_FREE(buf);
     153          42 :                         TALLOC_FREE(req);
     154             :                 }
     155             : 
     156          84 :                 gss_release_buffer(&minor, &output_desc);
     157             : 
     158          84 :                 if ((major != GSS_S_COMPLETE) &&
     159             :                     (major != GSS_S_CONTINUE_NEEDED)) {
     160           0 :                         return ERROR_DNS_GSS_ERROR;
     161             :                 }
     162             : 
     163          84 :                 if (major == GSS_S_CONTINUE_NEEDED) {
     164             : 
     165           0 :                         struct dns_request *resp;
     166           0 :                         struct dns_tkey_record *tkey;
     167          42 :                         struct dns_rrec *tkey_answer = NULL;
     168           0 :                         uint16_t i;
     169             : 
     170          42 :                         err = dns_receive(mem_ctx, conn, &buf);
     171          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     172             : 
     173          42 :                         err = dns_unmarshall_request(buf, buf, &resp);
     174          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     175             : 
     176             :                         /*
     177             :                          * TODO: Compare id and keyname
     178             :                          */
     179             : 
     180          84 :                         for (i=0; i < resp->num_answers; i++) {
     181          42 :                                 if (resp->answers[i]->type != QTYPE_TKEY) {
     182           0 :                                         continue;
     183             :                                 }
     184             : 
     185          42 :                                 tkey_answer = resp->answers[i];
     186             :                         }
     187             : 
     188          42 :                         if (tkey_answer == NULL) {
     189           0 :                                 err = ERROR_DNS_INVALID_MESSAGE;
     190           0 :                                 goto error;
     191             :                         }
     192             : 
     193          42 :                         err = dns_unmarshall_tkey_record(
     194          42 :                                 mem_ctx, resp->answers[0], &tkey);
     195          42 :                         if (!ERR_DNS_IS_OK(err)) goto error;
     196             : 
     197          42 :                         input_desc.length = tkey->key_length;
     198          42 :                         input_desc.value = talloc_move(mem_ctx, &tkey->key);
     199             : 
     200          42 :                         input_ptr = &input_desc;
     201             : 
     202          42 :                         TALLOC_FREE(buf);
     203             :                 }
     204             : 
     205          84 :         } while ( major == GSS_S_CONTINUE_NEEDED );
     206             : 
     207             :         /* If we arrive here, we have a valid security context */
     208             : 
     209          42 :         err = ERROR_DNS_SUCCESS;
     210             : 
     211          42 :       error:
     212             : 
     213          42 :         TALLOC_FREE(buf);
     214          42 :         TALLOC_FREE(req);
     215          42 :         return err;
     216             : }
     217             : 
     218          42 : DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
     219             :                                  const char *servername,
     220             :                                  const char *keyname,
     221             :                                  gss_ctx_id_t *gss_ctx,
     222             :                                  enum dns_ServerType srv_type )
     223             : {
     224           0 :         OM_uint32 major, minor;
     225             : 
     226           0 :         char *upcaserealm, *targetname;
     227           0 :         DNS_ERROR err;
     228             : 
     229           0 :         gss_buffer_desc input_name;
     230           0 :         struct dns_connection *conn;
     231             : 
     232           0 :         gss_name_t targ_name;
     233             : 
     234          42 :         gss_OID_desc nt_host_oid_desc =
     235             :                 {10, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
     236             : 
     237           0 :         TALLOC_CTX *mem_ctx;
     238             : 
     239          42 :         if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
     240           0 :                 return ERROR_DNS_NO_MEMORY;
     241             :         }
     242             : 
     243          42 :         err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
     244          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     245             : 
     246          42 :         if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
     247           0 :                 err = ERROR_DNS_NO_MEMORY;
     248           0 :                 goto error;
     249             :         }
     250             : 
     251          42 :         strupr(upcaserealm);
     252             : 
     253          42 :         if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
     254             :                                            servername, upcaserealm))) {
     255           0 :                 err = ERROR_DNS_NO_MEMORY;
     256           0 :                 goto error;
     257             :         }
     258             : 
     259          42 :         input_name.value = targetname;
     260          42 :         input_name.length = strlen(targetname);
     261             : 
     262          42 :         major = gss_import_name( &minor, &input_name,
     263             :                                  &nt_host_oid_desc, &targ_name );
     264             : 
     265          42 :         if (major) {
     266           0 :                 err = ERROR_DNS_GSS_ERROR;
     267           0 :                 goto error;
     268             :         }
     269             : 
     270          42 :         err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname, 
     271             :                                         targ_name, gss_ctx, srv_type );
     272             :         
     273          42 :         gss_release_name( &minor, &targ_name );
     274             : 
     275          42 :  error:
     276          42 :         TALLOC_FREE(mem_ctx);
     277             : 
     278          42 :         return err;
     279             : }
     280             : 
     281          42 : DNS_ERROR dns_sign_update(struct dns_update_request *req,
     282             :                           gss_ctx_id_t gss_ctx,
     283             :                           const char *keyname,
     284             :                           const char *algorithmname,
     285             :                           time_t time_signed, uint16_t fudge)
     286             : {
     287           0 :         struct dns_buffer *buf;
     288           0 :         DNS_ERROR err;
     289           0 :         struct dns_domain_name *key, *algorithm;
     290           0 :         struct gss_buffer_desc_struct msg, mic;
     291           0 :         OM_uint32 major, minor;
     292           0 :         struct dns_rrec *rec;
     293             : 
     294          42 :         err = dns_marshall_update_request(req, req, &buf);
     295          42 :         if (!ERR_DNS_IS_OK(err)) return err;
     296             : 
     297          42 :         err = dns_domain_name_from_string(buf, keyname, &key);
     298          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     299             : 
     300          42 :         err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
     301          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     302             : 
     303          42 :         dns_marshall_domain_name(buf, key);
     304          42 :         dns_marshall_uint16(buf, DNS_CLASS_ANY);
     305          42 :         dns_marshall_uint32(buf, 0); /* TTL */
     306          42 :         dns_marshall_domain_name(buf, algorithm);
     307          42 :         dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
     308          42 :         dns_marshall_uint32(buf, time_signed);
     309          42 :         dns_marshall_uint16(buf, fudge);
     310          42 :         dns_marshall_uint16(buf, 0); /* error */
     311          42 :         dns_marshall_uint16(buf, 0); /* other len */
     312             : 
     313          42 :         err = buf->error;
     314          42 :         if (!ERR_DNS_IS_OK(buf->error)) goto error;
     315             : 
     316          42 :         msg.value = (void *)buf->data;
     317          42 :         msg.length = buf->offset;
     318             : 
     319          42 :         major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
     320          42 :         if (major != 0) {
     321           0 :                 err = ERROR_DNS_GSS_ERROR;
     322           0 :                 goto error;
     323             :         }
     324             : 
     325          42 :         if (mic.length > 0xffff) {
     326           0 :                 gss_release_buffer(&minor, &mic);
     327           0 :                 err = ERROR_DNS_GSS_ERROR;
     328           0 :                 goto error;
     329             :         }
     330             : 
     331          42 :         err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
     332          42 :                                      fudge, mic.length, (uint8_t *)mic.value,
     333          42 :                                      req->id, 0, &rec);
     334          42 :         gss_release_buffer(&minor, &mic);
     335          42 :         if (!ERR_DNS_IS_OK(err)) goto error;
     336             : 
     337          42 :         err = dns_add_rrec(req, rec, &req->num_additionals, &req->additional);
     338             : 
     339          42 :  error:
     340          42 :         TALLOC_FREE(buf);
     341          42 :         return err;
     342             : }
     343             : 
     344             : #endif  /* HAVE_GSSAPI */

Generated by: LCOV version 1.14