root/source3/libaddns/dnsgss.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. strupr
  2. display_status_1
  3. display_status
  4. dns_negotiate_gss_ctx_int
  5. dns_negotiate_sec_ctx
  6. dns_sign_update

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

/* [<][>][^][v][top][bottom][index][help] */