1*00b67f09SDavid van Moolenbroek /* $NetBSD: gssapictx.c,v 1.8 2014/12/10 04:37:58 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 2000, 2001 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: gssapictx.c,v 1.29 2011/08/29 06:33:25 marka Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek #include <config.h>
23*00b67f09SDavid van Moolenbroek
24*00b67f09SDavid van Moolenbroek #include <ctype.h>
25*00b67f09SDavid van Moolenbroek #include <stdlib.h>
26*00b67f09SDavid van Moolenbroek #include <string.h>
27*00b67f09SDavid van Moolenbroek
28*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
29*00b67f09SDavid van Moolenbroek #include <isc/dir.h>
30*00b67f09SDavid van Moolenbroek #include <isc/entropy.h>
31*00b67f09SDavid van Moolenbroek #include <isc/file.h>
32*00b67f09SDavid van Moolenbroek #include <isc/lex.h>
33*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
34*00b67f09SDavid van Moolenbroek #include <isc/once.h>
35*00b67f09SDavid van Moolenbroek #include <isc/print.h>
36*00b67f09SDavid van Moolenbroek #include <isc/platform.h>
37*00b67f09SDavid van Moolenbroek #include <isc/random.h>
38*00b67f09SDavid van Moolenbroek #include <isc/string.h>
39*00b67f09SDavid van Moolenbroek #include <isc/time.h>
40*00b67f09SDavid van Moolenbroek #include <isc/util.h>
41*00b67f09SDavid van Moolenbroek
42*00b67f09SDavid van Moolenbroek #include <dns/fixedname.h>
43*00b67f09SDavid van Moolenbroek #include <dns/name.h>
44*00b67f09SDavid van Moolenbroek #include <dns/rdata.h>
45*00b67f09SDavid van Moolenbroek #include <dns/rdataclass.h>
46*00b67f09SDavid van Moolenbroek #include <dns/result.h>
47*00b67f09SDavid van Moolenbroek #include <dns/types.h>
48*00b67f09SDavid van Moolenbroek #include <dns/keyvalues.h>
49*00b67f09SDavid van Moolenbroek #include <dns/log.h>
50*00b67f09SDavid van Moolenbroek
51*00b67f09SDavid van Moolenbroek #include <dst/gssapi.h>
52*00b67f09SDavid van Moolenbroek #include <dst/result.h>
53*00b67f09SDavid van Moolenbroek
54*00b67f09SDavid van Moolenbroek #include "dst_internal.h"
55*00b67f09SDavid van Moolenbroek
56*00b67f09SDavid van Moolenbroek /*
57*00b67f09SDavid van Moolenbroek * If we're using our own SPNEGO implementation (see configure.in),
58*00b67f09SDavid van Moolenbroek * pull it in now. Otherwise, we just use whatever GSSAPI supplies.
59*00b67f09SDavid van Moolenbroek */
60*00b67f09SDavid van Moolenbroek #if defined(GSSAPI) && defined(USE_ISC_SPNEGO)
61*00b67f09SDavid van Moolenbroek #include "spnego.h"
62*00b67f09SDavid van Moolenbroek #define gss_accept_sec_context gss_accept_sec_context_spnego
63*00b67f09SDavid van Moolenbroek #define gss_init_sec_context gss_init_sec_context_spnego
64*00b67f09SDavid van Moolenbroek #endif
65*00b67f09SDavid van Moolenbroek
66*00b67f09SDavid van Moolenbroek /*
67*00b67f09SDavid van Moolenbroek * Solaris8 apparently needs an explicit OID set, and Solaris10 needs
68*00b67f09SDavid van Moolenbroek * one for anything but Kerberos. Supplying an explicit OID set
69*00b67f09SDavid van Moolenbroek * doesn't appear to hurt anything in other implementations, so we
70*00b67f09SDavid van Moolenbroek * always use one. If we're not using our own SPNEGO implementation,
71*00b67f09SDavid van Moolenbroek * we include SPNEGO's OID.
72*00b67f09SDavid van Moolenbroek */
73*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
74*00b67f09SDavid van Moolenbroek #ifdef WIN32
75*00b67f09SDavid van Moolenbroek #include <krb5/krb5.h>
76*00b67f09SDavid van Moolenbroek #else
77*00b67f09SDavid van Moolenbroek #include ISC_PLATFORM_KRB5HEADER
78*00b67f09SDavid van Moolenbroek #endif
79*00b67f09SDavid van Moolenbroek
80*00b67f09SDavid van Moolenbroek static unsigned char krb5_mech_oid_bytes[] = {
81*00b67f09SDavid van Moolenbroek 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02
82*00b67f09SDavid van Moolenbroek };
83*00b67f09SDavid van Moolenbroek
84*00b67f09SDavid van Moolenbroek #ifndef USE_ISC_SPNEGO
85*00b67f09SDavid van Moolenbroek static unsigned char spnego_mech_oid_bytes[] = {
86*00b67f09SDavid van Moolenbroek 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02
87*00b67f09SDavid van Moolenbroek };
88*00b67f09SDavid van Moolenbroek #endif
89*00b67f09SDavid van Moolenbroek
90*00b67f09SDavid van Moolenbroek static gss_OID_desc mech_oid_set_array[] = {
91*00b67f09SDavid van Moolenbroek { sizeof(krb5_mech_oid_bytes), krb5_mech_oid_bytes },
92*00b67f09SDavid van Moolenbroek #ifndef USE_ISC_SPNEGO
93*00b67f09SDavid van Moolenbroek { sizeof(spnego_mech_oid_bytes), spnego_mech_oid_bytes },
94*00b67f09SDavid van Moolenbroek #endif
95*00b67f09SDavid van Moolenbroek };
96*00b67f09SDavid van Moolenbroek
97*00b67f09SDavid van Moolenbroek static gss_OID_set_desc mech_oid_set = {
98*00b67f09SDavid van Moolenbroek sizeof(mech_oid_set_array) / sizeof(*mech_oid_set_array),
99*00b67f09SDavid van Moolenbroek mech_oid_set_array
100*00b67f09SDavid van Moolenbroek };
101*00b67f09SDavid van Moolenbroek
102*00b67f09SDavid van Moolenbroek #endif
103*00b67f09SDavid van Moolenbroek
104*00b67f09SDavid van Moolenbroek #define REGION_TO_GBUFFER(r, gb) \
105*00b67f09SDavid van Moolenbroek do { \
106*00b67f09SDavid van Moolenbroek (gb).length = (r).length; \
107*00b67f09SDavid van Moolenbroek (gb).value = (r).base; \
108*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
109*00b67f09SDavid van Moolenbroek
110*00b67f09SDavid van Moolenbroek #define GBUFFER_TO_REGION(gb, r) \
111*00b67f09SDavid van Moolenbroek do { \
112*00b67f09SDavid van Moolenbroek (r).length = (unsigned int)(gb).length; \
113*00b67f09SDavid van Moolenbroek (r).base = (gb).value; \
114*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
115*00b67f09SDavid van Moolenbroek
116*00b67f09SDavid van Moolenbroek
117*00b67f09SDavid van Moolenbroek #define RETERR(x) do { \
118*00b67f09SDavid van Moolenbroek result = (x); \
119*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) \
120*00b67f09SDavid van Moolenbroek goto out; \
121*00b67f09SDavid van Moolenbroek } while (/*CONSTCOND*/0)
122*00b67f09SDavid van Moolenbroek
123*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
124*00b67f09SDavid van Moolenbroek static inline void
name_to_gbuffer(dns_name_t * name,isc_buffer_t * buffer,gss_buffer_desc * gbuffer)125*00b67f09SDavid van Moolenbroek name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer,
126*00b67f09SDavid van Moolenbroek gss_buffer_desc *gbuffer)
127*00b67f09SDavid van Moolenbroek {
128*00b67f09SDavid van Moolenbroek dns_name_t tname, *namep;
129*00b67f09SDavid van Moolenbroek isc_region_t r;
130*00b67f09SDavid van Moolenbroek isc_result_t result;
131*00b67f09SDavid van Moolenbroek
132*00b67f09SDavid van Moolenbroek if (!dns_name_isabsolute(name))
133*00b67f09SDavid van Moolenbroek namep = name;
134*00b67f09SDavid van Moolenbroek else
135*00b67f09SDavid van Moolenbroek {
136*00b67f09SDavid van Moolenbroek unsigned int labels;
137*00b67f09SDavid van Moolenbroek dns_name_init(&tname, NULL);
138*00b67f09SDavid van Moolenbroek labels = dns_name_countlabels(name);
139*00b67f09SDavid van Moolenbroek dns_name_getlabelsequence(name, 0, labels - 1, &tname);
140*00b67f09SDavid van Moolenbroek namep = &tname;
141*00b67f09SDavid van Moolenbroek }
142*00b67f09SDavid van Moolenbroek
143*00b67f09SDavid van Moolenbroek result = dns_name_toprincipal(namep, buffer);
144*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(result == ISC_R_SUCCESS);
145*00b67f09SDavid van Moolenbroek isc_buffer_putuint8(buffer, 0);
146*00b67f09SDavid van Moolenbroek isc_buffer_usedregion(buffer, &r);
147*00b67f09SDavid van Moolenbroek REGION_TO_GBUFFER(r, *gbuffer);
148*00b67f09SDavid van Moolenbroek }
149*00b67f09SDavid van Moolenbroek
150*00b67f09SDavid van Moolenbroek static void
log_cred(const gss_cred_id_t cred)151*00b67f09SDavid van Moolenbroek log_cred(const gss_cred_id_t cred) {
152*00b67f09SDavid van Moolenbroek OM_uint32 gret, minor, lifetime;
153*00b67f09SDavid van Moolenbroek gss_name_t gname;
154*00b67f09SDavid van Moolenbroek gss_buffer_desc gbuffer;
155*00b67f09SDavid van Moolenbroek gss_cred_usage_t usage;
156*00b67f09SDavid van Moolenbroek const char *usage_text;
157*00b67f09SDavid van Moolenbroek char buf[1024];
158*00b67f09SDavid van Moolenbroek
159*00b67f09SDavid van Moolenbroek gret = gss_inquire_cred(&minor, cred, &gname, &lifetime, &usage, NULL);
160*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
161*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_inquire_cred: %s",
162*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf, sizeof(buf)));
163*00b67f09SDavid van Moolenbroek return;
164*00b67f09SDavid van Moolenbroek }
165*00b67f09SDavid van Moolenbroek
166*00b67f09SDavid van Moolenbroek gret = gss_display_name(&minor, gname, &gbuffer, NULL);
167*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE)
168*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_display_name: %s",
169*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf, sizeof(buf)));
170*00b67f09SDavid van Moolenbroek else {
171*00b67f09SDavid van Moolenbroek switch (usage) {
172*00b67f09SDavid van Moolenbroek case GSS_C_BOTH:
173*00b67f09SDavid van Moolenbroek usage_text = "GSS_C_BOTH";
174*00b67f09SDavid van Moolenbroek break;
175*00b67f09SDavid van Moolenbroek case GSS_C_INITIATE:
176*00b67f09SDavid van Moolenbroek usage_text = "GSS_C_INITIATE";
177*00b67f09SDavid van Moolenbroek break;
178*00b67f09SDavid van Moolenbroek case GSS_C_ACCEPT:
179*00b67f09SDavid van Moolenbroek usage_text = "GSS_C_ACCEPT";
180*00b67f09SDavid van Moolenbroek break;
181*00b67f09SDavid van Moolenbroek default:
182*00b67f09SDavid van Moolenbroek usage_text = "???";
183*00b67f09SDavid van Moolenbroek }
184*00b67f09SDavid van Moolenbroek gss_log(3, "gss cred: \"%s\", %s, %lu", (char *)gbuffer.value,
185*00b67f09SDavid van Moolenbroek usage_text, (unsigned long)lifetime);
186*00b67f09SDavid van Moolenbroek }
187*00b67f09SDavid van Moolenbroek
188*00b67f09SDavid van Moolenbroek if (gret == GSS_S_COMPLETE) {
189*00b67f09SDavid van Moolenbroek if (gbuffer.length != 0U) {
190*00b67f09SDavid van Moolenbroek gret = gss_release_buffer(&minor, &gbuffer);
191*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE)
192*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_release_buffer: %s",
193*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf,
194*00b67f09SDavid van Moolenbroek sizeof(buf)));
195*00b67f09SDavid van Moolenbroek }
196*00b67f09SDavid van Moolenbroek }
197*00b67f09SDavid van Moolenbroek
198*00b67f09SDavid van Moolenbroek gret = gss_release_name(&minor, &gname);
199*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE)
200*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_release_name: %s",
201*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf, sizeof(buf)));
202*00b67f09SDavid van Moolenbroek }
203*00b67f09SDavid van Moolenbroek #endif
204*00b67f09SDavid van Moolenbroek
205*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
206*00b67f09SDavid van Moolenbroek /*
207*00b67f09SDavid van Moolenbroek * check for the most common configuration errors.
208*00b67f09SDavid van Moolenbroek *
209*00b67f09SDavid van Moolenbroek * The errors checked for are:
210*00b67f09SDavid van Moolenbroek * - tkey-gssapi-credential doesn't start with DNS/
211*00b67f09SDavid van Moolenbroek * - the default realm in /etc/krb5.conf and the
212*00b67f09SDavid van Moolenbroek * tkey-gssapi-credential bind config option don't match
213*00b67f09SDavid van Moolenbroek *
214*00b67f09SDavid van Moolenbroek * Note that if tkey-gssapi-keytab is set then these configure checks
215*00b67f09SDavid van Moolenbroek * are not performed, and runtime errors from gssapi are used instead
216*00b67f09SDavid van Moolenbroek */
217*00b67f09SDavid van Moolenbroek static void
check_config(const char * gss_name)218*00b67f09SDavid van Moolenbroek check_config(const char *gss_name) {
219*00b67f09SDavid van Moolenbroek const char *p;
220*00b67f09SDavid van Moolenbroek krb5_context krb5_ctx;
221*00b67f09SDavid van Moolenbroek char *krb5_realm = NULL;
222*00b67f09SDavid van Moolenbroek
223*00b67f09SDavid van Moolenbroek if (strncasecmp(gss_name, "DNS/", 4) != 0) {
224*00b67f09SDavid van Moolenbroek gss_log(ISC_LOG_ERROR, "tkey-gssapi-credential (%s) "
225*00b67f09SDavid van Moolenbroek "should start with 'DNS/'", gss_name);
226*00b67f09SDavid van Moolenbroek return;
227*00b67f09SDavid van Moolenbroek }
228*00b67f09SDavid van Moolenbroek
229*00b67f09SDavid van Moolenbroek if (krb5_init_context(&krb5_ctx) != 0) {
230*00b67f09SDavid van Moolenbroek gss_log(ISC_LOG_ERROR, "Unable to initialise krb5 context");
231*00b67f09SDavid van Moolenbroek return;
232*00b67f09SDavid van Moolenbroek }
233*00b67f09SDavid van Moolenbroek if (krb5_get_default_realm(krb5_ctx, &krb5_realm) != 0) {
234*00b67f09SDavid van Moolenbroek gss_log(ISC_LOG_ERROR, "Unable to get krb5 default realm");
235*00b67f09SDavid van Moolenbroek krb5_free_context(krb5_ctx);
236*00b67f09SDavid van Moolenbroek return;
237*00b67f09SDavid van Moolenbroek }
238*00b67f09SDavid van Moolenbroek p = strchr(gss_name, '@');
239*00b67f09SDavid van Moolenbroek if (p == NULL) {
240*00b67f09SDavid van Moolenbroek gss_log(ISC_LOG_ERROR, "badly formatted "
241*00b67f09SDavid van Moolenbroek "tkey-gssapi-credentials (%s)", gss_name);
242*00b67f09SDavid van Moolenbroek krb5_free_context(krb5_ctx);
243*00b67f09SDavid van Moolenbroek return;
244*00b67f09SDavid van Moolenbroek }
245*00b67f09SDavid van Moolenbroek if (strcasecmp(p + 1, krb5_realm) != 0) {
246*00b67f09SDavid van Moolenbroek gss_log(ISC_LOG_ERROR, "default realm from krb5.conf (%s) "
247*00b67f09SDavid van Moolenbroek "does not match tkey-gssapi-credential (%s)",
248*00b67f09SDavid van Moolenbroek krb5_realm, gss_name);
249*00b67f09SDavid van Moolenbroek krb5_free_context(krb5_ctx);
250*00b67f09SDavid van Moolenbroek return;
251*00b67f09SDavid van Moolenbroek }
252*00b67f09SDavid van Moolenbroek krb5_free_context(krb5_ctx);
253*00b67f09SDavid van Moolenbroek }
254*00b67f09SDavid van Moolenbroek #endif
255*00b67f09SDavid van Moolenbroek
256*00b67f09SDavid van Moolenbroek isc_result_t
dst_gssapi_acquirecred(dns_name_t * name,isc_boolean_t initiate,gss_cred_id_t * cred)257*00b67f09SDavid van Moolenbroek dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate,
258*00b67f09SDavid van Moolenbroek gss_cred_id_t *cred)
259*00b67f09SDavid van Moolenbroek {
260*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
261*00b67f09SDavid van Moolenbroek isc_result_t result;
262*00b67f09SDavid van Moolenbroek isc_buffer_t namebuf;
263*00b67f09SDavid van Moolenbroek gss_name_t gname;
264*00b67f09SDavid van Moolenbroek gss_buffer_desc gnamebuf;
265*00b67f09SDavid van Moolenbroek unsigned char array[DNS_NAME_MAXTEXT + 1];
266*00b67f09SDavid van Moolenbroek OM_uint32 gret, minor;
267*00b67f09SDavid van Moolenbroek OM_uint32 lifetime;
268*00b67f09SDavid van Moolenbroek gss_cred_usage_t usage;
269*00b67f09SDavid van Moolenbroek char buf[1024];
270*00b67f09SDavid van Moolenbroek
271*00b67f09SDavid van Moolenbroek REQUIRE(cred != NULL && *cred == NULL);
272*00b67f09SDavid van Moolenbroek
273*00b67f09SDavid van Moolenbroek /*
274*00b67f09SDavid van Moolenbroek * XXXSRA In theory we could use GSS_C_NT_HOSTBASED_SERVICE
275*00b67f09SDavid van Moolenbroek * here when we're in the acceptor role, which would let us
276*00b67f09SDavid van Moolenbroek * default the hostname and use a compiled in default service
277*00b67f09SDavid van Moolenbroek * name of "DNS", giving one less thing to configure in
278*00b67f09SDavid van Moolenbroek * named.conf. Unfortunately, this creates a circular
279*00b67f09SDavid van Moolenbroek * dependency due to DNS-based realm lookup in at least one
280*00b67f09SDavid van Moolenbroek * GSSAPI implementation (Heimdal). Oh well.
281*00b67f09SDavid van Moolenbroek */
282*00b67f09SDavid van Moolenbroek if (name != NULL) {
283*00b67f09SDavid van Moolenbroek isc_buffer_init(&namebuf, array, sizeof(array));
284*00b67f09SDavid van Moolenbroek name_to_gbuffer(name, &namebuf, &gnamebuf);
285*00b67f09SDavid van Moolenbroek gret = gss_import_name(&minor, &gnamebuf,
286*00b67f09SDavid van Moolenbroek GSS_C_NO_OID, &gname);
287*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
288*00b67f09SDavid van Moolenbroek check_config((char *)array);
289*00b67f09SDavid van Moolenbroek
290*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_import_name: %s",
291*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf,
292*00b67f09SDavid van Moolenbroek sizeof(buf)));
293*00b67f09SDavid van Moolenbroek return (ISC_R_FAILURE);
294*00b67f09SDavid van Moolenbroek }
295*00b67f09SDavid van Moolenbroek } else
296*00b67f09SDavid van Moolenbroek gname = NULL;
297*00b67f09SDavid van Moolenbroek
298*00b67f09SDavid van Moolenbroek /* Get the credentials. */
299*00b67f09SDavid van Moolenbroek if (gname != NULL)
300*00b67f09SDavid van Moolenbroek gss_log(3, "acquiring credentials for %s",
301*00b67f09SDavid van Moolenbroek (char *)gnamebuf.value);
302*00b67f09SDavid van Moolenbroek else {
303*00b67f09SDavid van Moolenbroek /* XXXDCL does this even make any sense? */
304*00b67f09SDavid van Moolenbroek gss_log(3, "acquiring credentials for ?");
305*00b67f09SDavid van Moolenbroek }
306*00b67f09SDavid van Moolenbroek
307*00b67f09SDavid van Moolenbroek if (initiate)
308*00b67f09SDavid van Moolenbroek usage = GSS_C_INITIATE;
309*00b67f09SDavid van Moolenbroek else
310*00b67f09SDavid van Moolenbroek usage = GSS_C_ACCEPT;
311*00b67f09SDavid van Moolenbroek
312*00b67f09SDavid van Moolenbroek gret = gss_acquire_cred(&minor, gname, GSS_C_INDEFINITE,
313*00b67f09SDavid van Moolenbroek &mech_oid_set, usage, cred, NULL, &lifetime);
314*00b67f09SDavid van Moolenbroek
315*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
316*00b67f09SDavid van Moolenbroek gss_log(3, "failed to acquire %s credentials for %s: %s",
317*00b67f09SDavid van Moolenbroek initiate ? "initiate" : "accept",
318*00b67f09SDavid van Moolenbroek (gname != NULL) ? (char *)gnamebuf.value : "?",
319*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf, sizeof(buf)));
320*00b67f09SDavid van Moolenbroek if (gname != NULL)
321*00b67f09SDavid van Moolenbroek check_config((char *)array);
322*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
323*00b67f09SDavid van Moolenbroek goto cleanup;
324*00b67f09SDavid van Moolenbroek }
325*00b67f09SDavid van Moolenbroek
326*00b67f09SDavid van Moolenbroek gss_log(4, "acquired %s credentials for %s",
327*00b67f09SDavid van Moolenbroek initiate ? "initiate" : "accept",
328*00b67f09SDavid van Moolenbroek (gname != NULL) ? (char *)gnamebuf.value : "?");
329*00b67f09SDavid van Moolenbroek
330*00b67f09SDavid van Moolenbroek log_cred(*cred);
331*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
332*00b67f09SDavid van Moolenbroek
333*00b67f09SDavid van Moolenbroek cleanup:
334*00b67f09SDavid van Moolenbroek if (gname != NULL) {
335*00b67f09SDavid van Moolenbroek gret = gss_release_name(&minor, &gname);
336*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE)
337*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_release_name: %s",
338*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf,
339*00b67f09SDavid van Moolenbroek sizeof(buf)));
340*00b67f09SDavid van Moolenbroek }
341*00b67f09SDavid van Moolenbroek
342*00b67f09SDavid van Moolenbroek return (result);
343*00b67f09SDavid van Moolenbroek #else
344*00b67f09SDavid van Moolenbroek REQUIRE(cred != NULL && *cred == NULL);
345*00b67f09SDavid van Moolenbroek
346*00b67f09SDavid van Moolenbroek UNUSED(name);
347*00b67f09SDavid van Moolenbroek UNUSED(initiate);
348*00b67f09SDavid van Moolenbroek UNUSED(cred);
349*00b67f09SDavid van Moolenbroek
350*00b67f09SDavid van Moolenbroek return (ISC_R_NOTIMPLEMENTED);
351*00b67f09SDavid van Moolenbroek #endif
352*00b67f09SDavid van Moolenbroek }
353*00b67f09SDavid van Moolenbroek
354*00b67f09SDavid van Moolenbroek isc_boolean_t
dst_gssapi_identitymatchesrealmkrb5(dns_name_t * signer,dns_name_t * name,dns_name_t * realm)355*00b67f09SDavid van Moolenbroek dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name,
356*00b67f09SDavid van Moolenbroek dns_name_t *realm)
357*00b67f09SDavid van Moolenbroek {
358*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
359*00b67f09SDavid van Moolenbroek char sbuf[DNS_NAME_FORMATSIZE];
360*00b67f09SDavid van Moolenbroek char nbuf[DNS_NAME_FORMATSIZE];
361*00b67f09SDavid van Moolenbroek char rbuf[DNS_NAME_FORMATSIZE];
362*00b67f09SDavid van Moolenbroek char *sname;
363*00b67f09SDavid van Moolenbroek char *rname;
364*00b67f09SDavid van Moolenbroek isc_buffer_t buffer;
365*00b67f09SDavid van Moolenbroek isc_result_t result;
366*00b67f09SDavid van Moolenbroek
367*00b67f09SDavid van Moolenbroek /*
368*00b67f09SDavid van Moolenbroek * It is far, far easier to write the names we are looking at into
369*00b67f09SDavid van Moolenbroek * a string, and do string operations on them.
370*00b67f09SDavid van Moolenbroek */
371*00b67f09SDavid van Moolenbroek isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
372*00b67f09SDavid van Moolenbroek result = dns_name_toprincipal(signer, &buffer);
373*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(result == ISC_R_SUCCESS);
374*00b67f09SDavid van Moolenbroek isc_buffer_putuint8(&buffer, 0);
375*00b67f09SDavid van Moolenbroek if (name != NULL)
376*00b67f09SDavid van Moolenbroek dns_name_format(name, nbuf, sizeof(nbuf));
377*00b67f09SDavid van Moolenbroek dns_name_format(realm, rbuf, sizeof(rbuf));
378*00b67f09SDavid van Moolenbroek
379*00b67f09SDavid van Moolenbroek /*
380*00b67f09SDavid van Moolenbroek * Find the realm portion. This is the part after the @. If it
381*00b67f09SDavid van Moolenbroek * does not exist, we don't have something we like, so we fail our
382*00b67f09SDavid van Moolenbroek * compare.
383*00b67f09SDavid van Moolenbroek */
384*00b67f09SDavid van Moolenbroek rname = strchr(sbuf, '@');
385*00b67f09SDavid van Moolenbroek if (rname == NULL)
386*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
387*00b67f09SDavid van Moolenbroek *rname = '\0';
388*00b67f09SDavid van Moolenbroek rname++;
389*00b67f09SDavid van Moolenbroek
390*00b67f09SDavid van Moolenbroek /*
391*00b67f09SDavid van Moolenbroek * Find the host portion of the signer's name. We do this by
392*00b67f09SDavid van Moolenbroek * searching for the first / character. We then check to make
393*00b67f09SDavid van Moolenbroek * certain the instance name is "host"
394*00b67f09SDavid van Moolenbroek *
395*00b67f09SDavid van Moolenbroek * This will work for
396*00b67f09SDavid van Moolenbroek * host/example.com@EXAMPLE.COM
397*00b67f09SDavid van Moolenbroek */
398*00b67f09SDavid van Moolenbroek sname = strchr(sbuf, '/');
399*00b67f09SDavid van Moolenbroek if (sname == NULL)
400*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
401*00b67f09SDavid van Moolenbroek *sname = '\0';
402*00b67f09SDavid van Moolenbroek sname++;
403*00b67f09SDavid van Moolenbroek if (strcmp(sbuf, "host") != 0)
404*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
405*00b67f09SDavid van Moolenbroek
406*00b67f09SDavid van Moolenbroek /*
407*00b67f09SDavid van Moolenbroek * Now, we do a simple comparison between the name and the realm.
408*00b67f09SDavid van Moolenbroek */
409*00b67f09SDavid van Moolenbroek if (name != NULL) {
410*00b67f09SDavid van Moolenbroek if ((strcasecmp(sname, nbuf) == 0)
411*00b67f09SDavid van Moolenbroek && (strcmp(rname, rbuf) == 0))
412*00b67f09SDavid van Moolenbroek return (isc_boolean_true);
413*00b67f09SDavid van Moolenbroek } else {
414*00b67f09SDavid van Moolenbroek if (strcmp(rname, rbuf) == 0)
415*00b67f09SDavid van Moolenbroek return (isc_boolean_true);
416*00b67f09SDavid van Moolenbroek }
417*00b67f09SDavid van Moolenbroek
418*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
419*00b67f09SDavid van Moolenbroek #else
420*00b67f09SDavid van Moolenbroek UNUSED(signer);
421*00b67f09SDavid van Moolenbroek UNUSED(name);
422*00b67f09SDavid van Moolenbroek UNUSED(realm);
423*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
424*00b67f09SDavid van Moolenbroek #endif
425*00b67f09SDavid van Moolenbroek }
426*00b67f09SDavid van Moolenbroek
427*00b67f09SDavid van Moolenbroek isc_boolean_t
dst_gssapi_identitymatchesrealmms(dns_name_t * signer,dns_name_t * name,dns_name_t * realm)428*00b67f09SDavid van Moolenbroek dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name,
429*00b67f09SDavid van Moolenbroek dns_name_t *realm)
430*00b67f09SDavid van Moolenbroek {
431*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
432*00b67f09SDavid van Moolenbroek char sbuf[DNS_NAME_FORMATSIZE];
433*00b67f09SDavid van Moolenbroek char nbuf[DNS_NAME_FORMATSIZE];
434*00b67f09SDavid van Moolenbroek char rbuf[DNS_NAME_FORMATSIZE];
435*00b67f09SDavid van Moolenbroek char *sname;
436*00b67f09SDavid van Moolenbroek char *nname;
437*00b67f09SDavid van Moolenbroek char *rname;
438*00b67f09SDavid van Moolenbroek isc_buffer_t buffer;
439*00b67f09SDavid van Moolenbroek isc_result_t result;
440*00b67f09SDavid van Moolenbroek
441*00b67f09SDavid van Moolenbroek /*
442*00b67f09SDavid van Moolenbroek * It is far, far easier to write the names we are looking at into
443*00b67f09SDavid van Moolenbroek * a string, and do string operations on them.
444*00b67f09SDavid van Moolenbroek */
445*00b67f09SDavid van Moolenbroek isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
446*00b67f09SDavid van Moolenbroek result = dns_name_toprincipal(signer, &buffer);
447*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(result == ISC_R_SUCCESS);
448*00b67f09SDavid van Moolenbroek isc_buffer_putuint8(&buffer, 0);
449*00b67f09SDavid van Moolenbroek if (name != NULL)
450*00b67f09SDavid van Moolenbroek dns_name_format(name, nbuf, sizeof(nbuf));
451*00b67f09SDavid van Moolenbroek dns_name_format(realm, rbuf, sizeof(rbuf));
452*00b67f09SDavid van Moolenbroek
453*00b67f09SDavid van Moolenbroek /*
454*00b67f09SDavid van Moolenbroek * Find the realm portion. This is the part after the @. If it
455*00b67f09SDavid van Moolenbroek * does not exist, we don't have something we like, so we fail our
456*00b67f09SDavid van Moolenbroek * compare.
457*00b67f09SDavid van Moolenbroek */
458*00b67f09SDavid van Moolenbroek rname = strchr(sbuf, '@');
459*00b67f09SDavid van Moolenbroek if (rname == NULL)
460*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
461*00b67f09SDavid van Moolenbroek sname = strchr(sbuf, '$');
462*00b67f09SDavid van Moolenbroek if (sname == NULL)
463*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
464*00b67f09SDavid van Moolenbroek
465*00b67f09SDavid van Moolenbroek /*
466*00b67f09SDavid van Moolenbroek * Verify that the $ and @ follow one another.
467*00b67f09SDavid van Moolenbroek */
468*00b67f09SDavid van Moolenbroek if (rname - sname != 1)
469*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
470*00b67f09SDavid van Moolenbroek
471*00b67f09SDavid van Moolenbroek /*
472*00b67f09SDavid van Moolenbroek * Find the host portion of the signer's name. Zero out the $ so
473*00b67f09SDavid van Moolenbroek * it terminates the signer's name, and skip past the @ for
474*00b67f09SDavid van Moolenbroek * the realm.
475*00b67f09SDavid van Moolenbroek *
476*00b67f09SDavid van Moolenbroek * All service principals in Microsoft format seem to be in
477*00b67f09SDavid van Moolenbroek * machinename$@EXAMPLE.COM
478*00b67f09SDavid van Moolenbroek * format.
479*00b67f09SDavid van Moolenbroek */
480*00b67f09SDavid van Moolenbroek rname++;
481*00b67f09SDavid van Moolenbroek *sname = '\0';
482*00b67f09SDavid van Moolenbroek sname = sbuf;
483*00b67f09SDavid van Moolenbroek
484*00b67f09SDavid van Moolenbroek /*
485*00b67f09SDavid van Moolenbroek * Find the first . in the target name, and make it the end of
486*00b67f09SDavid van Moolenbroek * the string. The rest of the name has to match the realm.
487*00b67f09SDavid van Moolenbroek */
488*00b67f09SDavid van Moolenbroek if (name != NULL) {
489*00b67f09SDavid van Moolenbroek nname = strchr(nbuf, '.');
490*00b67f09SDavid van Moolenbroek if (nname == NULL)
491*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
492*00b67f09SDavid van Moolenbroek *nname++ = '\0';
493*00b67f09SDavid van Moolenbroek }
494*00b67f09SDavid van Moolenbroek
495*00b67f09SDavid van Moolenbroek /*
496*00b67f09SDavid van Moolenbroek * Now, we do a simple comparison between the name and the realm.
497*00b67f09SDavid van Moolenbroek */
498*00b67f09SDavid van Moolenbroek if (name != NULL) {
499*00b67f09SDavid van Moolenbroek if ((strcasecmp(sname, nbuf) == 0)
500*00b67f09SDavid van Moolenbroek && (strcmp(rname, rbuf) == 0)
501*00b67f09SDavid van Moolenbroek && (strcasecmp(nname, rbuf) == 0))
502*00b67f09SDavid van Moolenbroek return (isc_boolean_true);
503*00b67f09SDavid van Moolenbroek } else {
504*00b67f09SDavid van Moolenbroek if (strcmp(rname, rbuf) == 0)
505*00b67f09SDavid van Moolenbroek return (isc_boolean_true);
506*00b67f09SDavid van Moolenbroek }
507*00b67f09SDavid van Moolenbroek
508*00b67f09SDavid van Moolenbroek
509*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
510*00b67f09SDavid van Moolenbroek #else
511*00b67f09SDavid van Moolenbroek UNUSED(signer);
512*00b67f09SDavid van Moolenbroek UNUSED(name);
513*00b67f09SDavid van Moolenbroek UNUSED(realm);
514*00b67f09SDavid van Moolenbroek return (isc_boolean_false);
515*00b67f09SDavid van Moolenbroek #endif
516*00b67f09SDavid van Moolenbroek }
517*00b67f09SDavid van Moolenbroek
518*00b67f09SDavid van Moolenbroek isc_result_t
dst_gssapi_releasecred(gss_cred_id_t * cred)519*00b67f09SDavid van Moolenbroek dst_gssapi_releasecred(gss_cred_id_t *cred) {
520*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
521*00b67f09SDavid van Moolenbroek OM_uint32 gret, minor;
522*00b67f09SDavid van Moolenbroek char buf[1024];
523*00b67f09SDavid van Moolenbroek
524*00b67f09SDavid van Moolenbroek REQUIRE(cred != NULL && *cred != NULL);
525*00b67f09SDavid van Moolenbroek
526*00b67f09SDavid van Moolenbroek gret = gss_release_cred(&minor, cred);
527*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
528*00b67f09SDavid van Moolenbroek /* Log the error, but still free the credential's memory */
529*00b67f09SDavid van Moolenbroek gss_log(3, "failed releasing credential: %s",
530*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf, sizeof(buf)));
531*00b67f09SDavid van Moolenbroek }
532*00b67f09SDavid van Moolenbroek *cred = NULL;
533*00b67f09SDavid van Moolenbroek
534*00b67f09SDavid van Moolenbroek return(ISC_R_SUCCESS);
535*00b67f09SDavid van Moolenbroek #else
536*00b67f09SDavid van Moolenbroek UNUSED(cred);
537*00b67f09SDavid van Moolenbroek
538*00b67f09SDavid van Moolenbroek return (ISC_R_NOTIMPLEMENTED);
539*00b67f09SDavid van Moolenbroek #endif
540*00b67f09SDavid van Moolenbroek }
541*00b67f09SDavid van Moolenbroek
542*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
543*00b67f09SDavid van Moolenbroek /*
544*00b67f09SDavid van Moolenbroek * Format a gssapi error message info into a char ** on the given memory
545*00b67f09SDavid van Moolenbroek * context. This is used to return gssapi error messages back up the
546*00b67f09SDavid van Moolenbroek * call chain for reporting to the user.
547*00b67f09SDavid van Moolenbroek */
548*00b67f09SDavid van Moolenbroek static void
gss_err_message(isc_mem_t * mctx,isc_uint32_t major,isc_uint32_t minor,char ** err_message)549*00b67f09SDavid van Moolenbroek gss_err_message(isc_mem_t *mctx, isc_uint32_t major, isc_uint32_t minor,
550*00b67f09SDavid van Moolenbroek char **err_message)
551*00b67f09SDavid van Moolenbroek {
552*00b67f09SDavid van Moolenbroek char buf[1024];
553*00b67f09SDavid van Moolenbroek char *estr;
554*00b67f09SDavid van Moolenbroek
555*00b67f09SDavid van Moolenbroek if (err_message == NULL || mctx == NULL) {
556*00b67f09SDavid van Moolenbroek /* the caller doesn't want any error messages */
557*00b67f09SDavid van Moolenbroek return;
558*00b67f09SDavid van Moolenbroek }
559*00b67f09SDavid van Moolenbroek
560*00b67f09SDavid van Moolenbroek estr = gss_error_tostring(major, minor, buf, sizeof(buf));
561*00b67f09SDavid van Moolenbroek if (estr != NULL)
562*00b67f09SDavid van Moolenbroek (*err_message) = isc_mem_strdup(mctx, estr);
563*00b67f09SDavid van Moolenbroek }
564*00b67f09SDavid van Moolenbroek #endif
565*00b67f09SDavid van Moolenbroek
566*00b67f09SDavid van Moolenbroek isc_result_t
dst_gssapi_initctx(dns_name_t * name,isc_buffer_t * intoken,isc_buffer_t * outtoken,gss_ctx_id_t * gssctx,isc_mem_t * mctx,char ** err_message)567*00b67f09SDavid van Moolenbroek dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
568*00b67f09SDavid van Moolenbroek isc_buffer_t *outtoken, gss_ctx_id_t *gssctx,
569*00b67f09SDavid van Moolenbroek isc_mem_t *mctx, char **err_message)
570*00b67f09SDavid van Moolenbroek {
571*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
572*00b67f09SDavid van Moolenbroek isc_region_t r;
573*00b67f09SDavid van Moolenbroek isc_buffer_t namebuf;
574*00b67f09SDavid van Moolenbroek gss_name_t gname;
575*00b67f09SDavid van Moolenbroek OM_uint32 gret, minor, ret_flags, flags;
576*00b67f09SDavid van Moolenbroek gss_buffer_desc gintoken, *gintokenp, gouttoken = GSS_C_EMPTY_BUFFER;
577*00b67f09SDavid van Moolenbroek isc_result_t result;
578*00b67f09SDavid van Moolenbroek gss_buffer_desc gnamebuf;
579*00b67f09SDavid van Moolenbroek unsigned char array[DNS_NAME_MAXTEXT + 1];
580*00b67f09SDavid van Moolenbroek
581*00b67f09SDavid van Moolenbroek /* Client must pass us a valid gss_ctx_id_t here */
582*00b67f09SDavid van Moolenbroek REQUIRE(gssctx != NULL);
583*00b67f09SDavid van Moolenbroek REQUIRE(mctx != NULL);
584*00b67f09SDavid van Moolenbroek
585*00b67f09SDavid van Moolenbroek isc_buffer_init(&namebuf, array, sizeof(array));
586*00b67f09SDavid van Moolenbroek name_to_gbuffer(name, &namebuf, &gnamebuf);
587*00b67f09SDavid van Moolenbroek
588*00b67f09SDavid van Moolenbroek /* Get the name as a GSS name */
589*00b67f09SDavid van Moolenbroek gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
590*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
591*00b67f09SDavid van Moolenbroek gss_err_message(mctx, gret, minor, err_message);
592*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
593*00b67f09SDavid van Moolenbroek goto out;
594*00b67f09SDavid van Moolenbroek }
595*00b67f09SDavid van Moolenbroek
596*00b67f09SDavid van Moolenbroek if (intoken != NULL) {
597*00b67f09SDavid van Moolenbroek /* Don't call gss_release_buffer for gintoken! */
598*00b67f09SDavid van Moolenbroek REGION_TO_GBUFFER(*intoken, gintoken);
599*00b67f09SDavid van Moolenbroek gintokenp = &gintoken;
600*00b67f09SDavid van Moolenbroek } else {
601*00b67f09SDavid van Moolenbroek gintokenp = NULL;
602*00b67f09SDavid van Moolenbroek }
603*00b67f09SDavid van Moolenbroek
604*00b67f09SDavid van Moolenbroek /*
605*00b67f09SDavid van Moolenbroek * Note that we don't set GSS_C_SEQUENCE_FLAG as Windows DNS
606*00b67f09SDavid van Moolenbroek * servers don't like it.
607*00b67f09SDavid van Moolenbroek */
608*00b67f09SDavid van Moolenbroek flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
609*00b67f09SDavid van Moolenbroek
610*00b67f09SDavid van Moolenbroek gret = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, gssctx,
611*00b67f09SDavid van Moolenbroek gname, GSS_SPNEGO_MECHANISM, flags,
612*00b67f09SDavid van Moolenbroek 0, NULL, gintokenp,
613*00b67f09SDavid van Moolenbroek NULL, &gouttoken, &ret_flags, NULL);
614*00b67f09SDavid van Moolenbroek
615*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) {
616*00b67f09SDavid van Moolenbroek gss_err_message(mctx, gret, minor, err_message);
617*00b67f09SDavid van Moolenbroek if (err_message != NULL && *err_message != NULL)
618*00b67f09SDavid van Moolenbroek gss_log(3, "Failure initiating security context: %s",
619*00b67f09SDavid van Moolenbroek *err_message);
620*00b67f09SDavid van Moolenbroek else
621*00b67f09SDavid van Moolenbroek gss_log(3, "Failure initiating security context");
622*00b67f09SDavid van Moolenbroek
623*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
624*00b67f09SDavid van Moolenbroek goto out;
625*00b67f09SDavid van Moolenbroek }
626*00b67f09SDavid van Moolenbroek
627*00b67f09SDavid van Moolenbroek /*
628*00b67f09SDavid van Moolenbroek * XXXSRA Not handled yet: RFC 3645 3.1.1: check ret_flags
629*00b67f09SDavid van Moolenbroek * MUTUAL and INTEG flags, fail if either not set.
630*00b67f09SDavid van Moolenbroek */
631*00b67f09SDavid van Moolenbroek
632*00b67f09SDavid van Moolenbroek /*
633*00b67f09SDavid van Moolenbroek * RFC 2744 states the a valid output token has a non-zero length.
634*00b67f09SDavid van Moolenbroek */
635*00b67f09SDavid van Moolenbroek if (gouttoken.length != 0U) {
636*00b67f09SDavid van Moolenbroek GBUFFER_TO_REGION(gouttoken, r);
637*00b67f09SDavid van Moolenbroek RETERR(isc_buffer_copyregion(outtoken, &r));
638*00b67f09SDavid van Moolenbroek (void)gss_release_buffer(&minor, &gouttoken);
639*00b67f09SDavid van Moolenbroek }
640*00b67f09SDavid van Moolenbroek
641*00b67f09SDavid van Moolenbroek if (gret == GSS_S_COMPLETE)
642*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
643*00b67f09SDavid van Moolenbroek else
644*00b67f09SDavid van Moolenbroek result = DNS_R_CONTINUE;
645*00b67f09SDavid van Moolenbroek
646*00b67f09SDavid van Moolenbroek out:
647*00b67f09SDavid van Moolenbroek (void)gss_release_name(&minor, &gname);
648*00b67f09SDavid van Moolenbroek return (result);
649*00b67f09SDavid van Moolenbroek #else
650*00b67f09SDavid van Moolenbroek UNUSED(name);
651*00b67f09SDavid van Moolenbroek UNUSED(intoken);
652*00b67f09SDavid van Moolenbroek UNUSED(outtoken);
653*00b67f09SDavid van Moolenbroek UNUSED(gssctx);
654*00b67f09SDavid van Moolenbroek UNUSED(mctx);
655*00b67f09SDavid van Moolenbroek UNUSED(err_message);
656*00b67f09SDavid van Moolenbroek
657*00b67f09SDavid van Moolenbroek return (ISC_R_NOTIMPLEMENTED);
658*00b67f09SDavid van Moolenbroek #endif
659*00b67f09SDavid van Moolenbroek }
660*00b67f09SDavid van Moolenbroek
661*00b67f09SDavid van Moolenbroek 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)662*00b67f09SDavid van Moolenbroek dst_gssapi_acceptctx(gss_cred_id_t cred,
663*00b67f09SDavid van Moolenbroek const char *gssapi_keytab,
664*00b67f09SDavid van Moolenbroek isc_region_t *intoken, isc_buffer_t **outtoken,
665*00b67f09SDavid van Moolenbroek gss_ctx_id_t *ctxout, dns_name_t *principal,
666*00b67f09SDavid van Moolenbroek isc_mem_t *mctx)
667*00b67f09SDavid van Moolenbroek {
668*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
669*00b67f09SDavid van Moolenbroek isc_region_t r;
670*00b67f09SDavid van Moolenbroek isc_buffer_t namebuf;
671*00b67f09SDavid van Moolenbroek gss_buffer_desc gnamebuf = GSS_C_EMPTY_BUFFER, gintoken,
672*00b67f09SDavid van Moolenbroek gouttoken = GSS_C_EMPTY_BUFFER;
673*00b67f09SDavid van Moolenbroek OM_uint32 gret, minor;
674*00b67f09SDavid van Moolenbroek gss_ctx_id_t context = GSS_C_NO_CONTEXT;
675*00b67f09SDavid van Moolenbroek gss_name_t gname = NULL;
676*00b67f09SDavid van Moolenbroek isc_result_t result;
677*00b67f09SDavid van Moolenbroek char buf[1024];
678*00b67f09SDavid van Moolenbroek
679*00b67f09SDavid van Moolenbroek REQUIRE(outtoken != NULL && *outtoken == NULL);
680*00b67f09SDavid van Moolenbroek
681*00b67f09SDavid van Moolenbroek REGION_TO_GBUFFER(*intoken, gintoken);
682*00b67f09SDavid van Moolenbroek
683*00b67f09SDavid van Moolenbroek if (*ctxout == NULL)
684*00b67f09SDavid van Moolenbroek context = GSS_C_NO_CONTEXT;
685*00b67f09SDavid van Moolenbroek else
686*00b67f09SDavid van Moolenbroek context = *ctxout;
687*00b67f09SDavid van Moolenbroek
688*00b67f09SDavid van Moolenbroek if (gssapi_keytab != NULL) {
689*00b67f09SDavid van Moolenbroek #if defined(ISC_PLATFORM_GSSAPI_KRB5_HEADER) || defined(WIN32)
690*00b67f09SDavid van Moolenbroek gret = gsskrb5_register_acceptor_identity(gssapi_keytab);
691*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
692*00b67f09SDavid van Moolenbroek gss_log(3, "failed "
693*00b67f09SDavid van Moolenbroek "gsskrb5_register_acceptor_identity(%s): %s",
694*00b67f09SDavid van Moolenbroek gssapi_keytab,
695*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, 0, buf, sizeof(buf)));
696*00b67f09SDavid van Moolenbroek return (DNS_R_INVALIDTKEY);
697*00b67f09SDavid van Moolenbroek }
698*00b67f09SDavid van Moolenbroek #else
699*00b67f09SDavid van Moolenbroek /*
700*00b67f09SDavid van Moolenbroek * Minimize memory leakage by only setting KRB5_KTNAME
701*00b67f09SDavid van Moolenbroek * if it needs to change.
702*00b67f09SDavid van Moolenbroek */
703*00b67f09SDavid van Moolenbroek const char *old = getenv("KRB5_KTNAME");
704*00b67f09SDavid van Moolenbroek if (old == NULL || strcmp(old, gssapi_keytab) != 0) {
705*00b67f09SDavid van Moolenbroek char *kt = malloc(strlen(gssapi_keytab) + 13);
706*00b67f09SDavid van Moolenbroek if (kt == NULL)
707*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
708*00b67f09SDavid van Moolenbroek sprintf(kt, "KRB5_KTNAME=%s", gssapi_keytab);
709*00b67f09SDavid van Moolenbroek if (putenv(kt) != 0)
710*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
711*00b67f09SDavid van Moolenbroek }
712*00b67f09SDavid van Moolenbroek #endif
713*00b67f09SDavid van Moolenbroek }
714*00b67f09SDavid van Moolenbroek
715*00b67f09SDavid van Moolenbroek log_cred(cred);
716*00b67f09SDavid van Moolenbroek
717*00b67f09SDavid van Moolenbroek gret = gss_accept_sec_context(&minor, &context, cred, &gintoken,
718*00b67f09SDavid van Moolenbroek GSS_C_NO_CHANNEL_BINDINGS, &gname,
719*00b67f09SDavid van Moolenbroek NULL, &gouttoken, NULL, NULL, NULL);
720*00b67f09SDavid van Moolenbroek
721*00b67f09SDavid van Moolenbroek result = ISC_R_FAILURE;
722*00b67f09SDavid van Moolenbroek
723*00b67f09SDavid van Moolenbroek switch (gret) {
724*00b67f09SDavid van Moolenbroek case GSS_S_COMPLETE:
725*00b67f09SDavid van Moolenbroek result = ISC_R_SUCCESS;
726*00b67f09SDavid van Moolenbroek break;
727*00b67f09SDavid van Moolenbroek case GSS_S_CONTINUE_NEEDED:
728*00b67f09SDavid van Moolenbroek result = DNS_R_CONTINUE;
729*00b67f09SDavid van Moolenbroek break;
730*00b67f09SDavid van Moolenbroek case GSS_S_DEFECTIVE_TOKEN:
731*00b67f09SDavid van Moolenbroek case GSS_S_DEFECTIVE_CREDENTIAL:
732*00b67f09SDavid van Moolenbroek case GSS_S_BAD_SIG:
733*00b67f09SDavid van Moolenbroek case GSS_S_DUPLICATE_TOKEN:
734*00b67f09SDavid van Moolenbroek case GSS_S_OLD_TOKEN:
735*00b67f09SDavid van Moolenbroek case GSS_S_NO_CRED:
736*00b67f09SDavid van Moolenbroek case GSS_S_CREDENTIALS_EXPIRED:
737*00b67f09SDavid van Moolenbroek case GSS_S_BAD_BINDINGS:
738*00b67f09SDavid van Moolenbroek case GSS_S_NO_CONTEXT:
739*00b67f09SDavid van Moolenbroek case GSS_S_BAD_MECH:
740*00b67f09SDavid van Moolenbroek case GSS_S_FAILURE:
741*00b67f09SDavid van Moolenbroek result = DNS_R_INVALIDTKEY;
742*00b67f09SDavid van Moolenbroek /* fall through */
743*00b67f09SDavid van Moolenbroek default:
744*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_accept_sec_context: %s",
745*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf, sizeof(buf)));
746*00b67f09SDavid van Moolenbroek return (result);
747*00b67f09SDavid van Moolenbroek }
748*00b67f09SDavid van Moolenbroek
749*00b67f09SDavid van Moolenbroek if (gouttoken.length > 0U) {
750*00b67f09SDavid van Moolenbroek RETERR(isc_buffer_allocate(mctx, outtoken,
751*00b67f09SDavid van Moolenbroek (unsigned int)gouttoken.length));
752*00b67f09SDavid van Moolenbroek GBUFFER_TO_REGION(gouttoken, r);
753*00b67f09SDavid van Moolenbroek RETERR(isc_buffer_copyregion(*outtoken, &r));
754*00b67f09SDavid van Moolenbroek (void)gss_release_buffer(&minor, &gouttoken);
755*00b67f09SDavid van Moolenbroek }
756*00b67f09SDavid van Moolenbroek
757*00b67f09SDavid van Moolenbroek if (gret == GSS_S_COMPLETE) {
758*00b67f09SDavid van Moolenbroek gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
759*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
760*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_display_name: %s",
761*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor,
762*00b67f09SDavid van Moolenbroek buf, sizeof(buf)));
763*00b67f09SDavid van Moolenbroek RETERR(ISC_R_FAILURE);
764*00b67f09SDavid van Moolenbroek }
765*00b67f09SDavid van Moolenbroek
766*00b67f09SDavid van Moolenbroek /*
767*00b67f09SDavid van Moolenbroek * Compensate for a bug in Solaris8's implementation
768*00b67f09SDavid van Moolenbroek * of gss_display_name(). Should be harmless in any
769*00b67f09SDavid van Moolenbroek * case, since principal names really should not
770*00b67f09SDavid van Moolenbroek * contain null characters.
771*00b67f09SDavid van Moolenbroek */
772*00b67f09SDavid van Moolenbroek if (gnamebuf.length > 0U &&
773*00b67f09SDavid van Moolenbroek ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
774*00b67f09SDavid van Moolenbroek gnamebuf.length--;
775*00b67f09SDavid van Moolenbroek
776*00b67f09SDavid van Moolenbroek gss_log(3, "gss-api source name (accept) is %.*s",
777*00b67f09SDavid van Moolenbroek (int)gnamebuf.length, (char *)gnamebuf.value);
778*00b67f09SDavid van Moolenbroek
779*00b67f09SDavid van Moolenbroek GBUFFER_TO_REGION(gnamebuf, r);
780*00b67f09SDavid van Moolenbroek isc_buffer_init(&namebuf, r.base, r.length);
781*00b67f09SDavid van Moolenbroek isc_buffer_add(&namebuf, r.length);
782*00b67f09SDavid van Moolenbroek
783*00b67f09SDavid van Moolenbroek RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname,
784*00b67f09SDavid van Moolenbroek 0, NULL));
785*00b67f09SDavid van Moolenbroek
786*00b67f09SDavid van Moolenbroek if (gnamebuf.length != 0U) {
787*00b67f09SDavid van Moolenbroek gret = gss_release_buffer(&minor, &gnamebuf);
788*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE)
789*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_release_buffer: %s",
790*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf,
791*00b67f09SDavid van Moolenbroek sizeof(buf)));
792*00b67f09SDavid van Moolenbroek }
793*00b67f09SDavid van Moolenbroek }
794*00b67f09SDavid van Moolenbroek
795*00b67f09SDavid van Moolenbroek *ctxout = context;
796*00b67f09SDavid van Moolenbroek
797*00b67f09SDavid van Moolenbroek out:
798*00b67f09SDavid van Moolenbroek if (gname != NULL) {
799*00b67f09SDavid van Moolenbroek gret = gss_release_name(&minor, &gname);
800*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE)
801*00b67f09SDavid van Moolenbroek gss_log(3, "failed gss_release_name: %s",
802*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf,
803*00b67f09SDavid van Moolenbroek sizeof(buf)));
804*00b67f09SDavid van Moolenbroek }
805*00b67f09SDavid van Moolenbroek
806*00b67f09SDavid van Moolenbroek return (result);
807*00b67f09SDavid van Moolenbroek #else
808*00b67f09SDavid van Moolenbroek UNUSED(cred);
809*00b67f09SDavid van Moolenbroek UNUSED(gssapi_keytab);
810*00b67f09SDavid van Moolenbroek UNUSED(intoken);
811*00b67f09SDavid van Moolenbroek UNUSED(outtoken);
812*00b67f09SDavid van Moolenbroek UNUSED(ctxout);
813*00b67f09SDavid van Moolenbroek UNUSED(principal);
814*00b67f09SDavid van Moolenbroek UNUSED(mctx);
815*00b67f09SDavid van Moolenbroek
816*00b67f09SDavid van Moolenbroek return (ISC_R_NOTIMPLEMENTED);
817*00b67f09SDavid van Moolenbroek #endif
818*00b67f09SDavid van Moolenbroek }
819*00b67f09SDavid van Moolenbroek
820*00b67f09SDavid van Moolenbroek isc_result_t
dst_gssapi_deletectx(isc_mem_t * mctx,gss_ctx_id_t * gssctx)821*00b67f09SDavid van Moolenbroek dst_gssapi_deletectx(isc_mem_t *mctx, gss_ctx_id_t *gssctx)
822*00b67f09SDavid van Moolenbroek {
823*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
824*00b67f09SDavid van Moolenbroek OM_uint32 gret, minor;
825*00b67f09SDavid van Moolenbroek char buf[1024];
826*00b67f09SDavid van Moolenbroek
827*00b67f09SDavid van Moolenbroek UNUSED(mctx);
828*00b67f09SDavid van Moolenbroek
829*00b67f09SDavid van Moolenbroek REQUIRE(gssctx != NULL && *gssctx != NULL);
830*00b67f09SDavid van Moolenbroek
831*00b67f09SDavid van Moolenbroek /* Delete the context from the GSS provider */
832*00b67f09SDavid van Moolenbroek gret = gss_delete_sec_context(&minor, gssctx, GSS_C_NO_BUFFER);
833*00b67f09SDavid van Moolenbroek if (gret != GSS_S_COMPLETE) {
834*00b67f09SDavid van Moolenbroek /* Log the error, but still free the context's memory */
835*00b67f09SDavid van Moolenbroek gss_log(3, "Failure deleting security context %s",
836*00b67f09SDavid van Moolenbroek gss_error_tostring(gret, minor, buf, sizeof(buf)));
837*00b67f09SDavid van Moolenbroek }
838*00b67f09SDavid van Moolenbroek return(ISC_R_SUCCESS);
839*00b67f09SDavid van Moolenbroek #else
840*00b67f09SDavid van Moolenbroek UNUSED(mctx);
841*00b67f09SDavid van Moolenbroek UNUSED(gssctx);
842*00b67f09SDavid van Moolenbroek return (ISC_R_NOTIMPLEMENTED);
843*00b67f09SDavid van Moolenbroek #endif
844*00b67f09SDavid van Moolenbroek }
845*00b67f09SDavid van Moolenbroek
846*00b67f09SDavid van Moolenbroek char *
gss_error_tostring(isc_uint32_t major,isc_uint32_t minor,char * buf,size_t buflen)847*00b67f09SDavid van Moolenbroek gss_error_tostring(isc_uint32_t major, isc_uint32_t minor,
848*00b67f09SDavid van Moolenbroek char *buf, size_t buflen) {
849*00b67f09SDavid van Moolenbroek #ifdef GSSAPI
850*00b67f09SDavid van Moolenbroek gss_buffer_desc msg_minor = GSS_C_EMPTY_BUFFER,
851*00b67f09SDavid van Moolenbroek msg_major = GSS_C_EMPTY_BUFFER;
852*00b67f09SDavid van Moolenbroek OM_uint32 msg_ctx, minor_stat;
853*00b67f09SDavid van Moolenbroek
854*00b67f09SDavid van Moolenbroek /* Handle major status */
855*00b67f09SDavid van Moolenbroek msg_ctx = 0;
856*00b67f09SDavid van Moolenbroek (void)gss_display_status(&minor_stat, major, GSS_C_GSS_CODE,
857*00b67f09SDavid van Moolenbroek GSS_C_NULL_OID, &msg_ctx, &msg_major);
858*00b67f09SDavid van Moolenbroek
859*00b67f09SDavid van Moolenbroek /* Handle minor status */
860*00b67f09SDavid van Moolenbroek msg_ctx = 0;
861*00b67f09SDavid van Moolenbroek (void)gss_display_status(&minor_stat, minor, GSS_C_MECH_CODE,
862*00b67f09SDavid van Moolenbroek GSS_C_NULL_OID, &msg_ctx, &msg_minor);
863*00b67f09SDavid van Moolenbroek
864*00b67f09SDavid van Moolenbroek snprintf(buf, buflen, "GSSAPI error: Major = %s, Minor = %s.",
865*00b67f09SDavid van Moolenbroek (char *)msg_major.value, (char *)msg_minor.value);
866*00b67f09SDavid van Moolenbroek
867*00b67f09SDavid van Moolenbroek if (msg_major.length != 0U)
868*00b67f09SDavid van Moolenbroek (void)gss_release_buffer(&minor_stat, &msg_major);
869*00b67f09SDavid van Moolenbroek if (msg_minor.length != 0U)
870*00b67f09SDavid van Moolenbroek (void)gss_release_buffer(&minor_stat, &msg_minor);
871*00b67f09SDavid van Moolenbroek return(buf);
872*00b67f09SDavid van Moolenbroek #else
873*00b67f09SDavid van Moolenbroek snprintf(buf, buflen, "GSSAPI error: Major = %u, Minor = %u.",
874*00b67f09SDavid van Moolenbroek major, minor);
875*00b67f09SDavid van Moolenbroek
876*00b67f09SDavid van Moolenbroek return (buf);
877*00b67f09SDavid van Moolenbroek #endif
878*00b67f09SDavid van Moolenbroek }
879*00b67f09SDavid van Moolenbroek
880*00b67f09SDavid van Moolenbroek void
gss_log(int level,const char * fmt,...)881*00b67f09SDavid van Moolenbroek gss_log(int level, const char *fmt, ...) {
882*00b67f09SDavid van Moolenbroek va_list ap;
883*00b67f09SDavid van Moolenbroek
884*00b67f09SDavid van Moolenbroek va_start(ap, fmt);
885*00b67f09SDavid van Moolenbroek isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL,
886*00b67f09SDavid van Moolenbroek DNS_LOGMODULE_TKEY, ISC_LOG_DEBUG(level), fmt, ap);
887*00b67f09SDavid van Moolenbroek va_end(ap);
888*00b67f09SDavid van Moolenbroek }
889*00b67f09SDavid van Moolenbroek
890*00b67f09SDavid van Moolenbroek /*! \file */
891