1 /* $NetBSD: gssapictx.c,v 1.8 2014/12/10 04:37:58 christos Exp $ */
4 * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: gssapictx.c,v 1.29 2011/08/29 06:33:25 marka Exp */
28 #include <isc/buffer.h>
30 #include <isc/entropy.h>
35 #include <isc/print.h>
36 #include <isc/platform.h>
37 #include <isc/random.h>
38 #include <isc/string.h>
42 #include <dns/fixedname.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataclass.h>
46 #include <dns/result.h>
47 #include <dns/types.h>
48 #include <dns/keyvalues.h>
51 #include <dst/gssapi.h>
52 #include <dst/result.h>
54 #include "dst_internal.h"
57 * If we're using our own SPNEGO implementation (see configure.in),
58 * pull it in now. Otherwise, we just use whatever GSSAPI supplies.
60 #if defined(GSSAPI) && defined(USE_ISC_SPNEGO)
62 #define gss_accept_sec_context gss_accept_sec_context_spnego
63 #define gss_init_sec_context gss_init_sec_context_spnego
67 * Solaris8 apparently needs an explicit OID set, and Solaris10 needs
68 * one for anything but Kerberos. Supplying an explicit OID set
69 * doesn't appear to hurt anything in other implementations, so we
70 * always use one. If we're not using our own SPNEGO implementation,
71 * we include SPNEGO's OID.
75 #include <krb5/krb5.h>
77 #include ISC_PLATFORM_KRB5HEADER
80 static unsigned char krb5_mech_oid_bytes
[] = {
81 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
84 #ifndef USE_ISC_SPNEGO
85 static unsigned char spnego_mech_oid_bytes
[] = {
86 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
90 static gss_OID_desc mech_oid_set_array
[] = {
91 { sizeof(krb5_mech_oid_bytes
), krb5_mech_oid_bytes
},
92 #ifndef USE_ISC_SPNEGO
93 { sizeof(spnego_mech_oid_bytes
), spnego_mech_oid_bytes
},
97 static gss_OID_set_desc mech_oid_set
= {
98 sizeof(mech_oid_set_array
) / sizeof(*mech_oid_set_array
),
104 #define REGION_TO_GBUFFER(r, gb) \
106 (gb).length = (r).length; \
107 (gb).value = (r).base; \
108 } while (/*CONSTCOND*/0)
110 #define GBUFFER_TO_REGION(gb, r) \
112 (r).length = (unsigned int)(gb).length; \
113 (r).base = (gb).value; \
114 } while (/*CONSTCOND*/0)
117 #define RETERR(x) do { \
119 if (result != ISC_R_SUCCESS) \
121 } while (/*CONSTCOND*/0)
125 name_to_gbuffer(dns_name_t
*name
, isc_buffer_t
*buffer
,
126 gss_buffer_desc
*gbuffer
)
128 dns_name_t tname
, *namep
;
132 if (!dns_name_isabsolute(name
))
137 dns_name_init(&tname
, NULL
);
138 labels
= dns_name_countlabels(name
);
139 dns_name_getlabelsequence(name
, 0, labels
- 1, &tname
);
143 result
= dns_name_toprincipal(namep
, buffer
);
144 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
145 isc_buffer_putuint8(buffer
, 0);
146 isc_buffer_usedregion(buffer
, &r
);
147 REGION_TO_GBUFFER(r
, *gbuffer
);
151 log_cred(const gss_cred_id_t cred
) {
152 OM_uint32 gret
, minor
, lifetime
;
154 gss_buffer_desc gbuffer
;
155 gss_cred_usage_t usage
;
156 const char *usage_text
;
159 gret
= gss_inquire_cred(&minor
, cred
, &gname
, &lifetime
, &usage
, NULL
);
160 if (gret
!= GSS_S_COMPLETE
) {
161 gss_log(3, "failed gss_inquire_cred: %s",
162 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
166 gret
= gss_display_name(&minor
, gname
, &gbuffer
, NULL
);
167 if (gret
!= GSS_S_COMPLETE
)
168 gss_log(3, "failed gss_display_name: %s",
169 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
173 usage_text
= "GSS_C_BOTH";
176 usage_text
= "GSS_C_INITIATE";
179 usage_text
= "GSS_C_ACCEPT";
184 gss_log(3, "gss cred: \"%s\", %s, %lu", (char *)gbuffer
.value
,
185 usage_text
, (unsigned long)lifetime
);
188 if (gret
== GSS_S_COMPLETE
) {
189 if (gbuffer
.length
!= 0U) {
190 gret
= gss_release_buffer(&minor
, &gbuffer
);
191 if (gret
!= GSS_S_COMPLETE
)
192 gss_log(3, "failed gss_release_buffer: %s",
193 gss_error_tostring(gret
, minor
, buf
,
198 gret
= gss_release_name(&minor
, &gname
);
199 if (gret
!= GSS_S_COMPLETE
)
200 gss_log(3, "failed gss_release_name: %s",
201 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
207 * check for the most common configuration errors.
209 * The errors checked for are:
210 * - tkey-gssapi-credential doesn't start with DNS/
211 * - the default realm in /etc/krb5.conf and the
212 * tkey-gssapi-credential bind config option don't match
214 * Note that if tkey-gssapi-keytab is set then these configure checks
215 * are not performed, and runtime errors from gssapi are used instead
218 check_config(const char *gss_name
) {
220 krb5_context krb5_ctx
;
221 char *krb5_realm
= NULL
;
223 if (strncasecmp(gss_name
, "DNS/", 4) != 0) {
224 gss_log(ISC_LOG_ERROR
, "tkey-gssapi-credential (%s) "
225 "should start with 'DNS/'", gss_name
);
229 if (krb5_init_context(&krb5_ctx
) != 0) {
230 gss_log(ISC_LOG_ERROR
, "Unable to initialise krb5 context");
233 if (krb5_get_default_realm(krb5_ctx
, &krb5_realm
) != 0) {
234 gss_log(ISC_LOG_ERROR
, "Unable to get krb5 default realm");
235 krb5_free_context(krb5_ctx
);
238 p
= strchr(gss_name
, '@');
240 gss_log(ISC_LOG_ERROR
, "badly formatted "
241 "tkey-gssapi-credentials (%s)", gss_name
);
242 krb5_free_context(krb5_ctx
);
245 if (strcasecmp(p
+ 1, krb5_realm
) != 0) {
246 gss_log(ISC_LOG_ERROR
, "default realm from krb5.conf (%s) "
247 "does not match tkey-gssapi-credential (%s)",
248 krb5_realm
, gss_name
);
249 krb5_free_context(krb5_ctx
);
252 krb5_free_context(krb5_ctx
);
257 dst_gssapi_acquirecred(dns_name_t
*name
, isc_boolean_t initiate
,
262 isc_buffer_t namebuf
;
264 gss_buffer_desc gnamebuf
;
265 unsigned char array
[DNS_NAME_MAXTEXT
+ 1];
266 OM_uint32 gret
, minor
;
268 gss_cred_usage_t usage
;
271 REQUIRE(cred
!= NULL
&& *cred
== NULL
);
274 * XXXSRA In theory we could use GSS_C_NT_HOSTBASED_SERVICE
275 * here when we're in the acceptor role, which would let us
276 * default the hostname and use a compiled in default service
277 * name of "DNS", giving one less thing to configure in
278 * named.conf. Unfortunately, this creates a circular
279 * dependency due to DNS-based realm lookup in at least one
280 * GSSAPI implementation (Heimdal). Oh well.
283 isc_buffer_init(&namebuf
, array
, sizeof(array
));
284 name_to_gbuffer(name
, &namebuf
, &gnamebuf
);
285 gret
= gss_import_name(&minor
, &gnamebuf
,
286 GSS_C_NO_OID
, &gname
);
287 if (gret
!= GSS_S_COMPLETE
) {
288 check_config((char *)array
);
290 gss_log(3, "failed gss_import_name: %s",
291 gss_error_tostring(gret
, minor
, buf
,
293 return (ISC_R_FAILURE
);
298 /* Get the credentials. */
300 gss_log(3, "acquiring credentials for %s",
301 (char *)gnamebuf
.value
);
303 /* XXXDCL does this even make any sense? */
304 gss_log(3, "acquiring credentials for ?");
308 usage
= GSS_C_INITIATE
;
310 usage
= GSS_C_ACCEPT
;
312 gret
= gss_acquire_cred(&minor
, gname
, GSS_C_INDEFINITE
,
313 &mech_oid_set
, usage
, cred
, NULL
, &lifetime
);
315 if (gret
!= GSS_S_COMPLETE
) {
316 gss_log(3, "failed to acquire %s credentials for %s: %s",
317 initiate
? "initiate" : "accept",
318 (gname
!= NULL
) ? (char *)gnamebuf
.value
: "?",
319 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
321 check_config((char *)array
);
322 result
= ISC_R_FAILURE
;
326 gss_log(4, "acquired %s credentials for %s",
327 initiate
? "initiate" : "accept",
328 (gname
!= NULL
) ? (char *)gnamebuf
.value
: "?");
331 result
= ISC_R_SUCCESS
;
335 gret
= gss_release_name(&minor
, &gname
);
336 if (gret
!= GSS_S_COMPLETE
)
337 gss_log(3, "failed gss_release_name: %s",
338 gss_error_tostring(gret
, minor
, buf
,
344 REQUIRE(cred
!= NULL
&& *cred
== NULL
);
350 return (ISC_R_NOTIMPLEMENTED
);
355 dst_gssapi_identitymatchesrealmkrb5(dns_name_t
*signer
, dns_name_t
*name
,
359 char sbuf
[DNS_NAME_FORMATSIZE
];
360 char nbuf
[DNS_NAME_FORMATSIZE
];
361 char rbuf
[DNS_NAME_FORMATSIZE
];
368 * It is far, far easier to write the names we are looking at into
369 * a string, and do string operations on them.
371 isc_buffer_init(&buffer
, sbuf
, sizeof(sbuf
));
372 result
= dns_name_toprincipal(signer
, &buffer
);
373 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
374 isc_buffer_putuint8(&buffer
, 0);
376 dns_name_format(name
, nbuf
, sizeof(nbuf
));
377 dns_name_format(realm
, rbuf
, sizeof(rbuf
));
380 * Find the realm portion. This is the part after the @. If it
381 * does not exist, we don't have something we like, so we fail our
384 rname
= strchr(sbuf
, '@');
386 return (isc_boolean_false
);
391 * Find the host portion of the signer's name. We do this by
392 * searching for the first / character. We then check to make
393 * certain the instance name is "host"
396 * host/example.com@EXAMPLE.COM
398 sname
= strchr(sbuf
, '/');
400 return (isc_boolean_false
);
403 if (strcmp(sbuf
, "host") != 0)
404 return (isc_boolean_false
);
407 * Now, we do a simple comparison between the name and the realm.
410 if ((strcasecmp(sname
, nbuf
) == 0)
411 && (strcmp(rname
, rbuf
) == 0))
412 return (isc_boolean_true
);
414 if (strcmp(rname
, rbuf
) == 0)
415 return (isc_boolean_true
);
418 return (isc_boolean_false
);
423 return (isc_boolean_false
);
428 dst_gssapi_identitymatchesrealmms(dns_name_t
*signer
, dns_name_t
*name
,
432 char sbuf
[DNS_NAME_FORMATSIZE
];
433 char nbuf
[DNS_NAME_FORMATSIZE
];
434 char rbuf
[DNS_NAME_FORMATSIZE
];
442 * It is far, far easier to write the names we are looking at into
443 * a string, and do string operations on them.
445 isc_buffer_init(&buffer
, sbuf
, sizeof(sbuf
));
446 result
= dns_name_toprincipal(signer
, &buffer
);
447 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
448 isc_buffer_putuint8(&buffer
, 0);
450 dns_name_format(name
, nbuf
, sizeof(nbuf
));
451 dns_name_format(realm
, rbuf
, sizeof(rbuf
));
454 * Find the realm portion. This is the part after the @. If it
455 * does not exist, we don't have something we like, so we fail our
458 rname
= strchr(sbuf
, '@');
460 return (isc_boolean_false
);
461 sname
= strchr(sbuf
, '$');
463 return (isc_boolean_false
);
466 * Verify that the $ and @ follow one another.
468 if (rname
- sname
!= 1)
469 return (isc_boolean_false
);
472 * Find the host portion of the signer's name. Zero out the $ so
473 * it terminates the signer's name, and skip past the @ for
476 * All service principals in Microsoft format seem to be in
477 * machinename$@EXAMPLE.COM
485 * Find the first . in the target name, and make it the end of
486 * the string. The rest of the name has to match the realm.
489 nname
= strchr(nbuf
, '.');
491 return (isc_boolean_false
);
496 * Now, we do a simple comparison between the name and the realm.
499 if ((strcasecmp(sname
, nbuf
) == 0)
500 && (strcmp(rname
, rbuf
) == 0)
501 && (strcasecmp(nname
, rbuf
) == 0))
502 return (isc_boolean_true
);
504 if (strcmp(rname
, rbuf
) == 0)
505 return (isc_boolean_true
);
509 return (isc_boolean_false
);
514 return (isc_boolean_false
);
519 dst_gssapi_releasecred(gss_cred_id_t
*cred
) {
521 OM_uint32 gret
, minor
;
524 REQUIRE(cred
!= NULL
&& *cred
!= NULL
);
526 gret
= gss_release_cred(&minor
, cred
);
527 if (gret
!= GSS_S_COMPLETE
) {
528 /* Log the error, but still free the credential's memory */
529 gss_log(3, "failed releasing credential: %s",
530 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
534 return(ISC_R_SUCCESS
);
538 return (ISC_R_NOTIMPLEMENTED
);
544 * Format a gssapi error message info into a char ** on the given memory
545 * context. This is used to return gssapi error messages back up the
546 * call chain for reporting to the user.
549 gss_err_message(isc_mem_t
*mctx
, isc_uint32_t major
, isc_uint32_t minor
,
555 if (err_message
== NULL
|| mctx
== NULL
) {
556 /* the caller doesn't want any error messages */
560 estr
= gss_error_tostring(major
, minor
, buf
, sizeof(buf
));
562 (*err_message
) = isc_mem_strdup(mctx
, estr
);
567 dst_gssapi_initctx(dns_name_t
*name
, isc_buffer_t
*intoken
,
568 isc_buffer_t
*outtoken
, gss_ctx_id_t
*gssctx
,
569 isc_mem_t
*mctx
, char **err_message
)
573 isc_buffer_t namebuf
;
575 OM_uint32 gret
, minor
, ret_flags
, flags
;
576 gss_buffer_desc gintoken
, *gintokenp
, gouttoken
= GSS_C_EMPTY_BUFFER
;
578 gss_buffer_desc gnamebuf
;
579 unsigned char array
[DNS_NAME_MAXTEXT
+ 1];
581 /* Client must pass us a valid gss_ctx_id_t here */
582 REQUIRE(gssctx
!= NULL
);
583 REQUIRE(mctx
!= NULL
);
585 isc_buffer_init(&namebuf
, array
, sizeof(array
));
586 name_to_gbuffer(name
, &namebuf
, &gnamebuf
);
588 /* Get the name as a GSS name */
589 gret
= gss_import_name(&minor
, &gnamebuf
, GSS_C_NO_OID
, &gname
);
590 if (gret
!= GSS_S_COMPLETE
) {
591 gss_err_message(mctx
, gret
, minor
, err_message
);
592 result
= ISC_R_FAILURE
;
596 if (intoken
!= NULL
) {
597 /* Don't call gss_release_buffer for gintoken! */
598 REGION_TO_GBUFFER(*intoken
, gintoken
);
599 gintokenp
= &gintoken
;
605 * Note that we don't set GSS_C_SEQUENCE_FLAG as Windows DNS
606 * servers don't like it.
608 flags
= GSS_C_REPLAY_FLAG
| GSS_C_MUTUAL_FLAG
| GSS_C_INTEG_FLAG
;
610 gret
= gss_init_sec_context(&minor
, GSS_C_NO_CREDENTIAL
, gssctx
,
611 gname
, GSS_SPNEGO_MECHANISM
, flags
,
613 NULL
, &gouttoken
, &ret_flags
, NULL
);
615 if (gret
!= GSS_S_COMPLETE
&& gret
!= GSS_S_CONTINUE_NEEDED
) {
616 gss_err_message(mctx
, gret
, minor
, err_message
);
617 if (err_message
!= NULL
&& *err_message
!= NULL
)
618 gss_log(3, "Failure initiating security context: %s",
621 gss_log(3, "Failure initiating security context");
623 result
= ISC_R_FAILURE
;
628 * XXXSRA Not handled yet: RFC 3645 3.1.1: check ret_flags
629 * MUTUAL and INTEG flags, fail if either not set.
633 * RFC 2744 states the a valid output token has a non-zero length.
635 if (gouttoken
.length
!= 0U) {
636 GBUFFER_TO_REGION(gouttoken
, r
);
637 RETERR(isc_buffer_copyregion(outtoken
, &r
));
638 (void)gss_release_buffer(&minor
, &gouttoken
);
641 if (gret
== GSS_S_COMPLETE
)
642 result
= ISC_R_SUCCESS
;
644 result
= DNS_R_CONTINUE
;
647 (void)gss_release_name(&minor
, &gname
);
657 return (ISC_R_NOTIMPLEMENTED
);
662 dst_gssapi_acceptctx(gss_cred_id_t cred
,
663 const char *gssapi_keytab
,
664 isc_region_t
*intoken
, isc_buffer_t
**outtoken
,
665 gss_ctx_id_t
*ctxout
, dns_name_t
*principal
,
670 isc_buffer_t namebuf
;
671 gss_buffer_desc gnamebuf
= GSS_C_EMPTY_BUFFER
, gintoken
,
672 gouttoken
= GSS_C_EMPTY_BUFFER
;
673 OM_uint32 gret
, minor
;
674 gss_ctx_id_t context
= GSS_C_NO_CONTEXT
;
675 gss_name_t gname
= NULL
;
679 REQUIRE(outtoken
!= NULL
&& *outtoken
== NULL
);
681 REGION_TO_GBUFFER(*intoken
, gintoken
);
684 context
= GSS_C_NO_CONTEXT
;
688 if (gssapi_keytab
!= NULL
) {
689 #if defined(ISC_PLATFORM_GSSAPI_KRB5_HEADER) || defined(WIN32)
690 gret
= gsskrb5_register_acceptor_identity(gssapi_keytab
);
691 if (gret
!= GSS_S_COMPLETE
) {
693 "gsskrb5_register_acceptor_identity(%s): %s",
695 gss_error_tostring(gret
, 0, buf
, sizeof(buf
)));
696 return (DNS_R_INVALIDTKEY
);
700 * Minimize memory leakage by only setting KRB5_KTNAME
701 * if it needs to change.
703 const char *old
= getenv("KRB5_KTNAME");
704 if (old
== NULL
|| strcmp(old
, gssapi_keytab
) != 0) {
705 char *kt
= malloc(strlen(gssapi_keytab
) + 13);
707 return (ISC_R_NOMEMORY
);
708 sprintf(kt
, "KRB5_KTNAME=%s", gssapi_keytab
);
710 return (ISC_R_NOMEMORY
);
717 gret
= gss_accept_sec_context(&minor
, &context
, cred
, &gintoken
,
718 GSS_C_NO_CHANNEL_BINDINGS
, &gname
,
719 NULL
, &gouttoken
, NULL
, NULL
, NULL
);
721 result
= ISC_R_FAILURE
;
725 result
= ISC_R_SUCCESS
;
727 case GSS_S_CONTINUE_NEEDED
:
728 result
= DNS_R_CONTINUE
;
730 case GSS_S_DEFECTIVE_TOKEN
:
731 case GSS_S_DEFECTIVE_CREDENTIAL
:
733 case GSS_S_DUPLICATE_TOKEN
:
734 case GSS_S_OLD_TOKEN
:
736 case GSS_S_CREDENTIALS_EXPIRED
:
737 case GSS_S_BAD_BINDINGS
:
738 case GSS_S_NO_CONTEXT
:
741 result
= DNS_R_INVALIDTKEY
;
744 gss_log(3, "failed gss_accept_sec_context: %s",
745 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
749 if (gouttoken
.length
> 0U) {
750 RETERR(isc_buffer_allocate(mctx
, outtoken
,
751 (unsigned int)gouttoken
.length
));
752 GBUFFER_TO_REGION(gouttoken
, r
);
753 RETERR(isc_buffer_copyregion(*outtoken
, &r
));
754 (void)gss_release_buffer(&minor
, &gouttoken
);
757 if (gret
== GSS_S_COMPLETE
) {
758 gret
= gss_display_name(&minor
, gname
, &gnamebuf
, NULL
);
759 if (gret
!= GSS_S_COMPLETE
) {
760 gss_log(3, "failed gss_display_name: %s",
761 gss_error_tostring(gret
, minor
,
763 RETERR(ISC_R_FAILURE
);
767 * Compensate for a bug in Solaris8's implementation
768 * of gss_display_name(). Should be harmless in any
769 * case, since principal names really should not
770 * contain null characters.
772 if (gnamebuf
.length
> 0U &&
773 ((char *)gnamebuf
.value
)[gnamebuf
.length
- 1] == '\0')
776 gss_log(3, "gss-api source name (accept) is %.*s",
777 (int)gnamebuf
.length
, (char *)gnamebuf
.value
);
779 GBUFFER_TO_REGION(gnamebuf
, r
);
780 isc_buffer_init(&namebuf
, r
.base
, r
.length
);
781 isc_buffer_add(&namebuf
, r
.length
);
783 RETERR(dns_name_fromtext(principal
, &namebuf
, dns_rootname
,
786 if (gnamebuf
.length
!= 0U) {
787 gret
= gss_release_buffer(&minor
, &gnamebuf
);
788 if (gret
!= GSS_S_COMPLETE
)
789 gss_log(3, "failed gss_release_buffer: %s",
790 gss_error_tostring(gret
, minor
, buf
,
799 gret
= gss_release_name(&minor
, &gname
);
800 if (gret
!= GSS_S_COMPLETE
)
801 gss_log(3, "failed gss_release_name: %s",
802 gss_error_tostring(gret
, minor
, buf
,
809 UNUSED(gssapi_keytab
);
816 return (ISC_R_NOTIMPLEMENTED
);
821 dst_gssapi_deletectx(isc_mem_t
*mctx
, gss_ctx_id_t
*gssctx
)
824 OM_uint32 gret
, minor
;
829 REQUIRE(gssctx
!= NULL
&& *gssctx
!= NULL
);
831 /* Delete the context from the GSS provider */
832 gret
= gss_delete_sec_context(&minor
, gssctx
, GSS_C_NO_BUFFER
);
833 if (gret
!= GSS_S_COMPLETE
) {
834 /* Log the error, but still free the context's memory */
835 gss_log(3, "Failure deleting security context %s",
836 gss_error_tostring(gret
, minor
, buf
, sizeof(buf
)));
838 return(ISC_R_SUCCESS
);
842 return (ISC_R_NOTIMPLEMENTED
);
847 gss_error_tostring(isc_uint32_t major
, isc_uint32_t minor
,
848 char *buf
, size_t buflen
) {
850 gss_buffer_desc msg_minor
= GSS_C_EMPTY_BUFFER
,
851 msg_major
= GSS_C_EMPTY_BUFFER
;
852 OM_uint32 msg_ctx
, minor_stat
;
854 /* Handle major status */
856 (void)gss_display_status(&minor_stat
, major
, GSS_C_GSS_CODE
,
857 GSS_C_NULL_OID
, &msg_ctx
, &msg_major
);
859 /* Handle minor status */
861 (void)gss_display_status(&minor_stat
, minor
, GSS_C_MECH_CODE
,
862 GSS_C_NULL_OID
, &msg_ctx
, &msg_minor
);
864 snprintf(buf
, buflen
, "GSSAPI error: Major = %s, Minor = %s.",
865 (char *)msg_major
.value
, (char *)msg_minor
.value
);
867 if (msg_major
.length
!= 0U)
868 (void)gss_release_buffer(&minor_stat
, &msg_major
);
869 if (msg_minor
.length
!= 0U)
870 (void)gss_release_buffer(&minor_stat
, &msg_minor
);
873 snprintf(buf
, buflen
, "GSSAPI error: Major = %u, Minor = %u.",
881 gss_log(int level
, const char *fmt
, ...) {
885 isc_log_vwrite(dns_lctx
, DNS_LOGCATEGORY_GENERAL
,
886 DNS_LOGMODULE_TKEY
, ISC_LOG_DEBUG(level
), fmt
, ap
);