1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c */
3 /*
4 * Copyright (c) 2004-2005, Novell, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * The copyright holder's name is not used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "autoconf.h"
32 #if HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #include <ctype.h>
37 #include "kdb_ldap.h"
38 #include "ldap_misc.h"
39 #include <kdb5.h>
40 #include <kadm5/admin.h>
41
42 /*
43 * ldap get age
44 */
45 krb5_error_code
krb5_ldap_get_age(context,db_name,age)46 krb5_ldap_get_age(context, db_name, age)
47 krb5_context context;
48 char *db_name;
49 time_t *age;
50 {
51 time (age);
52 return 0;
53 }
54
55 /*
56 * read startup information - kerberos and realm container
57 */
58 krb5_error_code
krb5_ldap_read_startup_information(krb5_context context)59 krb5_ldap_read_startup_information(krb5_context context)
60 {
61 krb5_error_code retval = 0;
62 kdb5_dal_handle *dal_handle=NULL;
63 krb5_ldap_context *ldap_context=NULL;
64 int mask = 0;
65
66 SETUP_CONTEXT();
67 if ((retval=krb5_ldap_read_krbcontainer_dn(context, &(ldap_context->container_dn)))) {
68 k5_prependmsg(context, retval, _("Unable to read Kerberos container"));
69 goto cleanup;
70 }
71
72 if ((retval=krb5_ldap_read_realm_params(context, context->default_realm, &(ldap_context->lrparams), &mask))) {
73 k5_prependmsg(context, retval, _("Unable to read Realm"));
74 goto cleanup;
75 }
76
77 if (((mask & LDAP_REALM_MAXTICKETLIFE) == 0) || ((mask & LDAP_REALM_MAXRENEWLIFE) == 0)
78 || ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0)) {
79 kadm5_config_params params_in, params_out;
80
81 memset(¶ms_in, 0, sizeof(params_in));
82 memset(¶ms_out, 0, sizeof(params_out));
83
84 retval = kadm5_get_config_params(context, 1, ¶ms_in, ¶ms_out);
85 if (retval) {
86 if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) {
87 ldap_context->lrparams->max_life = 24 * 60 * 60; /* 1 day */
88 }
89 if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) {
90 ldap_context->lrparams->max_renewable_life = 0;
91 }
92 if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) {
93 ldap_context->lrparams->tktflags = KRB5_KDB_DEF_FLAGS;
94 }
95 retval = 0;
96 goto cleanup;
97 }
98
99 if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) {
100 if (params_out.mask & KADM5_CONFIG_MAX_LIFE)
101 ldap_context->lrparams->max_life = params_out.max_life;
102 }
103
104 if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) {
105 if (params_out.mask & KADM5_CONFIG_MAX_RLIFE)
106 ldap_context->lrparams->max_renewable_life = params_out.max_rlife;
107 }
108
109 if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) {
110 if (params_out.mask & KADM5_CONFIG_FLAGS)
111 ldap_context->lrparams->tktflags = params_out.flags;
112 }
113
114 kadm5_free_config_params(context, ¶ms_out);
115 }
116
117 cleanup:
118 return retval;
119 }
120
121
122 /* Interrogate the root DSE (zero length DN) for an attribute value assertion.
123 * Return true if it is present, false if it is absent or we can't tell. */
124 static krb5_boolean
has_rootdse_ava(krb5_context context,const char * server_name,const char * attribute,const char * value)125 has_rootdse_ava(krb5_context context, const char *server_name,
126 const char *attribute, const char *value)
127 {
128 krb5_boolean result = FALSE;
129 char *attrs[2], **values = NULL;
130 int i, st;
131 LDAP *ld = NULL;
132 LDAPMessage *msg, *res = NULL;
133 struct berval cred;
134
135 attrs[0] = (char *)attribute;
136 attrs[1] = NULL;
137
138 st = ldap_initialize(&ld, server_name);
139 if (st != LDAP_SUCCESS)
140 goto cleanup;
141
142 /* Bind anonymously. */
143 cred.bv_val = "";
144 cred.bv_len = 0;
145 st = ldap_sasl_bind_s(ld, "", NULL, &cred, NULL, NULL, NULL);
146 if (st != LDAP_SUCCESS)
147 goto cleanup;
148
149 st = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, NULL,
150 NULL, NULL, 0, &res);
151 if (st != LDAP_SUCCESS)
152 goto cleanup;
153
154 msg = ldap_first_message(ld, res);
155 if (msg == NULL)
156 goto cleanup;
157
158 values = ldap_get_values(ld, msg, attribute);
159 if (values == NULL)
160 goto cleanup;
161
162 for (i = 0; values[i] != NULL; i++) {
163 if (strcmp(values[i], value) == 0) {
164 result = TRUE;
165 goto cleanup;
166 }
167 }
168
169 cleanup:
170 ldap_value_free(values);
171 ldap_msgfree(res);
172 ldap_unbind_ext_s(ld, NULL, NULL);
173
174 return result;
175 }
176
177 krb5_boolean
has_modify_increment(krb5_context context,const char * server_name)178 has_modify_increment(krb5_context context, const char *server_name)
179 {
180 return has_rootdse_ava(context, server_name, "supportedFeatures",
181 "1.3.6.1.1.14");
182 }
183
184 void *
krb5_ldap_alloc(krb5_context context,void * ptr,size_t size)185 krb5_ldap_alloc(krb5_context context, void *ptr, size_t size)
186 {
187 return realloc(ptr, size);
188 }
189
190 void
krb5_ldap_free(krb5_context context,void * ptr)191 krb5_ldap_free(krb5_context context, void *ptr)
192 {
193 free(ptr);
194 }
195
196 krb5_error_code
krb5_ldap_open(krb5_context context,char * conf_section,char ** db_args,int mode)197 krb5_ldap_open(krb5_context context, char *conf_section, char **db_args,
198 int mode)
199 {
200 krb5_error_code status = 0;
201 krb5_ldap_context *ldap_context=NULL;
202
203 /* Clear the global error string */
204 krb5_clear_error_message(context);
205
206 ldap_context = k5alloc(sizeof(krb5_ldap_context), &status);
207 if (ldap_context == NULL)
208 goto clean_n_exit;
209 context->dal_handle->db_context = ldap_context;
210 ldap_context->kcontext = context;
211
212 status = krb5_ldap_parse_db_params(context, db_args);
213 if (status) {
214 k5_prependmsg(context, status, _("Error processing LDAP DB params"));
215 goto clean_n_exit;
216 }
217
218 status = krb5_ldap_read_server_params(context, conf_section, mode & 0x0300);
219 if (status) {
220 k5_prependmsg(context, status, _("Error reading LDAP server params"));
221 goto clean_n_exit;
222 }
223 if ((status=krb5_ldap_db_init(context, ldap_context)) != 0) {
224 goto clean_n_exit;
225 }
226
227 if ((status=krb5_ldap_read_startup_information(context)) != 0) {
228 goto clean_n_exit;
229 }
230
231 clean_n_exit:
232 /* may be clearing up is not required db_fini might do it for us, check out */
233 if (status) {
234 krb5_ldap_close(context);
235 }
236 return status;
237 }
238
239 #include "ldap_err.h"
240 int
set_ldap_error(krb5_context ctx,int st,int op)241 set_ldap_error(krb5_context ctx, int st, int op)
242 {
243 int translated_st = translate_ldap_error(st, op);
244 k5_setmsg(ctx, translated_st, "%s", ldap_err2string(st));
245 return translated_st;
246 }
247
248 extern krb5int_access accessor;
249 MAKE_INIT_FUNCTION(kldap_init_fn);
250
251 int
kldap_init_fn(void)252 kldap_init_fn(void)
253 {
254 /* Global (per-module) initialization. */
255 return krb5int_accessor (&accessor, KRB5INT_ACCESS_VERSION);
256 }
257
258 int
kldap_ensure_initialized(void)259 kldap_ensure_initialized(void)
260 {
261 return CALL_INIT_FUNCTION (kldap_init_fn);
262 }
263
264 krb5_error_code
krb5_ldap_check_policy_as(krb5_context kcontext,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp kdc_time,const char ** status,krb5_pa_data *** e_data)265 krb5_ldap_check_policy_as(krb5_context kcontext, krb5_kdc_req *request,
266 krb5_db_entry *client, krb5_db_entry *server,
267 krb5_timestamp kdc_time, const char **status,
268 krb5_pa_data ***e_data)
269 {
270 krb5_error_code retval;
271
272 retval = krb5_ldap_lockout_check_policy(kcontext, client, kdc_time);
273 if (retval == KRB5KDC_ERR_CLIENT_REVOKED)
274 *status = "LOCKED_OUT";
275 return retval;
276 }
277
278 void
krb5_ldap_audit_as_req(krb5_context kcontext,krb5_kdc_req * request,const krb5_address * local_addr,const krb5_address * remote_addr,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp authtime,krb5_error_code error_code)279 krb5_ldap_audit_as_req(krb5_context kcontext, krb5_kdc_req *request,
280 const krb5_address *local_addr,
281 const krb5_address *remote_addr, krb5_db_entry *client,
282 krb5_db_entry *server, krb5_timestamp authtime,
283 krb5_error_code error_code)
284 {
285 (void) krb5_ldap_lockout_audit(kcontext, client, authtime, error_code);
286 }
287
288 krb5_error_code
krb5_ldap_check_allowed_to_delegate(krb5_context context,krb5_const_principal client,const krb5_db_entry * server,krb5_const_principal proxy)289 krb5_ldap_check_allowed_to_delegate(krb5_context context,
290 krb5_const_principal client,
291 const krb5_db_entry *server,
292 krb5_const_principal proxy)
293 {
294 krb5_error_code code;
295 krb5_tl_data *tlp;
296
297 code = KRB5KDC_ERR_BADOPTION;
298
299 for (tlp = server->tl_data; tlp != NULL; tlp = tlp->tl_data_next) {
300 krb5_principal acl;
301
302 if (tlp->tl_data_type != KRB5_TL_CONSTRAINED_DELEGATION_ACL)
303 continue;
304
305 if (krb5_parse_name(context, (char *)tlp->tl_data_contents, &acl) != 0)
306 continue;
307
308 if (proxy == NULL || krb5_principal_compare(context, proxy, acl)) {
309 code = 0;
310 krb5_free_principal(context, acl);
311 break;
312 }
313 krb5_free_principal(context, acl);
314 }
315
316 return code;
317 }
318