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(krb5_context context,char * db_name,time_t * age)46 krb5_ldap_get_age(krb5_context context, char *db_name, time_t *age)
47 {
48 time (age);
49 return 0;
50 }
51
52 /*
53 * read startup information - kerberos and realm container
54 */
55 krb5_error_code
krb5_ldap_read_startup_information(krb5_context context)56 krb5_ldap_read_startup_information(krb5_context context)
57 {
58 krb5_error_code retval = 0;
59 kdb5_dal_handle *dal_handle=NULL;
60 krb5_ldap_context *ldap_context=NULL;
61 int mask = 0;
62
63 SETUP_CONTEXT();
64 if ((retval=krb5_ldap_read_krbcontainer_dn(context, &(ldap_context->container_dn)))) {
65 k5_prependmsg(context, retval, _("Unable to read Kerberos container"));
66 goto cleanup;
67 }
68
69 if ((retval=krb5_ldap_read_realm_params(context, context->default_realm, &(ldap_context->lrparams), &mask))) {
70 k5_prependmsg(context, retval, _("Unable to read Realm"));
71 goto cleanup;
72 }
73
74 if (((mask & LDAP_REALM_MAXTICKETLIFE) == 0) || ((mask & LDAP_REALM_MAXRENEWLIFE) == 0)
75 || ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0)) {
76 kadm5_config_params params_in, params_out;
77
78 memset(¶ms_in, 0, sizeof(params_in));
79 memset(¶ms_out, 0, sizeof(params_out));
80
81 retval = kadm5_get_config_params(context, 1, ¶ms_in, ¶ms_out);
82 if (retval) {
83 if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) {
84 ldap_context->lrparams->max_life = 24 * 60 * 60; /* 1 day */
85 }
86 if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) {
87 ldap_context->lrparams->max_renewable_life = 0;
88 }
89 if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) {
90 ldap_context->lrparams->tktflags = KRB5_KDB_DEF_FLAGS;
91 }
92 retval = 0;
93 goto cleanup;
94 }
95
96 if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) {
97 if (params_out.mask & KADM5_CONFIG_MAX_LIFE)
98 ldap_context->lrparams->max_life = params_out.max_life;
99 }
100
101 if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) {
102 if (params_out.mask & KADM5_CONFIG_MAX_RLIFE)
103 ldap_context->lrparams->max_renewable_life = params_out.max_rlife;
104 }
105
106 if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) {
107 if (params_out.mask & KADM5_CONFIG_FLAGS)
108 ldap_context->lrparams->tktflags = params_out.flags;
109 }
110
111 kadm5_free_config_params(context, ¶ms_out);
112 }
113
114 cleanup:
115 return retval;
116 }
117
118
119 /* Interrogate the root DSE (zero length DN) for an attribute value assertion.
120 * Return true if it is present, false if it is absent or we can't tell. */
121 static krb5_boolean
has_rootdse_ava(krb5_context context,const char * server_name,const char * attribute,const char * value)122 has_rootdse_ava(krb5_context context, const char *server_name,
123 const char *attribute, const char *value)
124 {
125 krb5_boolean result = FALSE;
126 char *attrs[2], **values = NULL;
127 int i, st;
128 LDAP *ld = NULL;
129 LDAPMessage *msg, *res = NULL;
130 struct berval cred;
131
132 attrs[0] = (char *)attribute;
133 attrs[1] = NULL;
134
135 st = ldap_initialize(&ld, server_name);
136 if (st != LDAP_SUCCESS)
137 goto cleanup;
138
139 /* Bind anonymously. */
140 cred.bv_val = "";
141 cred.bv_len = 0;
142 st = ldap_sasl_bind_s(ld, "", NULL, &cred, NULL, NULL, NULL);
143 if (st != LDAP_SUCCESS)
144 goto cleanup;
145
146 st = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, NULL,
147 NULL, NULL, 0, &res);
148 if (st != LDAP_SUCCESS)
149 goto cleanup;
150
151 msg = ldap_first_message(ld, res);
152 if (msg == NULL)
153 goto cleanup;
154
155 values = ldap_get_values(ld, msg, attribute);
156 if (values == NULL)
157 goto cleanup;
158
159 for (i = 0; values[i] != NULL; i++) {
160 if (strcmp(values[i], value) == 0) {
161 result = TRUE;
162 goto cleanup;
163 }
164 }
165
166 cleanup:
167 ldap_value_free(values);
168 ldap_msgfree(res);
169 ldap_unbind_ext_s(ld, NULL, NULL);
170
171 return result;
172 }
173
174 krb5_boolean
has_modify_increment(krb5_context context,const char * server_name)175 has_modify_increment(krb5_context context, const char *server_name)
176 {
177 return has_rootdse_ava(context, server_name, "supportedFeatures",
178 "1.3.6.1.1.14");
179 }
180
181 void *
krb5_ldap_alloc(krb5_context context,void * ptr,size_t size)182 krb5_ldap_alloc(krb5_context context, void *ptr, size_t size)
183 {
184 return realloc(ptr, size);
185 }
186
187 void
krb5_ldap_free(krb5_context context,void * ptr)188 krb5_ldap_free(krb5_context context, void *ptr)
189 {
190 free(ptr);
191 }
192
193 krb5_error_code
krb5_ldap_open(krb5_context context,char * conf_section,char ** db_args,int mode)194 krb5_ldap_open(krb5_context context, char *conf_section, char **db_args,
195 int mode)
196 {
197 krb5_error_code status = 0;
198 krb5_ldap_context *ldap_context=NULL;
199
200 /* Clear the global error string */
201 krb5_clear_error_message(context);
202
203 ldap_context = k5alloc(sizeof(krb5_ldap_context), &status);
204 if (ldap_context == NULL)
205 goto clean_n_exit;
206 context->dal_handle->db_context = ldap_context;
207 ldap_context->kcontext = context;
208
209 status = krb5_ldap_parse_db_params(context, db_args);
210 if (status) {
211 k5_prependmsg(context, status, _("Error processing LDAP DB params"));
212 goto clean_n_exit;
213 }
214
215 status = krb5_ldap_read_server_params(context, conf_section, mode & 0x0300);
216 if (status) {
217 k5_prependmsg(context, status, _("Error reading LDAP server params"));
218 goto clean_n_exit;
219 }
220 if ((status=krb5_ldap_db_init(context, ldap_context)) != 0) {
221 goto clean_n_exit;
222 }
223
224 if ((status=krb5_ldap_read_startup_information(context)) != 0) {
225 goto clean_n_exit;
226 }
227
228 clean_n_exit:
229 /* may be clearing up is not required db_fini might do it for us, check out */
230 if (status) {
231 krb5_ldap_close(context);
232 }
233 return status;
234 }
235
236 #include "ldap_err.h"
237 int
set_ldap_error(krb5_context ctx,int st,int op)238 set_ldap_error(krb5_context ctx, int st, int op)
239 {
240 int translated_st = translate_ldap_error(st, op);
241 k5_setmsg(ctx, translated_st, "%s", ldap_err2string(st));
242 return translated_st;
243 }
244
245 extern krb5int_access accessor;
246 MAKE_INIT_FUNCTION(kldap_init_fn);
247
248 int
kldap_init_fn(void)249 kldap_init_fn(void)
250 {
251 /* Global (per-module) initialization. */
252 return krb5int_accessor (&accessor, KRB5INT_ACCESS_VERSION);
253 }
254
255 int
kldap_ensure_initialized(void)256 kldap_ensure_initialized(void)
257 {
258 return CALL_INIT_FUNCTION (kldap_init_fn);
259 }
260
261 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)262 krb5_ldap_check_policy_as(krb5_context kcontext, krb5_kdc_req *request,
263 krb5_db_entry *client, krb5_db_entry *server,
264 krb5_timestamp kdc_time, const char **status,
265 krb5_pa_data ***e_data)
266 {
267 krb5_error_code retval;
268
269 retval = krb5_ldap_lockout_check_policy(kcontext, client, kdc_time);
270 if (retval == KRB5KDC_ERR_CLIENT_REVOKED)
271 *status = "LOCKED_OUT";
272 return retval;
273 }
274
275 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)276 krb5_ldap_audit_as_req(krb5_context kcontext, krb5_kdc_req *request,
277 const krb5_address *local_addr,
278 const krb5_address *remote_addr, krb5_db_entry *client,
279 krb5_db_entry *server, krb5_timestamp authtime,
280 krb5_error_code error_code)
281 {
282 (void) krb5_ldap_lockout_audit(kcontext, client, authtime, error_code);
283 }
284
285 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)286 krb5_ldap_check_allowed_to_delegate(krb5_context context,
287 krb5_const_principal client,
288 const krb5_db_entry *server,
289 krb5_const_principal proxy)
290 {
291 krb5_error_code code;
292 krb5_tl_data *tlp;
293
294 code = KRB5KDC_ERR_BADOPTION;
295
296 for (tlp = server->tl_data; tlp != NULL; tlp = tlp->tl_data_next) {
297 krb5_principal acl;
298
299 if (tlp->tl_data_type != KRB5_TL_CONSTRAINED_DELEGATION_ACL ||
300 tlp->tl_data_length < 1 ||
301 tlp->tl_data_contents[tlp->tl_data_length - 1] != '\0')
302 continue;
303
304 if (krb5_parse_name(context, (char *)tlp->tl_data_contents, &acl) != 0)
305 continue;
306
307 if (proxy == NULL || krb5_principal_compare(context, proxy, acl)) {
308 code = 0;
309 krb5_free_principal(context, acl);
310 break;
311 }
312 krb5_free_principal(context, acl);
313 }
314
315 return code;
316 }
317