Coverage Report

Created: 2026-08-31 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/gssapictx.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <ctype.h>
15
#include <inttypes.h>
16
#include <stdbool.h>
17
#include <stdlib.h>
18
#include <string.h>
19
#include <time.h>
20
21
#if HAVE_GSSAPI_GSSAPI_H
22
#include <gssapi/gssapi.h>
23
#elif HAVE_GSSAPI_H
24
#include <gssapi.h>
25
#endif
26
27
#if HAVE_GSSAPI_GSSAPI_KRB5_H
28
#include <gssapi/gssapi_krb5.h>
29
#elif HAVE_GSSAPI_KRB5_H
30
#include <gssapi_krb5.h>
31
#endif
32
33
#if HAVE_KRB5_KRB5_H
34
#include <krb5/krb5.h>
35
#elif HAVE_KRB5_H
36
#include <krb5.h>
37
#endif
38
39
#include <isc/buffer.h>
40
#include <isc/dir.h>
41
#include <isc/file.h>
42
#include <isc/lex.h>
43
#include <isc/log.h>
44
#include <isc/mem.h>
45
#include <isc/once.h>
46
#include <isc/random.h>
47
#include <isc/result.h>
48
#include <isc/string.h>
49
#include <isc/time.h>
50
#include <isc/util.h>
51
52
#include <dns/fixedname.h>
53
#include <dns/keyvalues.h>
54
#include <dns/rdata.h>
55
#include <dns/rdataclass.h>
56
#include <dns/types.h>
57
58
#include <dst/gssapi.h>
59
60
#include "dst_internal.h"
61
62
#if HAVE_GSSAPI
63
64
#ifndef GSS_SPNEGO_MECHANISM
65
static unsigned char spnego_mech_oid_bytes[] = { 0x2b, 0x06, 0x01,
66
             0x05, 0x05, 0x02 };
67
static gss_OID_desc __gss_spnego_mechanism_oid_desc = {
68
  sizeof(spnego_mech_oid_bytes), spnego_mech_oid_bytes
69
};
70
#define GSS_SPNEGO_MECHANISM (&__gss_spnego_mechanism_oid_desc)
71
#endif /* ifndef GSS_SPNEGO_MECHANISM */
72
73
#define REGION_TO_GBUFFER(r, gb)          \
74
  do {                              \
75
    (gb).length = (r).length; \
76
    (gb).value = (r).base;    \
77
  } while (0)
78
79
#define GBUFFER_TO_REGION(gb, r)                        \
80
  do {                                            \
81
    (r).length = (unsigned int)(gb).length; \
82
    (r).base = (gb).value;                  \
83
  } while (0)
84
85
static void
86
name_to_gbuffer(const dns_name_t *name, isc_buffer_t *buffer,
87
    gss_buffer_desc *gbuffer) {
88
  dns_name_t tname;
89
  const dns_name_t *namep;
90
  isc_region_t r;
91
  isc_result_t result;
92
93
  if (!dns_name_isabsolute(name)) {
94
    namep = name;
95
  } else {
96
    unsigned int labels;
97
    dns_name_init(&tname);
98
    labels = dns_name_countlabels(name);
99
    dns_name_getlabelsequence(name, 0, labels - 1, &tname);
100
    namep = &tname;
101
  }
102
103
  result = dns_name_totext(
104
    namep, DNS_NAME_OMITFINALDOT | DNS_NAME_PRINCIPAL, buffer);
105
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
106
  isc_buffer_putuint8(buffer, 0);
107
  isc_buffer_usedregion(buffer, &r);
108
  REGION_TO_GBUFFER(r, *gbuffer);
109
}
110
111
bool
112
dst_gssapi_identitymatchesrealmkrb5(const dns_name_t *signer,
113
            const dns_name_t *name,
114
            const dns_name_t *realm, bool subdomain) {
115
  char sbuf[DNS_NAME_FORMATSIZE];
116
  char rbuf[DNS_NAME_FORMATSIZE];
117
  char *sname;
118
  char *rname;
119
  isc_buffer_t buffer;
120
  isc_result_t result;
121
122
  /*
123
   * It is far, far easier to write the names we are looking at into
124
   * a string, and do string operations on them.
125
   */
126
  isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
127
  result = dns_name_totext(
128
    signer, DNS_NAME_OMITFINALDOT | DNS_NAME_PRINCIPAL, &buffer);
129
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
130
  isc_buffer_putuint8(&buffer, 0);
131
  dns_name_format(realm, rbuf, sizeof(rbuf));
132
133
  /*
134
   * Find the realm portion.  This is the part after the @.  If it
135
   * does not exist, we don't have something we like, so we fail our
136
   * compare.
137
   */
138
  rname = strchr(sbuf, '@');
139
  if (rname == NULL) {
140
    return false;
141
  }
142
  *rname = '\0';
143
  rname++;
144
145
  if (strcmp(rname, rbuf) != 0) {
146
    return false;
147
  }
148
149
  /*
150
   * Find the host portion of the signer's name.  We do this by
151
   * searching for the first / character.  We then check to make
152
   * certain the instance name is "host"
153
   *
154
   * This will work for
155
   *    host/example.com@EXAMPLE.COM
156
   */
157
  sname = strchr(sbuf, '/');
158
  if (sname == NULL) {
159
    return false;
160
  }
161
  *sname = '\0';
162
  sname++;
163
  if (strcmp(sbuf, "host") != 0) {
164
    return false;
165
  }
166
167
  /*
168
   * If name is non NULL check that it matches against the
169
   * machine name as expected.
170
   */
171
  if (name != NULL) {
172
    dns_fixedname_t fixed;
173
    dns_name_t *machine;
174
175
    machine = dns_fixedname_initname(&fixed);
176
    result = dns_name_fromstring(machine, sname, dns_rootname, 0,
177
               NULL);
178
    if (result != ISC_R_SUCCESS) {
179
      return false;
180
    }
181
    if (subdomain) {
182
      return dns_name_issubdomain(name, machine);
183
    }
184
    return dns_name_equal(name, machine);
185
  }
186
187
  return true;
188
}
189
190
bool
191
dst_gssapi_identitymatchesrealmms(const dns_name_t *signer,
192
          const dns_name_t *name,
193
          const dns_name_t *realm, bool subdomain) {
194
  char sbuf[DNS_NAME_FORMATSIZE];
195
  char rbuf[DNS_NAME_FORMATSIZE];
196
  char *sname;
197
  char *rname;
198
  isc_buffer_t buffer;
199
  isc_result_t result;
200
201
  /*
202
   * It is far, far easier to write the names we are looking at into
203
   * a string, and do string operations on them.
204
   */
205
  isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
206
  result = dns_name_totext(
207
    signer, DNS_NAME_OMITFINALDOT | DNS_NAME_PRINCIPAL, &buffer);
208
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
209
  isc_buffer_putuint8(&buffer, 0);
210
  dns_name_format(realm, rbuf, sizeof(rbuf));
211
212
  /*
213
   * Find the realm portion.  This is the part after the @.  If it
214
   * does not exist, we don't have something we like, so we fail our
215
   * compare.
216
   */
217
  rname = strchr(sbuf, '@');
218
  if (rname == NULL) {
219
    return false;
220
  }
221
  sname = strchr(sbuf, '$');
222
  if (sname == NULL) {
223
    return false;
224
  }
225
226
  /*
227
   * Verify that the $ and @ follow one another.
228
   */
229
  if (rname - sname != 1) {
230
    return false;
231
  }
232
233
  /*
234
   * Find the host portion of the signer's name.  Zero out the $ so
235
   * it terminates the signer's name, and skip past the @ for
236
   * the realm.
237
   *
238
   * All service principals in Microsoft format seem to be in
239
   *    machinename$@EXAMPLE.COM
240
   * format.
241
   */
242
  rname++;
243
  *sname = '\0';
244
245
  if (strcmp(rname, rbuf) != 0) {
246
    return false;
247
  }
248
249
  /*
250
   * Now, we check that the realm matches (case sensitive) and that
251
   * 'name' matches against 'machinename' qualified with 'realm'.
252
   */
253
  if (name != NULL) {
254
    dns_fixedname_t fixed;
255
    dns_name_t *machine;
256
257
    machine = dns_fixedname_initname(&fixed);
258
    result = dns_name_fromstring(machine, sbuf, realm, 0, NULL);
259
    if (result != ISC_R_SUCCESS) {
260
      return false;
261
    }
262
    if (subdomain) {
263
      return dns_name_issubdomain(name, machine);
264
    }
265
    return dns_name_equal(name, machine);
266
  }
267
268
  return true;
269
}
270
271
/*
272
 * Format a gssapi error message info into a char ** on the given memory
273
 * context. This is used to return gssapi error messages back up the
274
 * call chain for reporting to the user.
275
 */
276
static void
277
gss_err_message(isc_mem_t *mctx, uint32_t major, uint32_t minor,
278
    char **err_message) {
279
  char buf[1024];
280
  char *estr;
281
282
  if (err_message == NULL || mctx == NULL) {
283
    /* the caller doesn't want any error messages */
284
    return;
285
  }
286
287
  estr = gss_error_tostring(major, minor, buf, sizeof(buf));
288
  if (estr != NULL) {
289
    (*err_message) = isc_mem_strdup(mctx, estr);
290
  }
291
}
292
293
isc_result_t
294
dst_gssapi_initctx(const dns_name_t *name, isc_buffer_t *intoken,
295
       isc_buffer_t *outtoken, dns_gss_ctx_id_t *gssctx,
296
       isc_mem_t *mctx, char **err_message) {
297
  isc_region_t r;
298
  isc_buffer_t namebuf;
299
  gss_name_t gname = NULL;
300
  OM_uint32 gret, minor, ret_flags, flags;
301
  gss_buffer_desc gintoken, *gintokenp, gouttoken = GSS_C_EMPTY_BUFFER;
302
  isc_result_t result;
303
  gss_buffer_desc gnamebuf;
304
  unsigned char array[DNS_NAME_MAXTEXT + 1];
305
306
  /* Client must pass us a valid gss_ctx_id_t here */
307
  REQUIRE(gssctx != NULL);
308
  REQUIRE(mctx != NULL);
309
310
  isc_buffer_init(&namebuf, array, sizeof(array));
311
  name_to_gbuffer(name, &namebuf, &gnamebuf);
312
313
  /* Get the name as a GSS name */
314
  gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
315
  if (gret != GSS_S_COMPLETE) {
316
    gss_err_message(mctx, gret, minor, err_message);
317
    CLEANUP(ISC_R_FAILURE);
318
  }
319
320
  if (intoken != NULL) {
321
    /* Don't call gss_release_buffer for gintoken! */
322
    REGION_TO_GBUFFER(*intoken, gintoken);
323
    gintokenp = &gintoken;
324
  } else {
325
    gintokenp = NULL;
326
  }
327
328
  /*
329
   * Note that we don't set GSS_C_SEQUENCE_FLAG as Windows DNS
330
   * servers don't like it.
331
   */
332
  flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
333
334
  gret = gss_init_sec_context(
335
    &minor, GSS_C_NO_CREDENTIAL, (gss_ctx_id_t *)gssctx, gname,
336
    GSS_SPNEGO_MECHANISM, flags, 0, NULL, gintokenp, NULL,
337
    &gouttoken, &ret_flags, NULL);
338
339
  switch (gret) {
340
  case GSS_S_COMPLETE:
341
    result = ISC_R_SUCCESS;
342
    break;
343
  case GSS_S_CONTINUE_NEEDED:
344
    result = DNS_R_CONTINUE;
345
    break;
346
  default:
347
    gss_err_message(mctx, gret, minor, err_message);
348
    if (err_message != NULL && *err_message != NULL) {
349
      gss_log(3, "Failure initiating security context: %s",
350
        *err_message);
351
    } else {
352
      gss_log(3, "Failure initiating security context");
353
    }
354
355
    CLEANUP(ISC_R_FAILURE);
356
  }
357
358
  /*
359
   * RFC 3645 Section 3.1.1: verify that replay detection, mutual
360
   * authentication and integrity are supported.  The RFC mandates
361
   * checking replay_det_state and mutual_state; integ_avail is
362
   * also verified because GSS-TSIG cannot function without it.
363
   */
364
  if (gret == GSS_S_COMPLETE &&
365
      (ret_flags &
366
       (GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG)) !=
367
        (GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG))
368
  {
369
    gss_log(3,
370
      "GSS-API context lacks required REPLAY, MUTUAL, "
371
      "or INTEG flags (ret_flags=0x%x)",
372
      (unsigned int)ret_flags);
373
    CLEANUP(ISC_R_FAILURE);
374
  }
375
376
  /*
377
   * RFC 2744 states the a valid output token has a non-zero length.
378
   */
379
  if (gouttoken.length != 0U) {
380
    GBUFFER_TO_REGION(gouttoken, r);
381
    CHECK(isc_buffer_copyregion(outtoken, &r));
382
  }
383
384
cleanup:
385
  if (gouttoken.length != 0U) {
386
    (void)gss_release_buffer(&minor, &gouttoken);
387
  }
388
  if (gname != NULL) {
389
    (void)gss_release_name(&minor, &gname);
390
  }
391
  return result;
392
}
393
394
isc_result_t
395
dst_gssapi_acceptctx(const char *gssapi_keytab, isc_region_t *intoken,
396
         isc_buffer_t **outtokenp, dns_gss_ctx_id_t *ctxout,
397
         dns_name_t *principal, isc_mem_t *mctx) {
398
  isc_region_t r;
399
  isc_buffer_t namebuf;
400
  gss_buffer_desc gnamebuf = GSS_C_EMPTY_BUFFER, gintoken,
401
      gouttoken = GSS_C_EMPTY_BUFFER;
402
  OM_uint32 gret, minor;
403
  gss_ctx_id_t context = GSS_C_NO_CONTEXT;
404
  gss_name_t gname = NULL;
405
  isc_result_t result;
406
  char buf[1024];
407
408
  REQUIRE(outtokenp != NULL && *outtokenp == NULL);
409
  REQUIRE(*ctxout == NULL);
410
411
  REGION_TO_GBUFFER(*intoken, gintoken);
412
413
  if (gssapi_keytab != NULL) {
414
#if HAVE_GSSAPI_GSSAPI_KRB5_H || HAVE_GSSAPI_KRB5_H
415
    gret = gsskrb5_register_acceptor_identity(gssapi_keytab);
416
    if (gret != GSS_S_COMPLETE) {
417
      gss_log(3,
418
        "failed "
419
        "gsskrb5_register_acceptor_identity(%s): %s",
420
        gssapi_keytab,
421
        gss_error_tostring(gret, 0, buf, sizeof(buf)));
422
      return DNS_R_INVALIDTKEY;
423
    }
424
#else
425
    /*
426
     * Minimize memory leakage by only setting KRB5_KTNAME
427
     * if it needs to change.
428
     */
429
    const char *old = getenv("KRB5_KTNAME");
430
    if (old == NULL || strcmp(old, gssapi_keytab) != 0) {
431
      size_t size;
432
      char *kt;
433
434
      size = strlen(gssapi_keytab) + 13;
435
      kt = malloc(size);
436
      if (kt == NULL) {
437
        return ISC_R_NOMEMORY;
438
      }
439
      snprintf(kt, size, "KRB5_KTNAME=%s", gssapi_keytab);
440
      if (putenv(kt) != 0) {
441
        return ISC_R_NOMEMORY;
442
      }
443
    }
444
#endif
445
  }
446
447
  OM_uint32 ret_flags = 0;
448
449
  gret = gss_accept_sec_context(&minor, &context, GSS_C_NO_CREDENTIAL,
450
              &gintoken, GSS_C_NO_CHANNEL_BINDINGS,
451
              &gname, NULL, &gouttoken, &ret_flags,
452
              NULL, NULL);
453
454
  result = ISC_R_FAILURE;
455
456
  switch (gret) {
457
  case GSS_S_COMPLETE:
458
    /*
459
     * RFC 2743 Section 1.2.2: verify that the negotiated
460
     * context provides integrity protection.
461
     */
462
    if ((ret_flags & GSS_C_INTEG_FLAG) == 0) {
463
      gss_log(3,
464
        "GSS-API context lacks required INTEG "
465
        "flag (ret_flags=0x%x)",
466
        (unsigned int)ret_flags);
467
      (void)gss_delete_sec_context(&minor, &context, NULL);
468
      result = DNS_R_INVALIDTKEY;
469
      goto cleanup;
470
    }
471
    break;
472
  /*
473
   * RFC 3645 4.1.3: we don't handle GSS_S_CONTINUE_NEEDED
474
   * Multi-round GSS-API negotiation is not supported.
475
   */
476
  case GSS_S_CONTINUE_NEEDED:
477
    gss_log(3, "multi-round GSS-API negotiation not supported");
478
    (void)gss_delete_sec_context(&minor, &context, NULL);
479
    FALLTHROUGH;
480
  case GSS_S_DEFECTIVE_TOKEN:
481
  case GSS_S_DEFECTIVE_CREDENTIAL:
482
  case GSS_S_BAD_SIG:
483
  case GSS_S_DUPLICATE_TOKEN:
484
  case GSS_S_OLD_TOKEN:
485
  case GSS_S_NO_CRED:
486
  case GSS_S_CREDENTIALS_EXPIRED:
487
  case GSS_S_BAD_BINDINGS:
488
  case GSS_S_NO_CONTEXT:
489
  case GSS_S_BAD_MECH:
490
  case GSS_S_FAILURE:
491
    result = DNS_R_INVALIDTKEY;
492
    FALLTHROUGH;
493
  default:
494
    gss_log(3, "failed gss_accept_sec_context: %s",
495
      gss_error_tostring(gret, minor, buf, sizeof(buf)));
496
    if (gouttoken.length > 0U) {
497
      (void)gss_release_buffer(&minor, &gouttoken);
498
    }
499
    return result;
500
  }
501
502
  if (gouttoken.length > 0U) {
503
    isc_buffer_allocate(mctx, outtokenp,
504
            (unsigned int)gouttoken.length);
505
    GBUFFER_TO_REGION(gouttoken, r);
506
    CHECK(isc_buffer_copyregion(*outtokenp, &r));
507
    (void)gss_release_buffer(&minor, &gouttoken);
508
  }
509
510
  INSIST(gret == GSS_S_COMPLETE);
511
512
  gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
513
  if (gret != GSS_S_COMPLETE) {
514
    gss_log(3, "failed gss_display_name: %s",
515
      gss_error_tostring(gret, minor, buf, sizeof(buf)));
516
    CLEANUP(ISC_R_FAILURE);
517
  }
518
519
  /*
520
   * Compensate for a bug in Solaris8's implementation
521
   * of gss_display_name().  Should be harmless in any
522
   * case, since principal names really should not
523
   * contain null characters.
524
   */
525
  if (gnamebuf.length > 0U &&
526
      ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
527
  {
528
    gnamebuf.length--;
529
  }
530
531
  gss_log(3, "gss-api source name (accept) is %.*s", (int)gnamebuf.length,
532
    (char *)gnamebuf.value);
533
534
  GBUFFER_TO_REGION(gnamebuf, r);
535
  isc_buffer_init(&namebuf, r.base, r.length);
536
  isc_buffer_add(&namebuf, r.length);
537
538
  CHECK(dns_name_fromtext(principal, &namebuf, dns_rootname, 0));
539
540
  *ctxout = context;
541
542
cleanup:
543
  if (result != ISC_R_SUCCESS && *outtokenp != NULL) {
544
    isc_buffer_free(outtokenp);
545
  }
546
547
  if (result != ISC_R_SUCCESS && context != GSS_C_NO_CONTEXT) {
548
    (void)gss_delete_sec_context(&minor, &context, NULL);
549
  }
550
551
  if (gnamebuf.length != 0U) {
552
    gret = gss_release_buffer(&minor, &gnamebuf);
553
    if (gret != GSS_S_COMPLETE) {
554
      gss_log(3, "failed gss_release_buffer: %s",
555
        gss_error_tostring(gret, minor, buf,
556
               sizeof(buf)));
557
    }
558
  }
559
560
  if (gname != NULL) {
561
    gret = gss_release_name(&minor, &gname);
562
    if (gret != GSS_S_COMPLETE) {
563
      gss_log(3, "failed gss_release_name: %s",
564
        gss_error_tostring(gret, minor, buf,
565
               sizeof(buf)));
566
    }
567
  }
568
569
  return result;
570
}
571
572
isc_result_t
573
dst_gssapi_deletectx(isc_mem_t *mctx, dns_gss_ctx_id_t *gssctx) {
574
  OM_uint32 gret, minor;
575
  char buf[1024];
576
577
  UNUSED(mctx);
578
579
  REQUIRE(gssctx != NULL && *gssctx != NULL);
580
581
  /* Delete the context from the GSS provider */
582
  gret = gss_delete_sec_context(&minor, (gss_ctx_id_t *)gssctx,
583
              GSS_C_NO_BUFFER);
584
  if (gret != GSS_S_COMPLETE) {
585
    /* Log the error, but still free the context's memory */
586
    gss_log(3, "Failure deleting security context %s",
587
      gss_error_tostring(gret, minor, buf, sizeof(buf)));
588
  }
589
  return ISC_R_SUCCESS;
590
}
591
592
char *
593
gss_error_tostring(uint32_t major, uint32_t minor, char *buf, size_t buflen) {
594
  gss_buffer_desc msg_minor = GSS_C_EMPTY_BUFFER,
595
      msg_major = GSS_C_EMPTY_BUFFER;
596
  OM_uint32 msg_ctx, minor_stat;
597
598
  /* Handle major status */
599
  msg_ctx = 0;
600
  (void)gss_display_status(&minor_stat, major, GSS_C_GSS_CODE,
601
         GSS_C_NULL_OID, &msg_ctx, &msg_major);
602
603
  /* Handle minor status */
604
  msg_ctx = 0;
605
  (void)gss_display_status(&minor_stat, minor, GSS_C_MECH_CODE,
606
         GSS_C_NULL_OID, &msg_ctx, &msg_minor);
607
608
  snprintf(buf, buflen, "GSSAPI error: Major = %s, Minor = %s.",
609
     (char *)msg_major.value, (char *)msg_minor.value);
610
611
  if (msg_major.length != 0U) {
612
    (void)gss_release_buffer(&minor_stat, &msg_major);
613
  }
614
  if (msg_minor.length != 0U) {
615
    (void)gss_release_buffer(&minor_stat, &msg_minor);
616
  }
617
  return buf;
618
}
619
620
#else
621
622
bool
623
dst_gssapi_identitymatchesrealmkrb5(const dns_name_t *signer,
624
            const dns_name_t *name,
625
0
            const dns_name_t *realm, bool subdomain) {
626
0
  UNUSED(signer);
627
0
  UNUSED(name);
628
0
  UNUSED(realm);
629
0
  UNUSED(subdomain);
630
631
0
  return false;
632
0
}
633
634
bool
635
dst_gssapi_identitymatchesrealmms(const dns_name_t *signer,
636
          const dns_name_t *name,
637
0
          const dns_name_t *realm, bool subdomain) {
638
0
  UNUSED(signer);
639
0
  UNUSED(name);
640
0
  UNUSED(realm);
641
0
  UNUSED(subdomain);
642
643
0
  return false;
644
0
}
645
646
isc_result_t
647
dst_gssapi_initctx(const dns_name_t *name, isc_buffer_t *intoken,
648
       isc_buffer_t *outtoken, dns_gss_ctx_id_t *gssctx,
649
0
       isc_mem_t *mctx, char **err_message) {
650
0
  UNUSED(name);
651
0
  UNUSED(intoken);
652
0
  UNUSED(outtoken);
653
0
  UNUSED(gssctx);
654
0
  UNUSED(mctx);
655
0
  UNUSED(err_message);
656
657
0
  return ISC_R_NOTIMPLEMENTED;
658
0
}
659
660
isc_result_t
661
dst_gssapi_acceptctx(const char *gssapi_keytab, isc_region_t *intoken,
662
         isc_buffer_t **outtoken, dns_gss_ctx_id_t *ctxout,
663
0
         dns_name_t *principal, isc_mem_t *mctx) {
664
0
  UNUSED(gssapi_keytab);
665
0
  UNUSED(intoken);
666
0
  UNUSED(outtoken);
667
0
  UNUSED(ctxout);
668
0
  UNUSED(principal);
669
0
  UNUSED(mctx);
670
671
0
  return ISC_R_NOTIMPLEMENTED;
672
0
}
673
674
isc_result_t
675
0
dst_gssapi_deletectx(isc_mem_t *mctx, dns_gss_ctx_id_t *gssctx) {
676
0
  UNUSED(mctx);
677
0
  UNUSED(gssctx);
678
0
  return ISC_R_NOTIMPLEMENTED;
679
0
}
680
681
char *
682
0
gss_error_tostring(uint32_t major, uint32_t minor, char *buf, size_t buflen) {
683
0
  snprintf(buf, buflen, "GSSAPI error: Major = %u, Minor = %u.", major,
684
0
     minor);
685
686
0
  return buf;
687
0
}
688
689
#endif
690
691
void
692
0
gss_log(int level, const char *fmt, ...) {
693
0
  va_list ap;
694
695
0
  va_start(ap, fmt);
696
0
  isc_log_vwrite(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_TKEY,
697
0
           ISC_LOG_DEBUG(level), fmt, ap);
698
  va_end(ap);
699
0
}