diff options
Diffstat (limited to 'contrib/bind9/lib/dns/gssapictx.c')
-rw-r--r-- | contrib/bind9/lib/dns/gssapictx.c | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/contrib/bind9/lib/dns/gssapictx.c b/contrib/bind9/lib/dns/gssapictx.c index f365a64..707745c 100644 --- a/contrib/bind9/lib/dns/gssapictx.c +++ b/contrib/bind9/lib/dns/gssapictx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,16 +15,18 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: gssapictx.c,v 1.12.118.5 2010-12-22 02:37:55 marka Exp $ */ +/* $Id: gssapictx.c,v 1.26 2011-01-10 03:49:49 marka Exp $ */ #include <config.h> +#include <ctype.h> #include <stdlib.h> #include <string.h> #include <isc/buffer.h> #include <isc/dir.h> #include <isc/entropy.h> +#include <isc/file.h> #include <isc/lex.h> #include <isc/mem.h> #include <isc/once.h> @@ -201,9 +203,12 @@ log_cred(const gss_cred_id_t cred) { * - tkey-gssapi-credential doesn't start with DNS/ * - the default realm in /etc/krb5.conf and the * tkey-gssapi-credential bind config option don't match + * + * Note that if tkey-gssapi-keytab is set then these configure checks + * are not performed, and runtime errors from gssapi are used instead */ static void -dst_gssapi_check_config(const char *gss_name) { +check_config(const char *gss_name) { const char *p; krb5_context krb5_ctx; char *krb5_realm = NULL; @@ -263,7 +268,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, * here when we're in the acceptor role, which would let us * default the hostname and use a compiled in default service * name of "DNS", giving one less thing to configure in - * named.conf. Unfortunately, this creates a circular + * named.conf. Unfortunately, this creates a circular * dependency due to DNS-based realm lookup in at least one * GSSAPI implementation (Heimdal). Oh well. */ @@ -273,7 +278,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); if (gret != GSS_S_COMPLETE) { - dst_gssapi_check_config((char *)array); + check_config((char *)array); gss_log(3, "failed gss_import_name: %s", gss_error_tostring(gret, minor, buf, @@ -306,7 +311,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate, initiate ? "initiate" : "accept", (char *)gnamebuf.value, gss_error_tostring(gret, minor, buf, sizeof(buf))); - dst_gssapi_check_config((char *)array); + check_config((char *)array); return (ISC_R_FAILURE); } @@ -361,7 +366,7 @@ dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name, rname++; /* - * Find the host portion of the signer's name. We do this by + * Find the host portion of the signer's name. We do this by * searching for the first / character. We then check to make * certain the instance name is "host" * @@ -440,7 +445,7 @@ dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name, return (isc_boolean_false); /* - * Find the host portion of the signer's name. Zero out the $ so + * Find the host portion of the signer's name. Zero out the $ so * it terminates the signer's name, and skip past the @ for * the realm. * @@ -454,7 +459,7 @@ dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name, /* * Find the first . in the target name, and make it the end of - * the string. The rest of the name has to match the realm. + * the string. The rest of the name has to match the realm. */ if (name != NULL) { nname = strchr(nbuf, '.'); @@ -510,9 +515,34 @@ dst_gssapi_releasecred(gss_cred_id_t *cred) { #endif } +#ifdef GSSAPI +/* + * Format a gssapi error message info into a char ** on the given memory + * context. This is used to return gssapi error messages back up the + * call chain for reporting to the user. + */ +static void +gss_err_message(isc_mem_t *mctx, isc_uint32_t major, isc_uint32_t minor, + char **err_message) +{ + char buf[1024]; + char *estr; + + if (err_message == NULL || mctx == NULL) { + /* the caller doesn't want any error messages */ + return; + } + + estr = gss_error_tostring(major, minor, buf, sizeof(buf)); + if (estr) + (*err_message) = isc_mem_strdup(mctx, estr); +} +#endif + isc_result_t dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, - isc_buffer_t *outtoken, gss_ctx_id_t *gssctx) + isc_buffer_t *outtoken, gss_ctx_id_t *gssctx, + isc_mem_t *mctx, char **err_message) { #ifdef GSSAPI isc_region_t r; @@ -523,10 +553,10 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, isc_result_t result; gss_buffer_desc gnamebuf; unsigned char array[DNS_NAME_MAXTEXT + 1]; - char buf[1024]; /* Client must pass us a valid gss_ctx_id_t here */ REQUIRE(gssctx != NULL); + REQUIRE(mctx != NULL); isc_buffer_init(&namebuf, array, sizeof(array)); name_to_gbuffer(name, &namebuf, &gnamebuf); @@ -534,6 +564,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, /* Get the name as a GSS name */ gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); if (gret != GSS_S_COMPLETE) { + gss_err_message(mctx, gret, minor, err_message); result = ISC_R_FAILURE; goto out; } @@ -550,8 +581,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, * Note that we don't set GSS_C_SEQUENCE_FLAG as Windows DNS * servers don't like it. */ - flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG | - GSS_C_INTEG_FLAG; + flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG; gret = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, gssctx, gname, GSS_SPNEGO_MECHANISM, flags, @@ -559,9 +589,9 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, NULL, &gouttoken, &ret_flags, NULL); if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) { - gss_log(3, "Failure initiating security context"); - gss_log(3, "%s", gss_error_tostring(gret, minor, - buf, sizeof(buf))); + gss_err_message(mctx, gret, minor, err_message); + gss_log(3, "Failure initiating security context: %s", + *err_message); result = ISC_R_FAILURE; goto out; } @@ -593,6 +623,8 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, UNUSED(intoken); UNUSED(outtoken); UNUSED(gssctx); + UNUSED(mctx); + UNUSED(err_message); return (ISC_R_NOTIMPLEMENTED); #endif @@ -600,6 +632,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, isc_result_t dst_gssapi_acceptctx(gss_cred_id_t cred, + const char *gssapi_keytab, isc_region_t *intoken, isc_buffer_t **outtoken, gss_ctx_id_t *ctxout, dns_name_t *principal, isc_mem_t *mctx) @@ -626,6 +659,34 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, else context = *ctxout; + if (gssapi_keytab != NULL) { +#ifdef ISC_PLATFORM_GSSAPI_KRB5_HEADER + gret = gsskrb5_register_acceptor_identity(gssapi_keytab); + if (gret != GSS_S_COMPLETE) { + gss_log(3, "failed " + "gsskrb5_register_acceptor_identity(%s): %s", + gssapi_keytab, + gss_error_tostring(gret, minor, + buf, sizeof(buf))); + return (DNS_R_INVALIDTKEY); + } +#else + /* + * Minimize memory leakage by only setting KRB5_KTNAME + * if it needs to change. + */ + const char *old = getenv("KRB5_KTNAME"); + if (old == NULL || strcmp(old, gssapi_keytab) != 0) { + char *kt = malloc(strlen(gssapi_keytab) + 13); + if (kt == NULL) + return (ISC_R_NOMEMORY); + sprintf(kt, "KRB5_KTNAME=%s", gssapi_keytab); + if (putenv(kt) != 0) + return (ISC_R_NOMEMORY); + } +#endif + } + gret = gss_accept_sec_context(&minor, &context, cred, &gintoken, GSS_C_NO_CHANNEL_BINDINGS, &gname, NULL, &gouttoken, NULL, NULL, NULL); @@ -692,7 +753,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, isc_buffer_add(&namebuf, r.length); RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname, - ISC_FALSE, NULL)); + 0, NULL)); if (gnamebuf.length != 0) { gret = gss_release_buffer(&minor, &gnamebuf); @@ -717,6 +778,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, return (result); #else UNUSED(cred); + UNUSED(gssapi_keytab); UNUSED(intoken); UNUSED(outtoken); UNUSED(ctxout); |