1 #pragma ident "%Z%%M% %I% %E% SMI"
2
3 /*
4 * lib/kdb/kdb_ldap/ldap_create.c
5 *
6 * Copyright (c) 2004-2005, Novell, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * * The copyright holder's name is not used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
35 * Use is subject to license terms.
36 */
37
38 #include "ldap_main.h"
39 #include "ldap_realm.h"
40 #include "ldap_principal.h"
41 #include "ldap_krbcontainer.h"
42 #include "ldap_err.h"
43 #include <libintl.h>
44
45 /*
46 * ******************************************************************************
47 * DAL functions
48 * ******************************************************************************
49 */
50
51 /*
52 * This function will create a krbcontainer and realm on the LDAP Server, with
53 * the specified attributes.
54 */
55 krb5_error_code
krb5_ldap_create(krb5_context context,char * conf_section,char ** db_args)56 krb5_ldap_create (krb5_context context, char *conf_section, char **db_args)
57 {
58 krb5_error_code status = 0;
59 char **t_ptr = db_args;
60 krb5_ldap_realm_params *rparams = NULL;
61 kdb5_dal_handle *dal_handle = NULL;
62 krb5_ldap_context *ldap_context=NULL;
63 krb5_boolean realm_obj_created = FALSE;
64 krb5_boolean krbcontainer_obj_created = FALSE;
65 krb5_ldap_krbcontainer_params kparams = {0};
66 int srv_cnt = 0;
67 int mask = 0;
68 #ifdef HAVE_EDIRECTORY
69 int i = 0, rightsmask = 0;
70 #endif
71
72 /* Clear the global error string */
73 krb5_clear_error_message(context);
74
75 ldap_context = malloc(sizeof(krb5_ldap_context));
76 if (ldap_context == NULL) {
77 status = ENOMEM;
78 goto cleanup;
79 }
80 memset(ldap_context, 0, sizeof(*ldap_context));
81
82 ldap_context->kcontext = context;
83
84 /* populate ldap_context with ldap specific options */
85 while (t_ptr && *t_ptr) {
86 char *opt = NULL, *val = NULL;
87
88 if ((status = krb5_ldap_get_db_opt(*t_ptr, &opt, &val)) != 0) {
89 goto cleanup;
90 }
91 if (opt && !strcmp(opt, "binddn")) {
92 if (ldap_context->bind_dn) {
93 free (opt);
94 free (val);
95 status = EINVAL;
96 krb5_set_error_message (context, status, gettext("'binddn' missing"));
97 goto cleanup;
98 }
99 if (val == NULL) {
100 status = EINVAL;
101 krb5_set_error_message (context, status, gettext("'binddn' value missing"));
102 free(opt);
103 goto cleanup;
104 }
105 ldap_context->bind_dn = strdup(val);
106 if (ldap_context->bind_dn == NULL) {
107 free (opt);
108 free (val);
109 status = ENOMEM;
110 goto cleanup;
111 }
112 } else if (opt && !strcmp(opt, "nconns")) {
113 if (ldap_context->max_server_conns) {
114 free (opt);
115 free (val);
116 status = EINVAL;
117 krb5_set_error_message (context, status, gettext("'nconns' missing"));
118 goto cleanup;
119 }
120 if (val == NULL) {
121 status = EINVAL;
122 krb5_set_error_message (context, status, gettext("'nconns' value missing"));
123 free(opt);
124 goto cleanup;
125 }
126 ldap_context->max_server_conns = atoi(val) ? atoi(val) : DEFAULT_CONNS_PER_SERVER;
127 } else if (opt && !strcmp(opt, "bindpwd")) {
128 if (ldap_context->bind_pwd) {
129 free (opt);
130 free (val);
131 status = EINVAL;
132 krb5_set_error_message (context, status, gettext("'bindpwd' missing"));
133 goto cleanup;
134 }
135 if (val == NULL) {
136 status = EINVAL;
137 krb5_set_error_message (context, status, gettext("'bindpwd' value missing"));
138 free(opt);
139 goto cleanup;
140 }
141 ldap_context->bind_pwd = strdup(val);
142 if (ldap_context->bind_pwd == NULL) {
143 free (opt);
144 free (val);
145 status = ENOMEM;
146 goto cleanup;
147 }
148 } else if (opt && !strcmp(opt, "host")) {
149 if (val == NULL) {
150 status = EINVAL;
151 krb5_set_error_message (context, status, gettext("'host' value missing"));
152 free(opt);
153 goto cleanup;
154 }
155 if (ldap_context->server_info_list == NULL)
156 ldap_context->server_info_list =
157 (krb5_ldap_server_info **) calloc(SERV_COUNT+1, sizeof(krb5_ldap_server_info *));
158
159 if (ldap_context->server_info_list == NULL) {
160 free (opt);
161 free (val);
162 status = ENOMEM;
163 goto cleanup;
164 }
165
166 ldap_context->server_info_list[srv_cnt] =
167 (krb5_ldap_server_info *) calloc(1, sizeof(krb5_ldap_server_info));
168 if (ldap_context->server_info_list[srv_cnt] == NULL) {
169 free (opt);
170 free (val);
171 status = ENOMEM;
172 goto cleanup;
173 }
174
175 ldap_context->server_info_list[srv_cnt]->server_status = NOTSET;
176
177 ldap_context->server_info_list[srv_cnt]->server_name = strdup(val);
178 if (ldap_context->server_info_list[srv_cnt]->server_name == NULL) {
179 free (opt);
180 free (val);
181 status = ENOMEM;
182 goto cleanup;
183 }
184
185 srv_cnt++;
186 #ifdef HAVE_EDIRECTORY
187 } else if (opt && !strcmp(opt, "cert")) {
188 if (val == NULL) {
189 status = EINVAL;
190 krb5_set_error_message (context, status, gettext("'cert' value missing"));
191 free(opt);
192 goto cleanup;
193 }
194
195 if (ldap_context->root_certificate_file == NULL) {
196 ldap_context->root_certificate_file = strdup(val);
197 if (ldap_context->root_certificate_file == NULL) {
198 free (opt);
199 free (val);
200 status = ENOMEM;
201 goto cleanup;
202 }
203 } else {
204 void *tmp=NULL;
205 char *oldstr = NULL;
206 unsigned int len=0;
207
208 oldstr = strdup(ldap_context->root_certificate_file);
209 if (oldstr == NULL) {
210 free (opt);
211 free (val);
212 status = ENOMEM;
213 goto cleanup;
214 }
215
216 tmp = ldap_context->root_certificate_file;
217 len = strlen(ldap_context->root_certificate_file) + 2 + strlen(val);
218 ldap_context->root_certificate_file = realloc(ldap_context->root_certificate_file,
219 len);
220 if (ldap_context->root_certificate_file == NULL) {
221 free (tmp);
222 free (opt);
223 free (val);
224 status = ENOMEM;
225 goto cleanup;
226 }
227 memset(ldap_context->root_certificate_file, 0, len);
228 sprintf(ldap_context->root_certificate_file,"%s %s", oldstr, val);
229 free (oldstr);
230 }
231 #endif
232 } else {
233 /* ignore hash argument. Might have been passed from create */
234 status = EINVAL;
235 if (opt && !strcmp(opt, "temporary")) {
236 /*
237 * temporary is passed in when kdb5_util load without -update is done.
238 * This is unsupported by the LDAP plugin.
239 */
240 krb5_set_error_message (context, status,
241 gettext("creation of LDAP entries aborted, plugin requires -update argument"));
242 } else {
243 krb5_set_error_message (context, status, gettext("unknown option \'%s\'"),
244 opt?opt:val);
245 }
246 free(opt);
247 free(val);
248 goto cleanup;
249 }
250
251 free(opt);
252 free(val);
253 t_ptr++;
254 }
255
256 dal_handle = (kdb5_dal_handle *) context->db_context;
257 dal_handle->db_context = (kdb5_dal_handle *) ldap_context;
258
259 status = krb5_ldap_read_server_params(context, conf_section, KRB5_KDB_SRV_TYPE_ADMIN);
260 if (status) {
261 dal_handle->db_context = NULL;
262 prepend_err_str (context, gettext("Error reading LDAP server params: "), status, status);
263 goto cleanup;
264 }
265 status = krb5_ldap_db_init(context, ldap_context);
266 if (status) {
267 goto cleanup;
268 }
269
270 /* read the kerberos container */
271 if ((status = krb5_ldap_read_krbcontainer_params(context,
272 &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) {
273
274 /* Read the kerberos container location from configuration file */
275 if (ldap_context->conf_section) {
276 if ((status = profile_get_string(context->profile,
277 KDB_MODULE_SECTION, ldap_context->conf_section,
278 "ldap_kerberos_container_dn", NULL,
279 &kparams.DN)) != 0) {
280 goto cleanup;
281 }
282 }
283 if (kparams.DN == NULL) {
284 if ((status = profile_get_string(context->profile,
285 KDB_MODULE_DEF_SECTION,
286 "ldap_kerberos_container_dn", NULL,
287 NULL, &kparams.DN)) != 0) {
288 goto cleanup;
289 }
290 }
291
292 /* create the kerberos container */
293 status = krb5_ldap_create_krbcontainer(context,
294 ((kparams.DN != NULL) ? &kparams : NULL));
295 if (status)
296 goto cleanup;
297
298 krbcontainer_obj_created = TRUE;
299
300 status = krb5_ldap_read_krbcontainer_params(context,
301 &(ldap_context->krbcontainer));
302 if (status) {
303 krb5_set_error_message(context, status, gettext("while reading kerberos container information"));
304 goto cleanup;
305 }
306
307 } else if (status) {
308 krb5_set_error_message(context, status, gettext("while reading kerberos container information"));
309 goto cleanup;
310 }
311
312 rparams = (krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params));
313 if (rparams == NULL) {
314 status = ENOMEM;
315 goto cleanup;
316 }
317 memset(rparams, 0, sizeof(*rparams));
318 rparams->realm_name = strdup(context->default_realm);
319 if (rparams->realm_name == NULL) {
320 status = ENOMEM;
321 goto cleanup;
322 }
323
324 if ((status = krb5_ldap_create_realm(context, rparams, mask))) {
325 krb5_set_error_message(context, status, gettext("while creating realm object entry"));
326 goto cleanup;
327 }
328
329 /* We just created the Realm container. Here starts our transaction tracking */
330 realm_obj_created = TRUE;
331
332 /* verify realm object */
333 if ((status = krb5_ldap_read_realm_params(context,
334 rparams->realm_name,
335 &(ldap_context->lrparams),
336 &mask))) {
337 krb5_set_error_message(context, status, gettext("while reading realm object entry"));
338 goto cleanup;
339 }
340
341 #ifdef HAVE_EDIRECTORY
342 if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) ||
343 (mask & LDAP_REALM_PASSWDSERVERS)) {
344
345 rightsmask =0;
346 rightsmask |= LDAP_REALM_RIGHTS;
347 rightsmask |= LDAP_SUBTREE_RIGHTS;
348 if ((rparams != NULL) && (rparams->kdcservers != NULL)) {
349 for (i=0; (rparams->kdcservers[i] != NULL); i++) {
350 if ((status=krb5_ldap_add_service_rights(context,
351 LDAP_KDC_SERVICE, rparams->kdcservers[i],
352 rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
353 goto cleanup;
354 }
355 }
356 }
357
358 rightsmask = 0;
359 rightsmask |= LDAP_REALM_RIGHTS;
360 rightsmask |= LDAP_SUBTREE_RIGHTS;
361 if ((rparams != NULL) && (rparams->adminservers != NULL)) {
362 for (i=0; (rparams->adminservers[i] != NULL); i++) {
363 if ((status=krb5_ldap_add_service_rights(context,
364 LDAP_ADMIN_SERVICE, rparams->adminservers[i],
365 rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
366 goto cleanup;
367 }
368 }
369 }
370
371 rightsmask = 0;
372 rightsmask |= LDAP_REALM_RIGHTS;
373 rightsmask |= LDAP_SUBTREE_RIGHTS;
374 if ((rparams != NULL) && (rparams->passwdservers != NULL)) {
375 for (i=0; (rparams->passwdservers[i] != NULL); i++) {
376 if ((status=krb5_ldap_add_service_rights(context,
377 LDAP_PASSWD_SERVICE, rparams->passwdservers[i],
378 rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
379 goto cleanup;
380 }
381 }
382 }
383 }
384 #endif
385
386 cleanup:
387
388 /* If the krbcontainer/realm creation is not complete, do the roll-back here */
389 if ((krbcontainer_obj_created) && (!realm_obj_created)) {
390 int rc;
391 rc = krb5_ldap_delete_krbcontainer(context,
392 ((kparams.DN != NULL) ? &kparams : NULL));
393 krb5_set_error_message(context, rc,
394 gettext("could not complete roll-back, error deleting Kerberos Container"));
395 }
396
397 /* should call krb5_ldap_free_krbcontainer_params() but can't */
398 if (kparams.DN != NULL)
399 krb5_xfree(kparams.DN);
400
401 if (rparams)
402 krb5_ldap_free_realm_params(rparams);
403
404 return(status);
405 }
406