154925bf6Swillf /*
254925bf6Swillf  * lib/kdb/kdb_ldap/ldap_create.c
354925bf6Swillf  *
454925bf6Swillf  * Copyright (c) 2004-2005, Novell, Inc.
554925bf6Swillf  * All rights reserved.
654925bf6Swillf  *
754925bf6Swillf  * Redistribution and use in source and binary forms, with or without
854925bf6Swillf  * modification, are permitted provided that the following conditions are met:
954925bf6Swillf  *
1054925bf6Swillf  *   * Redistributions of source code must retain the above copyright notice,
1154925bf6Swillf  *       this list of conditions and the following disclaimer.
1254925bf6Swillf  *   * Redistributions in binary form must reproduce the above copyright
1354925bf6Swillf  *       notice, this list of conditions and the following disclaimer in the
1454925bf6Swillf  *       documentation and/or other materials provided with the distribution.
1554925bf6Swillf  *   * The copyright holder's name is not used to endorse or promote products
1654925bf6Swillf  *       derived from this software without specific prior written permission.
1754925bf6Swillf  *
1854925bf6Swillf  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1954925bf6Swillf  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2054925bf6Swillf  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2154925bf6Swillf  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2254925bf6Swillf  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2354925bf6Swillf  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2454925bf6Swillf  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2554925bf6Swillf  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2654925bf6Swillf  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2754925bf6Swillf  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2854925bf6Swillf  * POSSIBILITY OF SUCH DAMAGE.
2954925bf6Swillf  */
3054925bf6Swillf 
3154925bf6Swillf /*
3254925bf6Swillf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3354925bf6Swillf  * Use is subject to license terms.
3454925bf6Swillf  */
3554925bf6Swillf 
3654925bf6Swillf #include "ldap_main.h"
3754925bf6Swillf #include "ldap_realm.h"
3854925bf6Swillf #include "ldap_principal.h"
3954925bf6Swillf #include "ldap_krbcontainer.h"
4054925bf6Swillf #include "ldap_err.h"
4154925bf6Swillf #include <libintl.h>
4254925bf6Swillf 
43*1da57d55SToomas Soome /*
4454925bf6Swillf  * ******************************************************************************
4554925bf6Swillf  * DAL functions
4654925bf6Swillf  * ******************************************************************************
4754925bf6Swillf  */
4854925bf6Swillf 
4954925bf6Swillf /*
5054925bf6Swillf  * This function will create a krbcontainer and realm on the LDAP Server, with
5154925bf6Swillf  * the specified attributes.
5254925bf6Swillf  */
5354925bf6Swillf krb5_error_code
krb5_ldap_create(krb5_context context,char * conf_section,char ** db_args)5454925bf6Swillf krb5_ldap_create (krb5_context context, char *conf_section, char **db_args)
5554925bf6Swillf {
5654925bf6Swillf     krb5_error_code status = 0;
5754925bf6Swillf     char  **t_ptr = db_args;
5854925bf6Swillf     krb5_ldap_realm_params *rparams = NULL;
5954925bf6Swillf     kdb5_dal_handle *dal_handle = NULL;
6054925bf6Swillf     krb5_ldap_context *ldap_context=NULL;
6154925bf6Swillf     krb5_boolean realm_obj_created = FALSE;
6254925bf6Swillf     krb5_boolean krbcontainer_obj_created = FALSE;
6354925bf6Swillf     krb5_ldap_krbcontainer_params kparams = {0};
6454925bf6Swillf     int srv_cnt = 0;
6554925bf6Swillf     int mask = 0;
6654925bf6Swillf #ifdef HAVE_EDIRECTORY
6754925bf6Swillf     int i = 0, rightsmask = 0;
6854925bf6Swillf #endif
6954925bf6Swillf 
7054925bf6Swillf     /* Clear the global error string */
7154925bf6Swillf     krb5_clear_error_message(context);
7254925bf6Swillf 
7354925bf6Swillf     ldap_context = malloc(sizeof(krb5_ldap_context));
7454925bf6Swillf     if (ldap_context == NULL) {
7554925bf6Swillf 	status = ENOMEM;
7654925bf6Swillf 	goto cleanup;
7754925bf6Swillf     }
7854925bf6Swillf     memset(ldap_context, 0, sizeof(*ldap_context));
7954925bf6Swillf 
8054925bf6Swillf     ldap_context->kcontext = context;
8154925bf6Swillf 
8254925bf6Swillf     /* populate ldap_context with ldap specific options */
8354925bf6Swillf     while (t_ptr && *t_ptr) {
8454925bf6Swillf 	char *opt = NULL, *val = NULL;
8554925bf6Swillf 
8654925bf6Swillf 	if ((status = krb5_ldap_get_db_opt(*t_ptr, &opt, &val)) != 0) {
8754925bf6Swillf 	    goto cleanup;
8854925bf6Swillf 	}
8954925bf6Swillf 	if (opt && !strcmp(opt, "binddn")) {
9054925bf6Swillf 	    if (ldap_context->bind_dn) {
9154925bf6Swillf 		free (opt);
9254925bf6Swillf 		free (val);
9354925bf6Swillf 		status = EINVAL;
9454925bf6Swillf 		krb5_set_error_message (context, status, gettext("'binddn' missing"));
9554925bf6Swillf 		goto cleanup;
9654925bf6Swillf 	    }
9754925bf6Swillf 	    if (val == NULL) {
9854925bf6Swillf 		status = EINVAL;
9954925bf6Swillf 		krb5_set_error_message (context, status, gettext("'binddn' value missing"));
10054925bf6Swillf 		free(opt);
10154925bf6Swillf 		goto cleanup;
10254925bf6Swillf 	    }
10354925bf6Swillf 	    ldap_context->bind_dn = strdup(val);
10454925bf6Swillf 	    if (ldap_context->bind_dn == NULL) {
10554925bf6Swillf 		free (opt);
10654925bf6Swillf 		free (val);
10754925bf6Swillf 		status = ENOMEM;
10854925bf6Swillf 		goto cleanup;
10954925bf6Swillf 	    }
11054925bf6Swillf 	} else if (opt && !strcmp(opt, "nconns")) {
11154925bf6Swillf 	    if (ldap_context->max_server_conns) {
11254925bf6Swillf 		free (opt);
11354925bf6Swillf 		free (val);
11454925bf6Swillf 		status = EINVAL;
11554925bf6Swillf 		krb5_set_error_message (context, status, gettext("'nconns' missing"));
11654925bf6Swillf 		goto cleanup;
11754925bf6Swillf 	    }
11854925bf6Swillf 	    if (val == NULL) {
11954925bf6Swillf 		status = EINVAL;
12054925bf6Swillf 		krb5_set_error_message (context, status, gettext("'nconns' value missing"));
12154925bf6Swillf 		free(opt);
12254925bf6Swillf 		goto cleanup;
12354925bf6Swillf 	    }
12454925bf6Swillf 	    ldap_context->max_server_conns = atoi(val) ? atoi(val) : DEFAULT_CONNS_PER_SERVER;
12554925bf6Swillf 	} else if (opt && !strcmp(opt, "bindpwd")) {
12654925bf6Swillf 	    if (ldap_context->bind_pwd) {
12754925bf6Swillf 		free (opt);
12854925bf6Swillf 		free (val);
12954925bf6Swillf 		status = EINVAL;
13054925bf6Swillf 		krb5_set_error_message (context, status, gettext("'bindpwd' missing"));
13154925bf6Swillf 		goto cleanup;
13254925bf6Swillf 	    }
13354925bf6Swillf 	    if (val == NULL) {
13454925bf6Swillf 		status = EINVAL;
13554925bf6Swillf 		krb5_set_error_message (context, status, gettext("'bindpwd' value missing"));
13654925bf6Swillf 		free(opt);
13754925bf6Swillf 		goto cleanup;
13854925bf6Swillf 	    }
13954925bf6Swillf 	    ldap_context->bind_pwd = strdup(val);
14054925bf6Swillf 	    if (ldap_context->bind_pwd == NULL) {
14154925bf6Swillf 		free (opt);
14254925bf6Swillf 		free (val);
14354925bf6Swillf 		status = ENOMEM;
14454925bf6Swillf 		goto cleanup;
14554925bf6Swillf 	    }
14654925bf6Swillf 	} else if (opt && !strcmp(opt, "host")) {
14754925bf6Swillf 	    if (val == NULL) {
14854925bf6Swillf 		status = EINVAL;
14954925bf6Swillf 		krb5_set_error_message (context, status, gettext("'host' value missing"));
15054925bf6Swillf 		free(opt);
15154925bf6Swillf 		goto cleanup;
15254925bf6Swillf 	    }
15354925bf6Swillf 	    if (ldap_context->server_info_list == NULL)
15454925bf6Swillf 		ldap_context->server_info_list =
15554925bf6Swillf 		    (krb5_ldap_server_info **) calloc(SERV_COUNT+1, sizeof(krb5_ldap_server_info *));
15654925bf6Swillf 
15754925bf6Swillf 	    if (ldap_context->server_info_list == NULL) {
15854925bf6Swillf 		free (opt);
15954925bf6Swillf 		free (val);
16054925bf6Swillf 		status = ENOMEM;
16154925bf6Swillf 		goto cleanup;
16254925bf6Swillf 	    }
16354925bf6Swillf 
16454925bf6Swillf 	    ldap_context->server_info_list[srv_cnt] =
16554925bf6Swillf 		(krb5_ldap_server_info *) calloc(1, sizeof(krb5_ldap_server_info));
16654925bf6Swillf 	    if (ldap_context->server_info_list[srv_cnt] == NULL) {
16754925bf6Swillf 		free (opt);
16854925bf6Swillf 		free (val);
16954925bf6Swillf 		status = ENOMEM;
17054925bf6Swillf 		goto cleanup;
17154925bf6Swillf 	    }
17254925bf6Swillf 
17354925bf6Swillf 	    ldap_context->server_info_list[srv_cnt]->server_status = NOTSET;
17454925bf6Swillf 
17554925bf6Swillf 	    ldap_context->server_info_list[srv_cnt]->server_name = strdup(val);
17654925bf6Swillf 	    if (ldap_context->server_info_list[srv_cnt]->server_name == NULL) {
17754925bf6Swillf 		free (opt);
17854925bf6Swillf 		free (val);
17954925bf6Swillf 		status = ENOMEM;
18054925bf6Swillf 		goto cleanup;
18154925bf6Swillf 	    }
18254925bf6Swillf 
18354925bf6Swillf 	    srv_cnt++;
18454925bf6Swillf #ifdef HAVE_EDIRECTORY
18554925bf6Swillf 	} else if (opt && !strcmp(opt, "cert")) {
18654925bf6Swillf 	    if (val == NULL) {
18754925bf6Swillf 		status = EINVAL;
18854925bf6Swillf 		krb5_set_error_message (context, status, gettext("'cert' value missing"));
18954925bf6Swillf 		free(opt);
19054925bf6Swillf 		goto cleanup;
19154925bf6Swillf 	    }
19254925bf6Swillf 
19354925bf6Swillf 	    if (ldap_context->root_certificate_file == NULL) {
19454925bf6Swillf 		ldap_context->root_certificate_file = strdup(val);
19554925bf6Swillf 		if (ldap_context->root_certificate_file == NULL) {
19654925bf6Swillf 		    free (opt);
19754925bf6Swillf 		    free (val);
19854925bf6Swillf 		    status = ENOMEM;
19954925bf6Swillf 		    goto cleanup;
20054925bf6Swillf 		}
20154925bf6Swillf 	    } else {
20254925bf6Swillf 		void *tmp=NULL;
20354925bf6Swillf 		char *oldstr = NULL;
20454925bf6Swillf 		unsigned int len=0;
20554925bf6Swillf 
20654925bf6Swillf 		oldstr = strdup(ldap_context->root_certificate_file);
20754925bf6Swillf 		if (oldstr == NULL) {
20854925bf6Swillf 		    free (opt);
20954925bf6Swillf 		    free (val);
21054925bf6Swillf 		    status = ENOMEM;
21154925bf6Swillf 		    goto cleanup;
21254925bf6Swillf 		}
21354925bf6Swillf 
21454925bf6Swillf 		tmp = ldap_context->root_certificate_file;
21554925bf6Swillf 		len = strlen(ldap_context->root_certificate_file) + 2 + strlen(val);
21654925bf6Swillf 		ldap_context->root_certificate_file = realloc(ldap_context->root_certificate_file,
21754925bf6Swillf 							      len);
21854925bf6Swillf 		if (ldap_context->root_certificate_file == NULL) {
21954925bf6Swillf 		    free (tmp);
22054925bf6Swillf 		    free (opt);
22154925bf6Swillf 		    free (val);
22254925bf6Swillf 		    status = ENOMEM;
22354925bf6Swillf 		    goto cleanup;
22454925bf6Swillf 		}
22554925bf6Swillf 		memset(ldap_context->root_certificate_file, 0, len);
22654925bf6Swillf 		sprintf(ldap_context->root_certificate_file,"%s %s", oldstr, val);
22754925bf6Swillf 		free (oldstr);
22854925bf6Swillf 	    }
22954925bf6Swillf #endif
23054925bf6Swillf 	} else {
23154925bf6Swillf 	/* ignore hash argument. Might have been passed from create */
23254925bf6Swillf 	    status = EINVAL;
23354925bf6Swillf 	    if (opt && !strcmp(opt, "temporary")) {
234*1da57d55SToomas Soome 		/*
23554925bf6Swillf 		 * temporary is passed in when kdb5_util load without -update is done.
23654925bf6Swillf 		 * This is unsupported by the LDAP plugin.
23754925bf6Swillf 		 */
23854925bf6Swillf 		krb5_set_error_message (context, status,
23954925bf6Swillf 		    gettext("creation of LDAP entries aborted, plugin requires -update argument"));
24054925bf6Swillf 	    } else {
24154925bf6Swillf 		krb5_set_error_message (context, status, gettext("unknown option \'%s\'"),
24254925bf6Swillf 					opt?opt:val);
24354925bf6Swillf 	    }
24454925bf6Swillf 	    free(opt);
24554925bf6Swillf 	    free(val);
24654925bf6Swillf 	    goto cleanup;
24754925bf6Swillf 	}
24854925bf6Swillf 
24954925bf6Swillf 	free(opt);
25054925bf6Swillf 	free(val);
25154925bf6Swillf 	t_ptr++;
25254925bf6Swillf     }
25354925bf6Swillf 
25454925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
25554925bf6Swillf     dal_handle->db_context = (kdb5_dal_handle *) ldap_context;
25654925bf6Swillf 
25754925bf6Swillf     status = krb5_ldap_read_server_params(context, conf_section, KRB5_KDB_SRV_TYPE_ADMIN);
25854925bf6Swillf     if (status) {
25954925bf6Swillf 	dal_handle->db_context = NULL;
26054925bf6Swillf 	prepend_err_str (context, gettext("Error reading LDAP server params: "), status, status);
26154925bf6Swillf 	goto cleanup;
26254925bf6Swillf     }
26354925bf6Swillf     status = krb5_ldap_db_init(context, ldap_context);
26454925bf6Swillf     if (status) {
26554925bf6Swillf 	goto cleanup;
26654925bf6Swillf     }
26754925bf6Swillf 
26854925bf6Swillf     /* read the kerberos container */
26954925bf6Swillf     if ((status = krb5_ldap_read_krbcontainer_params(context,
27054925bf6Swillf 			    &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) {
27154925bf6Swillf 
27254925bf6Swillf 	/* Read the kerberos container location from configuration file */
27354925bf6Swillf 	if (ldap_context->conf_section) {
27454925bf6Swillf 	    if ((status = profile_get_string(context->profile,
27554925bf6Swillf 					   KDB_MODULE_SECTION, ldap_context->conf_section,
27654925bf6Swillf 					   "ldap_kerberos_container_dn", NULL,
27754925bf6Swillf 					   &kparams.DN)) != 0) {
27854925bf6Swillf 		goto cleanup;
27954925bf6Swillf 	    }
28054925bf6Swillf 	}
28154925bf6Swillf 	if (kparams.DN == NULL) {
28254925bf6Swillf 	    if ((status = profile_get_string(context->profile,
28354925bf6Swillf 					   KDB_MODULE_DEF_SECTION,
28454925bf6Swillf 					   "ldap_kerberos_container_dn", NULL,
28554925bf6Swillf 					   NULL, &kparams.DN)) != 0) {
28654925bf6Swillf 		goto cleanup;
28754925bf6Swillf 	    }
28854925bf6Swillf 	}
28954925bf6Swillf 
29054925bf6Swillf 	/* create the kerberos container */
29154925bf6Swillf 	status = krb5_ldap_create_krbcontainer(context,
29254925bf6Swillf 					       ((kparams.DN != NULL) ? &kparams : NULL));
29354925bf6Swillf 	if (status)
29454925bf6Swillf 	    goto cleanup;
29554925bf6Swillf 
29654925bf6Swillf 	krbcontainer_obj_created = TRUE;
29754925bf6Swillf 
29854925bf6Swillf 	status = krb5_ldap_read_krbcontainer_params(context,
29954925bf6Swillf 						    &(ldap_context->krbcontainer));
30054925bf6Swillf 	if (status) {
30154925bf6Swillf 	    krb5_set_error_message(context, status, gettext("while reading kerberos container information"));
30254925bf6Swillf 	    goto cleanup;
30354925bf6Swillf 	}
30454925bf6Swillf 
30554925bf6Swillf     } else if (status) {
30654925bf6Swillf 	krb5_set_error_message(context, status, gettext("while reading kerberos container information"));
30754925bf6Swillf 	goto cleanup;
30854925bf6Swillf     }
30954925bf6Swillf 
31054925bf6Swillf     rparams = (krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params));
31154925bf6Swillf     if (rparams == NULL) {
31254925bf6Swillf 	status = ENOMEM;
31354925bf6Swillf 	goto cleanup;
31454925bf6Swillf     }
31554925bf6Swillf     memset(rparams, 0, sizeof(*rparams));
31654925bf6Swillf     rparams->realm_name = strdup(context->default_realm);
31754925bf6Swillf     if (rparams->realm_name == NULL) {
31854925bf6Swillf 	status = ENOMEM;
31954925bf6Swillf 	goto cleanup;
32054925bf6Swillf     }
32154925bf6Swillf 
32254925bf6Swillf     if ((status = krb5_ldap_create_realm(context, rparams, mask))) {
32354925bf6Swillf 	krb5_set_error_message(context, status, gettext("while creating realm object entry"));
32454925bf6Swillf 	goto cleanup;
32554925bf6Swillf     }
32654925bf6Swillf 
32754925bf6Swillf     /* We just created the Realm container. Here starts our transaction tracking */
32854925bf6Swillf     realm_obj_created = TRUE;
32954925bf6Swillf 
33054925bf6Swillf     /* verify realm object */
33154925bf6Swillf     if ((status = krb5_ldap_read_realm_params(context,
33254925bf6Swillf 					      rparams->realm_name,
33354925bf6Swillf 					      &(ldap_context->lrparams),
33454925bf6Swillf 					      &mask))) {
33554925bf6Swillf 	krb5_set_error_message(context, status, gettext("while reading realm object entry"));
33654925bf6Swillf 	goto cleanup;
33754925bf6Swillf     }
33854925bf6Swillf 
33954925bf6Swillf #ifdef HAVE_EDIRECTORY
34054925bf6Swillf     if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) ||
34154925bf6Swillf 	(mask & LDAP_REALM_PASSWDSERVERS)) {
34254925bf6Swillf 
34354925bf6Swillf 	rightsmask =0;
34454925bf6Swillf 	rightsmask |= LDAP_REALM_RIGHTS;
34554925bf6Swillf 	rightsmask |= LDAP_SUBTREE_RIGHTS;
34654925bf6Swillf 	if ((rparams != NULL) && (rparams->kdcservers != NULL)) {
34754925bf6Swillf 	    for (i=0; (rparams->kdcservers[i] != NULL); i++) {
34854925bf6Swillf 		if ((status=krb5_ldap_add_service_rights(context,
34954925bf6Swillf 				     LDAP_KDC_SERVICE, rparams->kdcservers[i],
35054925bf6Swillf 				     rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
35154925bf6Swillf 		    goto cleanup;
35254925bf6Swillf 		}
35354925bf6Swillf 	    }
35454925bf6Swillf 	}
35554925bf6Swillf 
35654925bf6Swillf 	rightsmask = 0;
35754925bf6Swillf 	rightsmask |= LDAP_REALM_RIGHTS;
35854925bf6Swillf 	rightsmask |= LDAP_SUBTREE_RIGHTS;
35954925bf6Swillf 	if ((rparams != NULL) && (rparams->adminservers != NULL)) {
36054925bf6Swillf 	    for (i=0; (rparams->adminservers[i] != NULL); i++) {
36154925bf6Swillf 		if ((status=krb5_ldap_add_service_rights(context,
36254925bf6Swillf 				     LDAP_ADMIN_SERVICE, rparams->adminservers[i],
36354925bf6Swillf 				     rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
36454925bf6Swillf 		    goto cleanup;
36554925bf6Swillf 		}
36654925bf6Swillf 	    }
36754925bf6Swillf 	}
36854925bf6Swillf 
36954925bf6Swillf 	rightsmask = 0;
37054925bf6Swillf 	rightsmask |= LDAP_REALM_RIGHTS;
37154925bf6Swillf 	rightsmask |= LDAP_SUBTREE_RIGHTS;
37254925bf6Swillf 	if ((rparams != NULL) && (rparams->passwdservers != NULL)) {
37354925bf6Swillf 	    for (i=0; (rparams->passwdservers[i] != NULL); i++) {
37454925bf6Swillf 		if ((status=krb5_ldap_add_service_rights(context,
37554925bf6Swillf 				     LDAP_PASSWD_SERVICE, rparams->passwdservers[i],
37654925bf6Swillf 				     rparams->realm_name, rparams->subtree, rightsmask)) != 0) {
37754925bf6Swillf 		    goto cleanup;
37854925bf6Swillf 		}
37954925bf6Swillf 	    }
38054925bf6Swillf 	}
38154925bf6Swillf     }
38254925bf6Swillf #endif
38354925bf6Swillf 
38454925bf6Swillf cleanup:
38554925bf6Swillf 
38654925bf6Swillf     /* If the krbcontainer/realm creation is not complete, do the roll-back here */
38754925bf6Swillf     if ((krbcontainer_obj_created) && (!realm_obj_created)) {
38854925bf6Swillf 	int rc;
38954925bf6Swillf 	rc = krb5_ldap_delete_krbcontainer(context,
39054925bf6Swillf 		    ((kparams.DN != NULL) ? &kparams : NULL));
39154925bf6Swillf 	krb5_set_error_message(context, rc,
39254925bf6Swillf 	    gettext("could not complete roll-back, error deleting Kerberos Container"));
39354925bf6Swillf     }
39454925bf6Swillf 
39554925bf6Swillf     /* should call krb5_ldap_free_krbcontainer_params() but can't */
39654925bf6Swillf     if (kparams.DN != NULL)
39754925bf6Swillf 	krb5_xfree(kparams.DN);
39854925bf6Swillf 
39954925bf6Swillf     if (rparams)
40054925bf6Swillf 	krb5_ldap_free_realm_params(rparams);
40154925bf6Swillf 
40254925bf6Swillf     return(status);
40354925bf6Swillf }
404