3 Helper routings for allowing LDAP to read configuration with GSSAPI/krb auth */
6 * Copyright (c) 2015-2017 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2014 William B.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of The Internet Software Consortium nor the names
20 * of its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * This helper was written by William Brown <william@adelaide.edu.au>,
38 * inspired by krb5_helper.c from bind-dyndb-ldap by Simo Sorce (Redhat)
40 #if defined(LDAP_USE_GSSAPI)
43 #include "ldap_krb_helper.h"
50 #define KRB_DEFAULT_KEYTAB "FILE:/etc/dhcp/dhcp.keytab"
51 #define KRB_MIN_TIME 300
53 #define CHECK_KRB5(ctx, err, msg, ...) \
56 const char * errmsg = krb5_get_error_message(ctx, err); \
57 log_error("Err: %s -> %s\n", msg, errmsg); \
58 result = ISC_R_FAILURE; \
63 #define CHECK(ret_code, msg) \
64 if (ret_code != 0) { \
65 log_error("Error, %i %s\n", ret_code, msg); \
70 check_credentials(krb5_context context
, krb5_ccache ccache
, krb5_principal service
)
75 krb5_error_code krberr
;
77 isc_result_t result
= ISC_R_FAILURE
;
79 memset(&mcreds
, 0, sizeof(mcreds
));
80 memset(&creds
, 0, sizeof(creds
));
82 krberr
= krb5_get_default_realm(context
, &realm
);
83 CHECK_KRB5(context
, krberr
, "Failed to retrieve default realm");
85 krberr
= krb5_build_principal(context
, &mcreds
.server
,
87 "krbtgt", realm
, NULL
);
88 CHECK_KRB5(context
, krberr
, "Failed to build 'krbtgt/REALM' principal");
90 mcreds
.client
= service
;
92 krberr
= krb5_cc_retrieve_cred(context
, ccache
, 0, &mcreds
, &creds
);
95 const char * errmsg
= krb5_get_error_message(context
, krberr
);
96 log_error("Credentials are not present in cache (%s)\n", errmsg
);
97 krb5_free_error_message(context
, errmsg
);
98 result
= ISC_R_FAILURE
;
101 CHECK_KRB5(context
, krberr
, "Credentials are not present in cache ");
103 krberr
= krb5_timeofday(context
, &now
);
104 CHECK_KRB5(context
, krberr
, "Failed to get time of day");
107 if (now
> (creds
.times
.endtime
+ KRB_MIN_TIME
)) {
108 log_error("Credentials cache expired");
109 result
= ISC_R_FAILURE
;
114 krb5_timestamp_to_sfstring(creds
.times
.endtime
, buf
, 16, &fill
);
115 log_info("Credentials valid til %s\n", buf
);
118 result
= ISC_R_SUCCESS
;
121 krb5_free_cred_contents(context
, &creds
);
122 if (mcreds
.server
) krb5_free_principal(context
, mcreds
.server
);
123 if (realm
) krb5_free_default_realm(context
, realm
);
128 krb5_get_tgt(const char *principal
, const char *keyfile
)
130 isc_result_t result
= ISC_R_FAILURE
;
132 krb5_context context
= NULL
;
133 krb5_error_code krberr
;
134 krb5_ccache ccache
= NULL
;
135 krb5_principal kprincpw
= NULL
;
137 krb5_creds
* my_creds_ptr
= NULL
;
138 krb5_get_init_creds_opt options
;
139 krb5_keytab keytab
= NULL
;
142 if (keyfile
== NULL
|| keyfile
[0] == '\0') {
143 keyfile
= KRB_DEFAULT_KEYTAB
;
144 log_info("Using default keytab %s\n", keyfile
);
146 if (strncmp(keyfile
, "FILE:", 5) != 0) {
147 log_error("Unknown keytab path format: Does it start with FILE:?\n");
148 return ISC_R_FAILURE
;
152 krberr
= krb5_init_context(&context
);
153 CHECK_KRB5(NULL
, krberr
, "Kerberos context initialization failed");
155 result
= ISC_R_SUCCESS
;
157 ccname
= "MEMORY:dhcp_ld_krb5_cc";
158 log_info("Using ccache %s\n" , ccname
);
160 ret
= setenv("KRB5CCNAME", ccname
, 1);
162 log_error("Failed to setup environment\n");
163 result
= ISC_R_FAILURE
;
167 krberr
= krb5_cc_resolve(context
, ccname
, &ccache
);
168 CHECK_KRB5(context
, krberr
, "Couldnt resolve ccache '%s'", ccname
);
170 krberr
= krb5_parse_name(context
, principal
, &kprincpw
);
171 CHECK_KRB5(context
, krberr
, "Failed to parse princ '%s'", princpal
);
173 result
= check_credentials(context
, ccache
, kprincpw
);
174 if (result
== ISC_R_SUCCESS
) {
175 log_info("Found valid kerberos credentials\n");
178 log_error("No valid krb5 credentials\n");
181 krberr
= krb5_kt_resolve(context
, keyfile
, &keytab
);
182 CHECK_KRB5(context
, krberr
,
183 "Failed to resolve kt files '%s'\n", keyfile
);
185 memset(&my_creds
, 0, sizeof(my_creds
));
186 memset(&options
, 0, sizeof(options
));
188 krb5_get_init_creds_opt_set_tkt_life(&options
, KRB_MIN_TIME
* 2);
189 krb5_get_init_creds_opt_set_address_list(&options
, NULL
);
190 krb5_get_init_creds_opt_set_forwardable(&options
, 0);
191 krb5_get_init_creds_opt_set_proxiable(&options
, 0);
193 krberr
= krb5_get_init_creds_keytab(context
, &my_creds
, kprincpw
,
194 keytab
, 0, NULL
, &options
);
195 CHECK_KRB5(context
, krberr
, "Failed to get initial credentials TGT\n");
197 my_creds_ptr
= &my_creds
;
199 krberr
= krb5_cc_initialize(context
, ccache
, kprincpw
);
200 CHECK_KRB5(context
, krberr
, "Failed to init ccache\n");
202 krberr
= krb5_cc_store_cred(context
, ccache
, &my_creds
);
203 CHECK_KRB5(context
, krberr
, "Failed to store credentials\n");
205 result
= ISC_R_SUCCESS
;
206 log_info("Successfully init krb tgt %s", principal
);
209 if (ccache
) krb5_cc_close(context
, ccache
);
210 if (keytab
) krb5_kt_close(context
, keytab
);
211 if (kprincpw
) krb5_free_principal(context
, kprincpw
);
212 if (my_creds_ptr
) krb5_free_cred_contents(context
, &my_creds
);
213 if (context
) krb5_free_context(context
);
217 #endif /* defined(LDAP_USE_GSSAPI) */