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 */
55krb5_error_code
56krb5_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
386cleanup:
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