2000-11-18 03:01:17 +00:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2000-11-18 03:01:17 +00:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2000-11-18 03:01:17 +00:00
|
|
|
*/
|
|
|
|
|
2010-12-18 01:56:23 +00:00
|
|
|
#include <ctype.h>
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2000-10-07 00:45:13 +00:00
|
|
|
#include <stdlib.h>
|
2006-12-04 01:54:53 +00:00
|
|
|
#include <string.h>
|
2000-10-07 00:45:13 +00:00
|
|
|
|
|
|
|
#include <isc/buffer.h>
|
|
|
|
#include <isc/dir.h>
|
2010-12-18 01:56:23 +00:00
|
|
|
#include <isc/file.h>
|
2000-10-07 00:45:13 +00:00
|
|
|
#include <isc/lex.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/once.h>
|
2008-01-22 11:47:54 +00:00
|
|
|
#include <isc/print.h>
|
2010-06-03 02:29:58 +00:00
|
|
|
#include <isc/platform.h>
|
2000-10-07 00:45:13 +00:00
|
|
|
#include <isc/random.h>
|
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/time.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/fixedname.h>
|
|
|
|
#include <dns/name.h>
|
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataclass.h>
|
|
|
|
#include <dns/result.h>
|
|
|
|
#include <dns/types.h>
|
|
|
|
#include <dns/keyvalues.h>
|
2006-12-04 01:54:53 +00:00
|
|
|
#include <dns/log.h>
|
2000-10-07 00:45:13 +00:00
|
|
|
|
|
|
|
#include <dst/gssapi.h>
|
|
|
|
#include <dst/result.h>
|
|
|
|
|
|
|
|
#include "dst_internal.h"
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
/*
|
|
|
|
* If we're using our own SPNEGO implementation (see configure.in),
|
|
|
|
* pull it in now. Otherwise, we just use whatever GSSAPI supplies.
|
|
|
|
*/
|
|
|
|
#if defined(GSSAPI) && defined(USE_ISC_SPNEGO)
|
|
|
|
#include "spnego.h"
|
|
|
|
#define gss_accept_sec_context gss_accept_sec_context_spnego
|
|
|
|
#define gss_init_sec_context gss_init_sec_context_spnego
|
|
|
|
#endif
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
/*
|
|
|
|
* Solaris8 apparently needs an explicit OID set, and Solaris10 needs
|
|
|
|
* one for anything but Kerberos. Supplying an explicit OID set
|
|
|
|
* doesn't appear to hurt anything in other implementations, so we
|
|
|
|
* always use one. If we're not using our own SPNEGO implementation,
|
|
|
|
* we include SPNEGO's OID.
|
|
|
|
*/
|
2013-12-04 12:47:23 +11:00
|
|
|
#ifdef GSSAPI
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <krb5/krb5.h>
|
|
|
|
#else
|
2010-06-03 02:29:58 +00:00
|
|
|
#include ISC_PLATFORM_KRB5HEADER
|
2013-12-04 12:47:23 +11:00
|
|
|
#endif
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
static unsigned char krb5_mech_oid_bytes[] = {
|
|
|
|
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifndef USE_ISC_SPNEGO
|
|
|
|
static unsigned char spnego_mech_oid_bytes[] = {
|
|
|
|
0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static gss_OID_desc mech_oid_set_array[] = {
|
|
|
|
{ sizeof(krb5_mech_oid_bytes), krb5_mech_oid_bytes },
|
|
|
|
#ifndef USE_ISC_SPNEGO
|
|
|
|
{ sizeof(spnego_mech_oid_bytes), spnego_mech_oid_bytes },
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static gss_OID_set_desc mech_oid_set = {
|
|
|
|
sizeof(mech_oid_set_array) / sizeof(*mech_oid_set_array),
|
|
|
|
mech_oid_set_array
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define REGION_TO_GBUFFER(r, gb) \
|
|
|
|
do { \
|
|
|
|
(gb).length = (r).length; \
|
|
|
|
(gb).value = (r).base; \
|
2000-10-07 00:45:13 +00:00
|
|
|
} while (0)
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
#define GBUFFER_TO_REGION(gb, r) \
|
|
|
|
do { \
|
2013-12-04 12:47:23 +11:00
|
|
|
(r).length = (unsigned int)(gb).length; \
|
2006-12-04 01:54:53 +00:00
|
|
|
(r).base = (gb).value; \
|
2000-10-07 00:45:13 +00:00
|
|
|
} while (0)
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
#define RETERR(x) do { \
|
|
|
|
result = (x); \
|
|
|
|
if (result != ISC_R_SUCCESS) \
|
|
|
|
goto out; \
|
2000-10-07 00:45:13 +00:00
|
|
|
} while (0)
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
#ifdef GSSAPI
|
2000-10-07 00:45:13 +00:00
|
|
|
static inline void
|
2016-12-30 15:45:08 +11:00
|
|
|
name_to_gbuffer(const dns_name_t *name, isc_buffer_t *buffer,
|
2000-10-07 00:45:13 +00:00
|
|
|
gss_buffer_desc *gbuffer)
|
|
|
|
{
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_name_t tname;
|
|
|
|
const dns_name_t *namep;
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_region_t r;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
if (!dns_name_isabsolute(name))
|
|
|
|
namep = name;
|
2006-12-04 01:54:53 +00:00
|
|
|
else
|
|
|
|
{
|
2000-10-07 00:45:13 +00:00
|
|
|
unsigned int labels;
|
|
|
|
dns_name_init(&tname, NULL);
|
|
|
|
labels = dns_name_countlabels(name);
|
|
|
|
dns_name_getlabelsequence(name, 0, labels - 1, &tname);
|
|
|
|
namep = &tname;
|
|
|
|
}
|
2008-01-22 23:28:04 +00:00
|
|
|
|
2010-07-09 05:13:15 +00:00
|
|
|
result = dns_name_toprincipal(namep, buffer);
|
2011-08-29 06:33:25 +00:00
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_buffer_putuint8(buffer, 0);
|
|
|
|
isc_buffer_usedregion(buffer, &r);
|
|
|
|
REGION_TO_GBUFFER(r, *gbuffer);
|
|
|
|
}
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
static void
|
|
|
|
log_cred(const gss_cred_id_t cred) {
|
|
|
|
OM_uint32 gret, minor, lifetime;
|
|
|
|
gss_name_t gname;
|
|
|
|
gss_buffer_desc gbuffer;
|
|
|
|
gss_cred_usage_t usage;
|
|
|
|
const char *usage_text;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
gret = gss_inquire_cred(&minor, cred, &gname, &lifetime, &usage, NULL);
|
|
|
|
if (gret != GSS_S_COMPLETE) {
|
|
|
|
gss_log(3, "failed gss_inquire_cred: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gret = gss_display_name(&minor, gname, &gbuffer, NULL);
|
|
|
|
if (gret != GSS_S_COMPLETE)
|
|
|
|
gss_log(3, "failed gss_display_name: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
|
|
|
else {
|
|
|
|
switch (usage) {
|
|
|
|
case GSS_C_BOTH:
|
|
|
|
usage_text = "GSS_C_BOTH";
|
|
|
|
break;
|
|
|
|
case GSS_C_INITIATE:
|
|
|
|
usage_text = "GSS_C_INITIATE";
|
|
|
|
break;
|
|
|
|
case GSS_C_ACCEPT:
|
|
|
|
usage_text = "GSS_C_ACCEPT";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage_text = "???";
|
|
|
|
}
|
|
|
|
gss_log(3, "gss cred: \"%s\", %s, %lu", (char *)gbuffer.value,
|
|
|
|
usage_text, (unsigned long)lifetime);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gret == GSS_S_COMPLETE) {
|
2011-03-28 05:20:08 +00:00
|
|
|
if (gbuffer.length != 0U) {
|
2008-04-03 00:45:23 +00:00
|
|
|
gret = gss_release_buffer(&minor, &gbuffer);
|
|
|
|
if (gret != GSS_S_COMPLETE)
|
|
|
|
gss_log(3, "failed gss_release_buffer: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf,
|
|
|
|
sizeof(buf)));
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gret = gss_release_name(&minor, &gname);
|
|
|
|
if (gret != GSS_S_COMPLETE)
|
|
|
|
gss_log(3, "failed gss_release_name: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-06-03 02:29:58 +00:00
|
|
|
#ifdef GSSAPI
|
|
|
|
/*
|
|
|
|
* check for the most common configuration errors.
|
|
|
|
*
|
|
|
|
* The errors checked for are:
|
|
|
|
* - 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
|
2010-12-18 01:56:23 +00:00
|
|
|
*
|
|
|
|
* Note that if tkey-gssapi-keytab is set then these configure checks
|
|
|
|
* are not performed, and runtime errors from gssapi are used instead
|
2010-06-03 02:29:58 +00:00
|
|
|
*/
|
|
|
|
static void
|
2010-12-18 01:56:23 +00:00
|
|
|
check_config(const char *gss_name) {
|
2010-06-03 02:29:58 +00:00
|
|
|
const char *p;
|
|
|
|
krb5_context krb5_ctx;
|
2015-02-27 10:55:55 +11:00
|
|
|
char *krb5_realm_name = NULL;
|
2010-06-03 02:29:58 +00:00
|
|
|
|
|
|
|
if (strncasecmp(gss_name, "DNS/", 4) != 0) {
|
|
|
|
gss_log(ISC_LOG_ERROR, "tkey-gssapi-credential (%s) "
|
|
|
|
"should start with 'DNS/'", gss_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (krb5_init_context(&krb5_ctx) != 0) {
|
|
|
|
gss_log(ISC_LOG_ERROR, "Unable to initialise krb5 context");
|
|
|
|
return;
|
|
|
|
}
|
2015-02-27 10:55:55 +11:00
|
|
|
if (krb5_get_default_realm(krb5_ctx, &krb5_realm_name) != 0) {
|
2010-06-03 02:29:58 +00:00
|
|
|
gss_log(ISC_LOG_ERROR, "Unable to get krb5 default realm");
|
|
|
|
krb5_free_context(krb5_ctx);
|
|
|
|
return;
|
|
|
|
}
|
2014-02-24 12:15:37 +11:00
|
|
|
p = strchr(gss_name, '@');
|
2010-06-03 02:29:58 +00:00
|
|
|
if (p == NULL) {
|
|
|
|
gss_log(ISC_LOG_ERROR, "badly formatted "
|
|
|
|
"tkey-gssapi-credentials (%s)", gss_name);
|
|
|
|
krb5_free_context(krb5_ctx);
|
|
|
|
return;
|
|
|
|
}
|
2015-02-27 10:55:55 +11:00
|
|
|
if (strcasecmp(p + 1, krb5_realm_name) != 0) {
|
2010-06-03 02:29:58 +00:00
|
|
|
gss_log(ISC_LOG_ERROR, "default realm from krb5.conf (%s) "
|
|
|
|
"does not match tkey-gssapi-credential (%s)",
|
2015-02-27 10:55:55 +11:00
|
|
|
krb5_realm_name, gss_name);
|
2010-06-03 02:29:58 +00:00
|
|
|
krb5_free_context(krb5_ctx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
krb5_free_context(krb5_ctx);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_result_t
|
2018-04-17 08:29:14 -07:00
|
|
|
dst_gssapi_acquirecred(const dns_name_t *name, bool initiate,
|
2006-12-04 01:54:53 +00:00
|
|
|
gss_cred_id_t *cred)
|
|
|
|
{
|
|
|
|
#ifdef GSSAPI
|
2013-06-04 11:59:57 +10:00
|
|
|
isc_result_t result;
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_buffer_t namebuf;
|
|
|
|
gss_name_t gname;
|
|
|
|
gss_buffer_desc gnamebuf;
|
|
|
|
unsigned char array[DNS_NAME_MAXTEXT + 1];
|
|
|
|
OM_uint32 gret, minor;
|
|
|
|
OM_uint32 lifetime;
|
|
|
|
gss_cred_usage_t usage;
|
2006-12-04 01:54:53 +00:00
|
|
|
char buf[1024];
|
2000-10-07 00:45:13 +00:00
|
|
|
|
|
|
|
REQUIRE(cred != NULL && *cred == NULL);
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
/*
|
|
|
|
* XXXSRA In theory we could use GSS_C_NT_HOSTBASED_SERVICE
|
|
|
|
* 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
|
2010-12-18 01:56:23 +00:00
|
|
|
* named.conf. Unfortunately, this creates a circular
|
2006-12-04 01:54:53 +00:00
|
|
|
* dependency due to DNS-based realm lookup in at least one
|
|
|
|
* GSSAPI implementation (Heimdal). Oh well.
|
|
|
|
*/
|
2000-10-07 00:45:13 +00:00
|
|
|
if (name != NULL) {
|
|
|
|
isc_buffer_init(&namebuf, array, sizeof(array));
|
|
|
|
name_to_gbuffer(name, &namebuf, &gnamebuf);
|
2006-12-04 01:54:53 +00:00
|
|
|
gret = gss_import_name(&minor, &gnamebuf,
|
|
|
|
GSS_C_NO_OID, &gname);
|
|
|
|
if (gret != GSS_S_COMPLETE) {
|
2010-12-18 01:56:23 +00:00
|
|
|
check_config((char *)array);
|
2010-06-03 02:29:58 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
gss_log(3, "failed gss_import_name: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf,
|
|
|
|
sizeof(buf)));
|
2000-10-07 00:45:13 +00:00
|
|
|
return (ISC_R_FAILURE);
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
2000-10-07 00:45:13 +00:00
|
|
|
} else
|
|
|
|
gname = NULL;
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
/* Get the credentials. */
|
|
|
|
if (gname != NULL)
|
|
|
|
gss_log(3, "acquiring credentials for %s",
|
|
|
|
(char *)gnamebuf.value);
|
|
|
|
else {
|
|
|
|
/* XXXDCL does this even make any sense? */
|
|
|
|
gss_log(3, "acquiring credentials for ?");
|
|
|
|
}
|
|
|
|
|
2000-10-07 00:45:13 +00:00
|
|
|
if (initiate)
|
|
|
|
usage = GSS_C_INITIATE;
|
|
|
|
else
|
|
|
|
usage = GSS_C_ACCEPT;
|
|
|
|
|
|
|
|
gret = gss_acquire_cred(&minor, gname, GSS_C_INDEFINITE,
|
2013-06-04 11:59:57 +10:00
|
|
|
&mech_oid_set, usage, cred, NULL, &lifetime);
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
if (gret != GSS_S_COMPLETE) {
|
|
|
|
gss_log(3, "failed to acquire %s credentials for %s: %s",
|
|
|
|
initiate ? "initiate" : "accept",
|
2011-08-29 06:33:25 +00:00
|
|
|
(gname != NULL) ? (char *)gnamebuf.value : "?",
|
2006-12-04 01:54:53 +00:00
|
|
|
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
2013-06-04 11:59:57 +10:00
|
|
|
if (gname != NULL)
|
|
|
|
check_config((char *)array);
|
|
|
|
result = ISC_R_FAILURE;
|
|
|
|
goto cleanup;
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gss_log(4, "acquired %s credentials for %s",
|
|
|
|
initiate ? "initiate" : "accept",
|
2011-08-29 06:33:25 +00:00
|
|
|
(gname != NULL) ? (char *)gnamebuf.value : "?");
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
log_cred(*cred);
|
2013-06-04 11:59:57 +10:00
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (gname != NULL) {
|
|
|
|
gret = gss_release_name(&minor, &gname);
|
|
|
|
if (gret != GSS_S_COMPLETE)
|
|
|
|
gss_log(3, "failed gss_release_name: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf,
|
|
|
|
sizeof(buf)));
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
|
2013-06-04 11:59:57 +10:00
|
|
|
return (result);
|
2006-12-04 01:54:53 +00:00
|
|
|
#else
|
2011-08-29 06:33:25 +00:00
|
|
|
REQUIRE(cred != NULL && *cred == NULL);
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
UNUSED(name);
|
|
|
|
UNUSED(initiate);
|
|
|
|
UNUSED(cred);
|
|
|
|
|
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2016-12-30 15:45:08 +11:00
|
|
|
dst_gssapi_identitymatchesrealmkrb5(const dns_name_t *signer,
|
|
|
|
const dns_name_t *name,
|
2018-08-30 18:31:17 +10:00
|
|
|
const dns_name_t *realm,
|
|
|
|
bool subdomain)
|
2006-12-04 01:54:53 +00:00
|
|
|
{
|
|
|
|
#ifdef GSSAPI
|
|
|
|
char sbuf[DNS_NAME_FORMATSIZE];
|
|
|
|
char rbuf[DNS_NAME_FORMATSIZE];
|
|
|
|
char *sname;
|
|
|
|
char *rname;
|
2010-07-09 05:13:15 +00:00
|
|
|
isc_buffer_t buffer;
|
2011-08-29 06:33:25 +00:00
|
|
|
isc_result_t result;
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* It is far, far easier to write the names we are looking at into
|
|
|
|
* a string, and do string operations on them.
|
|
|
|
*/
|
2010-07-09 05:13:15 +00:00
|
|
|
isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
|
2011-08-29 06:33:25 +00:00
|
|
|
result = dns_name_toprincipal(signer, &buffer);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2010-07-09 05:13:15 +00:00
|
|
|
isc_buffer_putuint8(&buffer, 0);
|
2006-12-04 01:54:53 +00:00
|
|
|
dns_name_format(realm, rbuf, sizeof(rbuf));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the realm portion. This is the part after the @. If it
|
|
|
|
* does not exist, we don't have something we like, so we fail our
|
|
|
|
* compare.
|
|
|
|
*/
|
2010-07-09 05:13:15 +00:00
|
|
|
rname = strchr(sbuf, '@');
|
2018-04-17 08:29:14 -07:00
|
|
|
if (rname == NULL) {
|
|
|
|
return (false);
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
*rname = '\0';
|
2010-12-22 02:33:12 +00:00
|
|
|
rname++;
|
2006-12-04 01:54:53 +00:00
|
|
|
|
2018-08-30 18:31:17 +10:00
|
|
|
if (strcmp(rname, rbuf) != 0) {
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
/*
|
2010-12-18 01:56:23 +00:00
|
|
|
* Find the host portion of the signer's name. We do this by
|
2006-12-04 01:54:53 +00:00
|
|
|
* searching for the first / character. We then check to make
|
|
|
|
* certain the instance name is "host"
|
|
|
|
*
|
|
|
|
* This will work for
|
|
|
|
* host/example.com@EXAMPLE.COM
|
|
|
|
*/
|
|
|
|
sname = strchr(sbuf, '/');
|
2018-04-17 08:29:14 -07:00
|
|
|
if (sname == NULL) {
|
|
|
|
return (false);
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
*sname = '\0';
|
|
|
|
sname++;
|
2018-04-17 08:29:14 -07:00
|
|
|
if (strcmp(sbuf, "host") != 0) {
|
|
|
|
return (false);
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
/*
|
2018-08-30 18:31:17 +10:00
|
|
|
* If name is non NULL check that it matches against the
|
|
|
|
* machine name as expected.
|
2006-12-04 01:54:53 +00:00
|
|
|
*/
|
|
|
|
if (name != NULL) {
|
2018-08-30 18:31:17 +10:00
|
|
|
dns_fixedname_t fixed;
|
|
|
|
dns_name_t *machine;
|
|
|
|
|
|
|
|
machine = dns_fixedname_initname(&fixed);
|
|
|
|
result = dns_name_fromstring(machine, sname, 0, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (false);
|
2018-04-17 08:29:14 -07:00
|
|
|
}
|
2018-08-30 18:31:17 +10:00
|
|
|
if (subdomain) {
|
|
|
|
return (dns_name_issubdomain(name, machine));
|
2018-04-17 08:29:14 -07:00
|
|
|
}
|
2018-08-30 18:31:17 +10:00
|
|
|
return (dns_name_equal(name, machine));
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
|
|
|
|
2018-08-30 18:31:17 +10:00
|
|
|
return (true);
|
2006-12-04 01:54:53 +00:00
|
|
|
#else
|
|
|
|
UNUSED(signer);
|
|
|
|
UNUSED(name);
|
|
|
|
UNUSED(realm);
|
2018-08-30 18:31:17 +10:00
|
|
|
UNUSED(subdomain);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2006-12-04 01:54:53 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2016-12-30 15:45:08 +11:00
|
|
|
dst_gssapi_identitymatchesrealmms(const dns_name_t *signer,
|
|
|
|
const dns_name_t *name,
|
2018-08-30 18:31:17 +10:00
|
|
|
const dns_name_t *realm,
|
|
|
|
bool subdomain)
|
2006-12-04 01:54:53 +00:00
|
|
|
{
|
|
|
|
#ifdef GSSAPI
|
|
|
|
char sbuf[DNS_NAME_FORMATSIZE];
|
|
|
|
char rbuf[DNS_NAME_FORMATSIZE];
|
|
|
|
char *sname;
|
|
|
|
char *rname;
|
2010-07-09 05:13:15 +00:00
|
|
|
isc_buffer_t buffer;
|
2011-08-29 06:33:25 +00:00
|
|
|
isc_result_t result;
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* It is far, far easier to write the names we are looking at into
|
|
|
|
* a string, and do string operations on them.
|
|
|
|
*/
|
2010-07-09 05:13:15 +00:00
|
|
|
isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
|
2011-08-29 06:33:25 +00:00
|
|
|
result = dns_name_toprincipal(signer, &buffer);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2010-07-09 05:13:15 +00:00
|
|
|
isc_buffer_putuint8(&buffer, 0);
|
2006-12-04 01:54:53 +00:00
|
|
|
dns_name_format(realm, rbuf, sizeof(rbuf));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the realm portion. This is the part after the @. If it
|
|
|
|
* does not exist, we don't have something we like, so we fail our
|
|
|
|
* compare.
|
|
|
|
*/
|
2010-07-09 05:13:15 +00:00
|
|
|
rname = strchr(sbuf, '@');
|
2018-04-17 08:29:14 -07:00
|
|
|
if (rname == NULL) {
|
|
|
|
return (false);
|
|
|
|
}
|
2010-07-09 05:13:15 +00:00
|
|
|
sname = strchr(sbuf, '$');
|
2018-04-17 08:29:14 -07:00
|
|
|
if (sname == NULL) {
|
|
|
|
return (false);
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify that the $ and @ follow one another.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
if (rname - sname != 1) {
|
|
|
|
return (false);
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
/*
|
2010-12-18 01:56:23 +00:00
|
|
|
* Find the host portion of the signer's name. Zero out the $ so
|
2006-12-04 01:54:53 +00:00
|
|
|
* it terminates the signer's name, and skip past the @ for
|
|
|
|
* the realm.
|
|
|
|
*
|
|
|
|
* All service principals in Microsoft format seem to be in
|
|
|
|
* machinename$@EXAMPLE.COM
|
|
|
|
* format.
|
|
|
|
*/
|
2010-07-09 05:13:15 +00:00
|
|
|
rname++;
|
2006-12-04 01:54:53 +00:00
|
|
|
*sname = '\0';
|
|
|
|
|
2018-08-30 18:31:17 +10:00
|
|
|
if (strcmp(rname, rbuf) != 0) {
|
|
|
|
return (false);
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2018-08-30 18:31:17 +10:00
|
|
|
* Now, we check that the realm matches (case sensitive) and that
|
|
|
|
* 'name' matches against 'machinename' qualified with 'realm'.
|
2006-12-04 01:54:53 +00:00
|
|
|
*/
|
|
|
|
if (name != NULL) {
|
2018-08-30 18:31:17 +10:00
|
|
|
dns_fixedname_t fixed;
|
|
|
|
dns_name_t *machine;
|
|
|
|
|
|
|
|
machine = dns_fixedname_initname(&fixed);
|
|
|
|
result = dns_name_fromstring2(machine, sbuf, realm, 0, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (false);
|
2018-04-17 08:29:14 -07:00
|
|
|
}
|
2018-08-30 18:31:17 +10:00
|
|
|
if (subdomain) {
|
|
|
|
return (dns_name_issubdomain(name, machine));
|
2018-04-17 08:29:14 -07:00
|
|
|
}
|
2018-08-30 18:31:17 +10:00
|
|
|
return (dns_name_equal(name, machine));
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
|
|
|
|
2018-08-30 18:31:17 +10:00
|
|
|
return (true);
|
2006-12-04 01:54:53 +00:00
|
|
|
#else
|
|
|
|
UNUSED(signer);
|
|
|
|
UNUSED(name);
|
|
|
|
UNUSED(realm);
|
2018-08-30 18:31:17 +10:00
|
|
|
UNUSED(subdomain);
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2006-12-04 01:54:53 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dst_gssapi_releasecred(gss_cred_id_t *cred) {
|
|
|
|
#ifdef GSSAPI
|
|
|
|
OM_uint32 gret, minor;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
REQUIRE(cred != NULL && *cred != NULL);
|
2008-01-22 23:28:04 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
gret = gss_release_cred(&minor, cred);
|
|
|
|
if (gret != GSS_S_COMPLETE) {
|
|
|
|
/* Log the error, but still free the credential's memory */
|
|
|
|
gss_log(3, "failed releasing credential: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
|
|
|
}
|
|
|
|
*cred = NULL;
|
2008-01-22 23:28:04 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
return(ISC_R_SUCCESS);
|
|
|
|
#else
|
|
|
|
UNUSED(cred);
|
|
|
|
|
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
|
|
|
#endif
|
2000-10-07 00:45:13 +00:00
|
|
|
}
|
|
|
|
|
2010-12-18 01:56:23 +00:00
|
|
|
#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
|
2018-03-28 14:19:37 +02:00
|
|
|
gss_err_message(isc_mem_t *mctx, uint32_t major, uint32_t minor,
|
2010-12-18 01:56:23 +00:00
|
|
|
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));
|
2012-10-06 14:20:45 +10:00
|
|
|
if (estr != NULL)
|
2010-12-18 01:56:23 +00:00
|
|
|
(*err_message) = isc_mem_strdup(mctx, estr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_result_t
|
2016-12-30 15:45:08 +11:00
|
|
|
dst_gssapi_initctx(const dns_name_t *name, isc_buffer_t *intoken,
|
2010-12-18 01:56:23 +00:00
|
|
|
isc_buffer_t *outtoken, gss_ctx_id_t *gssctx,
|
2011-01-08 00:33:12 +00:00
|
|
|
isc_mem_t *mctx, char **err_message)
|
2000-10-07 00:45:13 +00:00
|
|
|
{
|
2006-12-04 01:54:53 +00:00
|
|
|
#ifdef GSSAPI
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_region_t r;
|
|
|
|
isc_buffer_t namebuf;
|
|
|
|
gss_name_t gname;
|
2006-12-04 01:54:53 +00:00
|
|
|
OM_uint32 gret, minor, ret_flags, flags;
|
2008-04-03 00:45:23 +00:00
|
|
|
gss_buffer_desc gintoken, *gintokenp, gouttoken = GSS_C_EMPTY_BUFFER;
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_result_t result;
|
2006-12-04 01:54:53 +00:00
|
|
|
gss_buffer_desc gnamebuf;
|
2000-10-07 00:45:13 +00:00
|
|
|
unsigned char array[DNS_NAME_MAXTEXT + 1];
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
/* Client must pass us a valid gss_ctx_id_t here */
|
|
|
|
REQUIRE(gssctx != NULL);
|
2010-12-18 01:56:23 +00:00
|
|
|
REQUIRE(mctx != NULL);
|
|
|
|
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_buffer_init(&namebuf, array, sizeof(array));
|
|
|
|
name_to_gbuffer(name, &namebuf, &gnamebuf);
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
/* Get the name as a GSS name */
|
2000-10-07 00:45:13 +00:00
|
|
|
gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
|
2006-12-04 01:54:53 +00:00
|
|
|
if (gret != GSS_S_COMPLETE) {
|
2010-12-18 01:56:23 +00:00
|
|
|
gss_err_message(mctx, gret, minor, err_message);
|
2006-12-04 01:54:53 +00:00
|
|
|
result = ISC_R_FAILURE;
|
|
|
|
goto out;
|
|
|
|
}
|
2000-10-07 00:45:13 +00:00
|
|
|
|
|
|
|
if (intoken != NULL) {
|
2006-12-04 01:54:53 +00:00
|
|
|
/* Don't call gss_release_buffer for gintoken! */
|
2000-10-07 00:45:13 +00:00
|
|
|
REGION_TO_GBUFFER(*intoken, gintoken);
|
|
|
|
gintokenp = &gintoken;
|
2006-12-04 01:54:53 +00:00
|
|
|
} else {
|
2000-10-07 00:45:13 +00:00
|
|
|
gintokenp = NULL;
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2010-03-12 03:47:08 +00:00
|
|
|
/*
|
|
|
|
* Note that we don't set GSS_C_SEQUENCE_FLAG as Windows DNS
|
|
|
|
* servers don't like it.
|
|
|
|
*/
|
2010-12-18 01:56:23 +00:00
|
|
|
flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
gret = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, gssctx,
|
|
|
|
gname, GSS_SPNEGO_MECHANISM, flags,
|
|
|
|
0, NULL, gintokenp,
|
|
|
|
NULL, &gouttoken, &ret_flags, NULL);
|
|
|
|
|
|
|
|
if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) {
|
2010-12-18 01:56:23 +00:00
|
|
|
gss_err_message(mctx, gret, minor, err_message);
|
2012-10-06 14:20:45 +10:00
|
|
|
if (err_message != NULL && *err_message != NULL)
|
|
|
|
gss_log(3, "Failure initiating security context: %s",
|
|
|
|
*err_message);
|
|
|
|
else
|
|
|
|
gss_log(3, "Failure initiating security context");
|
2012-10-06 23:46:11 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
result = ISC_R_FAILURE;
|
|
|
|
goto out;
|
|
|
|
}
|
2008-01-22 23:28:04 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
/*
|
|
|
|
* XXXSRA Not handled yet: RFC 3645 3.1.1: check ret_flags
|
|
|
|
* MUTUAL and INTEG flags, fail if either not set.
|
|
|
|
*/
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2008-04-03 00:45:23 +00:00
|
|
|
/*
|
|
|
|
* RFC 2744 states the a valid output token has a non-zero length.
|
|
|
|
*/
|
2011-03-28 05:20:08 +00:00
|
|
|
if (gouttoken.length != 0U) {
|
2008-04-03 00:45:23 +00:00
|
|
|
GBUFFER_TO_REGION(gouttoken, r);
|
|
|
|
RETERR(isc_buffer_copyregion(outtoken, &r));
|
|
|
|
}
|
2006-12-04 01:54:53 +00:00
|
|
|
|
2000-10-07 00:45:13 +00:00
|
|
|
if (gret == GSS_S_COMPLETE)
|
2006-12-04 01:54:53 +00:00
|
|
|
result = ISC_R_SUCCESS;
|
2000-10-07 00:45:13 +00:00
|
|
|
else
|
2006-12-04 01:54:53 +00:00
|
|
|
result = DNS_R_CONTINUE;
|
2000-10-07 00:45:13 +00:00
|
|
|
|
|
|
|
out:
|
2015-08-14 08:20:01 +10:00
|
|
|
if (gouttoken.length != 0U)
|
|
|
|
(void)gss_release_buffer(&minor, &gouttoken);
|
2013-06-04 11:59:57 +10:00
|
|
|
(void)gss_release_name(&minor, &gname);
|
2006-12-04 01:54:53 +00:00
|
|
|
return (result);
|
|
|
|
#else
|
|
|
|
UNUSED(name);
|
|
|
|
UNUSED(intoken);
|
|
|
|
UNUSED(outtoken);
|
|
|
|
UNUSED(gssctx);
|
2010-12-18 01:56:23 +00:00
|
|
|
UNUSED(mctx);
|
|
|
|
UNUSED(err_message);
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
|
|
|
#endif
|
2000-10-07 00:45:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2006-12-04 01:54:53 +00:00
|
|
|
dst_gssapi_acceptctx(gss_cred_id_t cred,
|
2010-12-18 01:56:23 +00:00
|
|
|
const char *gssapi_keytab,
|
2006-12-05 21:59:12 +00:00
|
|
|
isc_region_t *intoken, isc_buffer_t **outtoken,
|
2006-12-04 01:54:53 +00:00
|
|
|
gss_ctx_id_t *ctxout, dns_name_t *principal,
|
|
|
|
isc_mem_t *mctx)
|
2000-10-07 00:45:13 +00:00
|
|
|
{
|
2006-12-04 01:54:53 +00:00
|
|
|
#ifdef GSSAPI
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_region_t r;
|
|
|
|
isc_buffer_t namebuf;
|
2008-04-03 00:45:23 +00:00
|
|
|
gss_buffer_desc gnamebuf = GSS_C_EMPTY_BUFFER, gintoken,
|
2008-04-03 06:09:05 +00:00
|
|
|
gouttoken = GSS_C_EMPTY_BUFFER;
|
2006-12-04 01:54:53 +00:00
|
|
|
OM_uint32 gret, minor;
|
|
|
|
gss_ctx_id_t context = GSS_C_NO_CONTEXT;
|
|
|
|
gss_name_t gname = NULL;
|
2000-10-07 00:45:13 +00:00
|
|
|
isc_result_t result;
|
2006-12-04 01:54:53 +00:00
|
|
|
char buf[1024];
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2006-12-05 21:59:12 +00:00
|
|
|
REQUIRE(outtoken != NULL && *outtoken == NULL);
|
|
|
|
|
2000-10-07 00:45:13 +00:00
|
|
|
REGION_TO_GBUFFER(*intoken, gintoken);
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
if (*ctxout == NULL)
|
|
|
|
context = GSS_C_NO_CONTEXT;
|
|
|
|
else
|
|
|
|
context = *ctxout;
|
|
|
|
|
2010-12-18 14:46:21 +00:00
|
|
|
if (gssapi_keytab != NULL) {
|
2013-12-04 12:47:23 +11:00
|
|
|
#if defined(ISC_PLATFORM_GSSAPI_KRB5_HEADER) || defined(WIN32)
|
2010-12-18 14:46:21 +00:00
|
|
|
gret = gsskrb5_register_acceptor_identity(gssapi_keytab);
|
|
|
|
if (gret != GSS_S_COMPLETE) {
|
|
|
|
gss_log(3, "failed "
|
|
|
|
"gsskrb5_register_acceptor_identity(%s): %s",
|
|
|
|
gssapi_keytab,
|
2011-08-29 06:33:25 +00:00
|
|
|
gss_error_tostring(gret, 0, buf, sizeof(buf)));
|
2010-12-18 14:46:21 +00:00
|
|
|
return (DNS_R_INVALIDTKEY);
|
|
|
|
}
|
2011-01-08 00:33:12 +00:00
|
|
|
#else
|
2011-01-10 03:49:49 +00:00
|
|
|
/*
|
|
|
|
* 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) {
|
2017-10-03 14:54:19 +11:00
|
|
|
size_t size;
|
|
|
|
char *kt;
|
|
|
|
|
|
|
|
size = strlen(gssapi_keytab) + 13;
|
|
|
|
kt = malloc(size);
|
2011-01-10 03:49:49 +00:00
|
|
|
if (kt == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
2017-10-03 14:54:19 +11:00
|
|
|
snprintf(kt, size, "KRB5_KTNAME=%s", gssapi_keytab);
|
2011-01-10 03:49:49 +00:00
|
|
|
if (putenv(kt) != 0)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
}
|
2010-12-18 14:46:21 +00:00
|
|
|
#endif
|
2010-12-18 01:56:23 +00:00
|
|
|
}
|
|
|
|
|
2011-04-07 23:03:22 +00:00
|
|
|
log_cred(cred);
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
gret = gss_accept_sec_context(&minor, &context, cred, &gintoken,
|
|
|
|
GSS_C_NO_CHANNEL_BINDINGS, &gname,
|
|
|
|
NULL, &gouttoken, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
result = ISC_R_FAILURE;
|
|
|
|
|
|
|
|
switch (gret) {
|
|
|
|
case GSS_S_COMPLETE:
|
|
|
|
case GSS_S_CONTINUE_NEEDED:
|
|
|
|
break;
|
|
|
|
case GSS_S_DEFECTIVE_TOKEN:
|
|
|
|
case GSS_S_DEFECTIVE_CREDENTIAL:
|
|
|
|
case GSS_S_BAD_SIG:
|
|
|
|
case GSS_S_DUPLICATE_TOKEN:
|
|
|
|
case GSS_S_OLD_TOKEN:
|
|
|
|
case GSS_S_NO_CRED:
|
|
|
|
case GSS_S_CREDENTIALS_EXPIRED:
|
|
|
|
case GSS_S_BAD_BINDINGS:
|
|
|
|
case GSS_S_NO_CONTEXT:
|
|
|
|
case GSS_S_BAD_MECH:
|
|
|
|
case GSS_S_FAILURE:
|
|
|
|
result = DNS_R_INVALIDTKEY;
|
|
|
|
/* fall through */
|
|
|
|
default:
|
|
|
|
gss_log(3, "failed gss_accept_sec_context: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
|
|
|
return (result);
|
|
|
|
}
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2011-03-28 05:20:08 +00:00
|
|
|
if (gouttoken.length > 0U) {
|
2013-12-04 12:47:23 +11:00
|
|
|
RETERR(isc_buffer_allocate(mctx, outtoken,
|
|
|
|
(unsigned int)gouttoken.length));
|
2006-12-04 01:54:53 +00:00
|
|
|
GBUFFER_TO_REGION(gouttoken, r);
|
2006-12-05 21:59:12 +00:00
|
|
|
RETERR(isc_buffer_copyregion(*outtoken, &r));
|
2008-04-03 00:45:23 +00:00
|
|
|
(void)gss_release_buffer(&minor, &gouttoken);
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
if (gret == GSS_S_COMPLETE) {
|
|
|
|
gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
|
|
|
|
if (gret != GSS_S_COMPLETE) {
|
|
|
|
gss_log(3, "failed gss_display_name: %s",
|
|
|
|
gss_error_tostring(gret, minor,
|
|
|
|
buf, sizeof(buf)));
|
|
|
|
RETERR(ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compensate for a bug in Solaris8's implementation
|
|
|
|
* of gss_display_name(). Should be harmless in any
|
|
|
|
* case, since principal names really should not
|
|
|
|
* contain null characters.
|
|
|
|
*/
|
2011-03-28 05:20:08 +00:00
|
|
|
if (gnamebuf.length > 0U &&
|
2006-12-04 01:54:53 +00:00
|
|
|
((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
|
|
|
|
gnamebuf.length--;
|
|
|
|
|
|
|
|
gss_log(3, "gss-api source name (accept) is %.*s",
|
|
|
|
(int)gnamebuf.length, (char *)gnamebuf.value);
|
|
|
|
|
|
|
|
GBUFFER_TO_REGION(gnamebuf, r);
|
|
|
|
isc_buffer_init(&namebuf, r.base, r.length);
|
|
|
|
isc_buffer_add(&namebuf, r.length);
|
|
|
|
|
|
|
|
RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname,
|
2009-09-01 00:22:28 +00:00
|
|
|
0, NULL));
|
2006-12-04 01:54:53 +00:00
|
|
|
|
2011-03-28 05:20:08 +00:00
|
|
|
if (gnamebuf.length != 0U) {
|
2008-04-03 00:45:23 +00:00
|
|
|
gret = gss_release_buffer(&minor, &gnamebuf);
|
|
|
|
if (gret != GSS_S_COMPLETE)
|
|
|
|
gss_log(3, "failed gss_release_buffer: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf,
|
|
|
|
sizeof(buf)));
|
|
|
|
}
|
2016-07-14 15:06:28 +10:00
|
|
|
} else
|
|
|
|
result = DNS_R_CONTINUE;
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
*ctxout = context;
|
2000-10-07 00:45:13 +00:00
|
|
|
|
|
|
|
out:
|
2006-12-04 01:54:53 +00:00
|
|
|
if (gname != NULL) {
|
|
|
|
gret = gss_release_name(&minor, &gname);
|
|
|
|
if (gret != GSS_S_COMPLETE)
|
|
|
|
gss_log(3, "failed gss_release_name: %s",
|
|
|
|
gss_error_tostring(gret, minor, buf,
|
|
|
|
sizeof(buf)));
|
|
|
|
}
|
2000-10-07 00:45:13 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
return (result);
|
2000-10-07 00:45:13 +00:00
|
|
|
#else
|
|
|
|
UNUSED(cred);
|
2010-12-18 01:56:23 +00:00
|
|
|
UNUSED(gssapi_keytab);
|
2000-10-07 00:45:13 +00:00
|
|
|
UNUSED(intoken);
|
|
|
|
UNUSED(outtoken);
|
2006-12-04 01:54:53 +00:00
|
|
|
UNUSED(ctxout);
|
|
|
|
UNUSED(principal);
|
|
|
|
UNUSED(mctx);
|
|
|
|
|
2000-10-07 00:45:13 +00:00
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
2006-12-04 01:54:53 +00:00
|
|
|
#endif
|
2000-10-07 00:45:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2006-12-04 01:54:53 +00:00
|
|
|
dst_gssapi_deletectx(isc_mem_t *mctx, gss_ctx_id_t *gssctx)
|
2000-10-07 00:45:13 +00:00
|
|
|
{
|
2006-12-04 01:54:53 +00:00
|
|
|
#ifdef GSSAPI
|
|
|
|
OM_uint32 gret, minor;
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
UNUSED(mctx);
|
|
|
|
|
|
|
|
REQUIRE(gssctx != NULL && *gssctx != NULL);
|
|
|
|
|
|
|
|
/* Delete the context from the GSS provider */
|
|
|
|
gret = gss_delete_sec_context(&minor, gssctx, GSS_C_NO_BUFFER);
|
|
|
|
if (gret != GSS_S_COMPLETE) {
|
|
|
|
/* Log the error, but still free the context's memory */
|
|
|
|
gss_log(3, "Failure deleting security context %s",
|
|
|
|
gss_error_tostring(gret, minor, buf, sizeof(buf)));
|
|
|
|
}
|
|
|
|
return(ISC_R_SUCCESS);
|
|
|
|
#else
|
|
|
|
UNUSED(mctx);
|
|
|
|
UNUSED(gssctx);
|
2000-10-07 00:45:13 +00:00
|
|
|
return (ISC_R_NOTIMPLEMENTED);
|
2006-12-04 01:54:53 +00:00
|
|
|
#endif
|
2000-10-07 00:45:13 +00:00
|
|
|
}
|
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
char *
|
2018-03-28 14:19:37 +02:00
|
|
|
gss_error_tostring(uint32_t major, uint32_t minor,
|
2006-12-04 01:54:53 +00:00
|
|
|
char *buf, size_t buflen) {
|
|
|
|
#ifdef GSSAPI
|
2008-04-03 00:45:23 +00:00
|
|
|
gss_buffer_desc msg_minor = GSS_C_EMPTY_BUFFER,
|
2008-04-03 06:09:05 +00:00
|
|
|
msg_major = GSS_C_EMPTY_BUFFER;
|
2006-12-04 01:54:53 +00:00
|
|
|
OM_uint32 msg_ctx, minor_stat;
|
|
|
|
|
|
|
|
/* Handle major status */
|
|
|
|
msg_ctx = 0;
|
|
|
|
(void)gss_display_status(&minor_stat, major, GSS_C_GSS_CODE,
|
2008-01-22 23:28:04 +00:00
|
|
|
GSS_C_NULL_OID, &msg_ctx, &msg_major);
|
2006-12-04 01:54:53 +00:00
|
|
|
|
|
|
|
/* Handle minor status */
|
|
|
|
msg_ctx = 0;
|
|
|
|
(void)gss_display_status(&minor_stat, minor, GSS_C_MECH_CODE,
|
|
|
|
GSS_C_NULL_OID, &msg_ctx, &msg_minor);
|
|
|
|
|
|
|
|
snprintf(buf, buflen, "GSSAPI error: Major = %s, Minor = %s.",
|
|
|
|
(char *)msg_major.value, (char *)msg_minor.value);
|
2008-01-22 23:28:04 +00:00
|
|
|
|
2011-03-28 05:20:08 +00:00
|
|
|
if (msg_major.length != 0U)
|
2008-04-03 00:45:23 +00:00
|
|
|
(void)gss_release_buffer(&minor_stat, &msg_major);
|
2011-03-28 05:20:08 +00:00
|
|
|
if (msg_minor.length != 0U)
|
2008-04-03 00:45:23 +00:00
|
|
|
(void)gss_release_buffer(&minor_stat, &msg_minor);
|
2006-12-04 01:54:53 +00:00
|
|
|
return(buf);
|
|
|
|
#else
|
|
|
|
snprintf(buf, buflen, "GSSAPI error: Major = %u, Minor = %u.",
|
|
|
|
major, minor);
|
2008-01-22 23:28:04 +00:00
|
|
|
|
2006-12-04 01:54:53 +00:00
|
|
|
return (buf);
|
2000-10-07 00:45:13 +00:00
|
|
|
#endif
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gss_log(int level, const char *fmt, ...) {
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
|
|
|
|
DNS_LOGMODULE_TKEY, ISC_LOG_DEBUG(level), fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
2005-04-27 04:57:32 +00:00
|
|
|
|
|
|
|
/*! \file */
|