154925bf6Swillf /*
254925bf6Swillf  * lib/kdb/kdb_ldap/ldap_misc.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 /*
312dd2efa5Swillf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3254925bf6Swillf  * Use is subject to license terms.
3354925bf6Swillf  */
3454925bf6Swillf #include <string.h>
3554925bf6Swillf #include <time.h>
3654925bf6Swillf #include <k5-platform.h>
3754925bf6Swillf #include "ldap_main.h"
3854925bf6Swillf #include "ldap_err.h"
3954925bf6Swillf #include "ldap_principal.h"
4054925bf6Swillf #include "princ_xdr.h"
4154925bf6Swillf #include "ldap_pwd_policy.h"
4254925bf6Swillf #include <libintl.h>
4354925bf6Swillf 
4454925bf6Swillf #ifdef NEED_STRPTIME_PROTO
4554925bf6Swillf extern char *strptime (const char *, const char *, struct tm *);
4654925bf6Swillf #endif
4754925bf6Swillf 
4854925bf6Swillf static krb5_error_code
4954925bf6Swillf remove_overlapping_subtrees(char **listin, char **listop, int *subtcount,
5054925bf6Swillf 			    int sscope);
5154925bf6Swillf 
5254925bf6Swillf /* Linux (GNU Libc) provides a length-limited variant of strdup.
5354925bf6Swillf    But all the world's not Linux.  */
5454925bf6Swillf #undef strndup
5554925bf6Swillf #define strndup my_strndup
5654925bf6Swillf #ifdef HAVE_LDAP_STR2DN
my_strndup(const char * input,size_t limit)5754925bf6Swillf static char *my_strndup (const char *input, size_t limit)
5854925bf6Swillf {
5954925bf6Swillf     size_t len = strlen(input);
6054925bf6Swillf     char *result;
6154925bf6Swillf     if (len > limit) {
6254925bf6Swillf 	result = malloc(1 + limit);
6354925bf6Swillf 	if (result != NULL) {
6454925bf6Swillf 	    memcpy(result, input, limit);
6554925bf6Swillf 	    result[limit] = 0;
6654925bf6Swillf 	}
6754925bf6Swillf 	return result;
6854925bf6Swillf     } else
6954925bf6Swillf 	return strdup(input);
7054925bf6Swillf }
7154925bf6Swillf #endif
7254925bf6Swillf 
7354925bf6Swillf /* Get integer or string values from the config section, falling back
7454925bf6Swillf    to the default section, then to hard-coded values.  */
7554925bf6Swillf static errcode_t
prof_get_integer_def(krb5_context ctx,const char * conf_section,const char * name,int dfl,krb5_ui_4 * out)7654925bf6Swillf prof_get_integer_def(krb5_context ctx, const char *conf_section,
7754925bf6Swillf 		     const char *name, int dfl, krb5_ui_4 *out)
7854925bf6Swillf {
7954925bf6Swillf     errcode_t err;
8054925bf6Swillf     int out_temp = 0;
8154925bf6Swillf 
8254925bf6Swillf     err = profile_get_integer (ctx->profile,
8354925bf6Swillf 			       KDB_MODULE_SECTION, conf_section, name,
8454925bf6Swillf 			       0, &out_temp);
8554925bf6Swillf     if (err) {
8654925bf6Swillf 	krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
8754925bf6Swillf 				name, error_message(err));
8854925bf6Swillf 	return err;
8954925bf6Swillf     }
9054925bf6Swillf     if (out_temp != 0) {
9154925bf6Swillf 	*out = out_temp;
9254925bf6Swillf 	return 0;
9354925bf6Swillf     }
9454925bf6Swillf     err = profile_get_integer (ctx->profile,
9554925bf6Swillf 			       KDB_MODULE_DEF_SECTION, name, 0,
9654925bf6Swillf 			       dfl, &out_temp);
9754925bf6Swillf     if (err) {
9854925bf6Swillf 	krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
9954925bf6Swillf 				name, error_message(err));
10054925bf6Swillf 	return err;
10154925bf6Swillf     }
10254925bf6Swillf     *out = out_temp;
10354925bf6Swillf     return 0;
10454925bf6Swillf }
10554925bf6Swillf 
10654925bf6Swillf /* We don't have non-null defaults in any of our calls, so don't
10754925bf6Swillf    bother with the extra argument.  */
10854925bf6Swillf static errcode_t
prof_get_string_def(krb5_context ctx,const char * conf_section,const char * name,char ** out)10954925bf6Swillf prof_get_string_def(krb5_context ctx, const char *conf_section,
11054925bf6Swillf 		    const char *name, char **out)
11154925bf6Swillf {
11254925bf6Swillf     errcode_t err;
11354925bf6Swillf 
11454925bf6Swillf     err = profile_get_string (ctx->profile,
11554925bf6Swillf 			      KDB_MODULE_SECTION, conf_section, name,
11654925bf6Swillf 			      0, out);
11754925bf6Swillf     if (err) {
11854925bf6Swillf 	krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
11954925bf6Swillf 				name, error_message(err));
12054925bf6Swillf 	return err;
12154925bf6Swillf     }
12254925bf6Swillf     if (*out != 0)
12354925bf6Swillf 	return 0;
12454925bf6Swillf     err = profile_get_string (ctx->profile,
12554925bf6Swillf 			      KDB_MODULE_DEF_SECTION, name, 0,
12654925bf6Swillf 			      0, out);
12754925bf6Swillf     if (err) {
12854925bf6Swillf 	krb5_set_error_message (ctx, err, gettext("Error reading '%s' attribute: %s"),
12954925bf6Swillf 				name, error_message(err));
13054925bf6Swillf 	return err;
13154925bf6Swillf     }
13254925bf6Swillf     return 0;
13354925bf6Swillf }
13454925bf6Swillf 
13554925bf6Swillf 
13654925bf6Swillf 
13754925bf6Swillf /*
13854925bf6Swillf  * This function reads the parameters from the krb5.conf file. The
13954925bf6Swillf  * parameters read here are DAL-LDAP specific attributes. Some of
14054925bf6Swillf  * these are ldap_server ....
14154925bf6Swillf  */
14254925bf6Swillf krb5_error_code
krb5_ldap_read_server_params(context,conf_section,srv_type)14354925bf6Swillf krb5_ldap_read_server_params(context, conf_section, srv_type)
14454925bf6Swillf     krb5_context               context;
14554925bf6Swillf     char                       *conf_section;
14654925bf6Swillf     int                        srv_type;
14754925bf6Swillf {
14854925bf6Swillf     char                        *tempval=NULL, *save_ptr=NULL;
14954925bf6Swillf     const char                  *delims="\t\n\f\v\r ,";
15054925bf6Swillf     krb5_error_code             st=0;
15154925bf6Swillf     kdb5_dal_handle             *dal_handle=NULL;
15254925bf6Swillf     krb5_ldap_context           *ldap_context=NULL;
15354925bf6Swillf     krb5_ldap_server_info       ***server_info=NULL;
15454925bf6Swillf 
15554925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
15654925bf6Swillf     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
15754925bf6Swillf 
15854925bf6Swillf     /* copy the conf_section into ldap_context for later use */
15954925bf6Swillf     if (conf_section) {
16054925bf6Swillf 	ldap_context->conf_section = strdup (conf_section);
16154925bf6Swillf 	if (ldap_context->conf_section == NULL) {
16254925bf6Swillf 	    st = ENOMEM;
16354925bf6Swillf 	    goto cleanup;
16454925bf6Swillf 	}
16554925bf6Swillf     }
16654925bf6Swillf 
16754925bf6Swillf     /* initialize the mutexs and condition variable */
16854925bf6Swillf     /* this portion logically doesn't fit here should be moved appropriately */
16954925bf6Swillf 
17054925bf6Swillf     /* this mutex is used in ldap reconnection pool */
17154925bf6Swillf     if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) {
17254925bf6Swillf 	st = KRB5_KDB_SERVER_INTERNAL_ERR;
17354925bf6Swillf #if 0
17454925bf6Swillf 	st = -1;
17554925bf6Swillf 	krb5_ldap_dal_err_funcp(context, krb5_err_have_str, st,
17654925bf6Swillf 				"k5_mutex_init failed");
17754925bf6Swillf #endif
17854925bf6Swillf 	goto cleanup;
17954925bf6Swillf     }
18054925bf6Swillf 
18154925bf6Swillf     /*
18254925bf6Swillf      * If max_server_conns is not set read it from database module
18354925bf6Swillf      * section of conf file this parameter defines maximum ldap
18454925bf6Swillf      * connections per ldap server.
18554925bf6Swillf      */
18654925bf6Swillf     if (ldap_context->max_server_conns == 0) {
18754925bf6Swillf 	st = prof_get_integer_def (context, conf_section,
18854925bf6Swillf 				   "ldap_conns_per_server",
18954925bf6Swillf 				   DEFAULT_CONNS_PER_SERVER,
19054925bf6Swillf 				   &ldap_context->max_server_conns);
19154925bf6Swillf 	if (st)
19254925bf6Swillf 	    goto cleanup;
19354925bf6Swillf     }
19454925bf6Swillf 
19554925bf6Swillf     if (ldap_context->max_server_conns < 2) {
19654925bf6Swillf 	st = EINVAL;
19754925bf6Swillf 	krb5_set_error_message (context, st,
19854925bf6Swillf 				gettext("Minimum connections required per server is 2"));
19954925bf6Swillf 	goto cleanup;
20054925bf6Swillf     }
20154925bf6Swillf 
20254925bf6Swillf     /*
20354925bf6Swillf      * If the bind dn is not set read it from the database module
20454925bf6Swillf      * section of conf file this paramter is populated by one of the
20554925bf6Swillf      * KDC, ADMIN or PASSWD dn to be used to connect to LDAP
20654925bf6Swillf      * server.  The srv_type decides which dn to read.
20754925bf6Swillf      */
20854925bf6Swillf     if (ldap_context->bind_dn == NULL) {
20954925bf6Swillf 	char *name = 0;
21054925bf6Swillf 	if (srv_type == KRB5_KDB_SRV_TYPE_KDC)
21154925bf6Swillf 	    name = "ldap_kdc_dn";
21254925bf6Swillf 	else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN)
21354925bf6Swillf 	    name = "ldap_kadmind_dn";
21454925bf6Swillf 	else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD)
21554925bf6Swillf 	    name = "ldap_kpasswdd_dn";
21654925bf6Swillf 
21754925bf6Swillf 	if (name) {
21854925bf6Swillf 	    st = prof_get_string_def (context, conf_section, name,
21954925bf6Swillf 				      &ldap_context->bind_dn);
22054925bf6Swillf 	    if (st)
22154925bf6Swillf 		goto cleanup;
22254925bf6Swillf 	}
22354925bf6Swillf     }
22454925bf6Swillf 
22554925bf6Swillf     /*
22654925bf6Swillf      * Read service_password_file parameter from database module
22754925bf6Swillf      * section of conf file this file contains stashed passwords of
22854925bf6Swillf      * the KDC, ADMIN and PASSWD dns.
22954925bf6Swillf      */
23054925bf6Swillf     if (ldap_context->service_password_file == NULL) {
23154925bf6Swillf 	/*
23254925bf6Swillf 	 * Solaris Kerberos: providing a default.
23354925bf6Swillf 	 */
23454925bf6Swillf 	st = profile_get_string (context->profile, KDB_MODULE_SECTION,
23554925bf6Swillf 				   conf_section,
23654925bf6Swillf 				  "ldap_service_password_file",
23754925bf6Swillf 				  NULL,
23854925bf6Swillf 				  &ldap_context->service_password_file);
23954925bf6Swillf 
24054925bf6Swillf 	if (st)
24154925bf6Swillf 	    goto cleanup;
24254925bf6Swillf 
24354925bf6Swillf 	if (ldap_context->service_password_file == NULL) {
24454925bf6Swillf 	    st = profile_get_string (context->profile, KDB_MODULE_DEF_SECTION,
24554925bf6Swillf 				      "ldap_service_password_file",
24654925bf6Swillf 				      NULL,
24754925bf6Swillf 				      DEF_SERVICE_PASSWD_FILE,
24854925bf6Swillf 				      &ldap_context->service_password_file);
24954925bf6Swillf 	    if (st)
25054925bf6Swillf 		goto cleanup;
25154925bf6Swillf 	}
25254925bf6Swillf     }
25354925bf6Swillf 
25454925bf6Swillf /*
25554925bf6Swillf  * Solaris Kerberos: we must use root_certificate_file
25654925bf6Swillf  *
25754925bf6Swillf  * Note, I've changed the ldap_root_certificate_file config parameter to
25854925bf6Swillf  * ldap_cert_path which is more appropriate for that parameter.
25954925bf6Swillf  */
26054925bf6Swillf /* #ifdef HAVE_EDIRECTORY */
26154925bf6Swillf     /*
26254925bf6Swillf      * If root certificate file is not set read it from database
26354925bf6Swillf      * module section of conf file this is the trusted root
26454925bf6Swillf      * certificate of the Directory.
26554925bf6Swillf      */
26654925bf6Swillf     if (ldap_context->root_certificate_file == NULL) {
26754925bf6Swillf 	st = prof_get_string_def (context, conf_section,
26854925bf6Swillf 				  "ldap_cert_path",
26954925bf6Swillf 				  &ldap_context->root_certificate_file);
27054925bf6Swillf 	if (st)
27154925bf6Swillf 	    goto cleanup;
27254925bf6Swillf     }
27354925bf6Swillf /* #endif */
27454925bf6Swillf 
27554925bf6Swillf     /*
27654925bf6Swillf      * If the ldap server parameter is not set read the list of ldap
27754925bf6Swillf      * servers from the database module section of the conf file.
27854925bf6Swillf      */
27954925bf6Swillf 
28054925bf6Swillf     if (ldap_context->server_info_list == NULL) {
28154925bf6Swillf 	unsigned int ele=0;
28254925bf6Swillf 
28354925bf6Swillf 	server_info = &(ldap_context->server_info_list);
28454925bf6Swillf 	*server_info = (krb5_ldap_server_info **) calloc (SERV_COUNT+1,
28554925bf6Swillf 							  sizeof (krb5_ldap_server_info *));
28654925bf6Swillf 
28754925bf6Swillf 	if (*server_info == NULL) {
28854925bf6Swillf 	    st = ENOMEM;
28954925bf6Swillf 	    goto cleanup;
29054925bf6Swillf 	}
29154925bf6Swillf 
29254925bf6Swillf 	if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section,
29354925bf6Swillf 				   "ldap_servers", NULL, &tempval)) != 0) {
29454925bf6Swillf 	    krb5_set_error_message (context, st, gettext("Error reading 'ldap_servers' attribute"));
29554925bf6Swillf 	    goto cleanup;
29654925bf6Swillf 	}
29754925bf6Swillf 
29854925bf6Swillf 	if (tempval == NULL) {
29954925bf6Swillf 
30054925bf6Swillf 	    (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
30154925bf6Swillf 								  sizeof(krb5_ldap_server_info));
30254925bf6Swillf 
30354925bf6Swillf 	    if ((*server_info)[ele] == NULL) {
30454925bf6Swillf 		st = ENOMEM;
30554925bf6Swillf 		goto cleanup;
30654925bf6Swillf 	    }
30754925bf6Swillf 	    (*server_info)[ele]->server_name = strdup("ldapi://");
30854925bf6Swillf 	    if ((*server_info)[ele]->server_name == NULL) {
30954925bf6Swillf 		st = ENOMEM;
31054925bf6Swillf 		goto cleanup;
31154925bf6Swillf 	    }
31254925bf6Swillf 	    (*server_info)[ele]->server_status = NOTSET;
31354925bf6Swillf 	} else {
31454925bf6Swillf 	    char *item=NULL;
31554925bf6Swillf 
31654925bf6Swillf 	    item = strtok_r(tempval,delims,&save_ptr);
31754925bf6Swillf 	    while (item != NULL && ele<SERV_COUNT) {
31854925bf6Swillf 		(*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
31954925bf6Swillf 								      sizeof(krb5_ldap_server_info));
32054925bf6Swillf 		if ((*server_info)[ele] == NULL) {
32154925bf6Swillf 		    st = ENOMEM;
32254925bf6Swillf 		    goto cleanup;
32354925bf6Swillf 		}
32454925bf6Swillf 		(*server_info)[ele]->server_name = strdup(item);
32554925bf6Swillf 		if ((*server_info)[ele]->server_name == NULL) {
32654925bf6Swillf 		    st = ENOMEM;
32754925bf6Swillf 		    goto cleanup;
32854925bf6Swillf 		}
32954925bf6Swillf 
33054925bf6Swillf 		(*server_info)[ele]->server_status = NOTSET;
33154925bf6Swillf 		item = strtok_r(NULL,delims,&save_ptr);
33254925bf6Swillf 		++ele;
33354925bf6Swillf 	    }
33454925bf6Swillf 	    profile_release_string(tempval);
33554925bf6Swillf 	}
33654925bf6Swillf     }
33754925bf6Swillf 
33854925bf6Swillf cleanup:
33954925bf6Swillf     return(st);
34054925bf6Swillf }
34154925bf6Swillf 
34254925bf6Swillf /*
34354925bf6Swillf  * This function frees the krb5_ldap_context structure members.
34454925bf6Swillf  */
34554925bf6Swillf 
34654925bf6Swillf krb5_error_code
krb5_ldap_free_server_params(ldap_context)34754925bf6Swillf krb5_ldap_free_server_params(ldap_context)
34854925bf6Swillf     krb5_ldap_context           *ldap_context;
34954925bf6Swillf {
35054925bf6Swillf     int                         i=0;
35154925bf6Swillf     krb5_ldap_server_handle     *ldap_server_handle=NULL, *next_ldap_server_handle=NULL;
35254925bf6Swillf 
35354925bf6Swillf     if (ldap_context == NULL)
35454925bf6Swillf 	return 0;
35554925bf6Swillf 
35654925bf6Swillf     /* Free all ldap servers list and the ldap handles associated with
35754925bf6Swillf        the ldap server.  */
35854925bf6Swillf     if (ldap_context->server_info_list) {
35954925bf6Swillf 	while (ldap_context->server_info_list[i]) {
36054925bf6Swillf 	    if (ldap_context->server_info_list[i]->server_name) {
36154925bf6Swillf 		free (ldap_context->server_info_list[i]->server_name);
36254925bf6Swillf 	    }
36354925bf6Swillf #ifdef HAVE_EDIRECTORY
36454925bf6Swillf 	    if (ldap_context->server_info_list[i]->root_certificate_file) {
36554925bf6Swillf 		free (ldap_context->server_info_list[i]->root_certificate_file);
36654925bf6Swillf 	    }
36754925bf6Swillf #endif
36854925bf6Swillf 	    if (ldap_context->server_info_list[i]->ldap_server_handles) {
36954925bf6Swillf 		ldap_server_handle = ldap_context->server_info_list[i]->ldap_server_handles;
37054925bf6Swillf 		while (ldap_server_handle) {
37154925bf6Swillf 		    ldap_unbind_ext_s(ldap_server_handle->ldap_handle, NULL, NULL);
37254925bf6Swillf 		    ldap_server_handle->ldap_handle = NULL;
37354925bf6Swillf 		    next_ldap_server_handle = ldap_server_handle->next;
37454925bf6Swillf 		    krb5_xfree(ldap_server_handle);
37554925bf6Swillf 		    ldap_server_handle = next_ldap_server_handle;
37654925bf6Swillf 		}
37754925bf6Swillf 	    }
37854925bf6Swillf 	    krb5_xfree(ldap_context->server_info_list[i]);
37954925bf6Swillf 	    i++;
38054925bf6Swillf 	}
38154925bf6Swillf 	krb5_xfree(ldap_context->server_info_list);
38254925bf6Swillf     }
38354925bf6Swillf 
38454925bf6Swillf     if (ldap_context->conf_section != NULL) {
38554925bf6Swillf 	krb5_xfree(ldap_context->conf_section);
38654925bf6Swillf 	ldap_context->conf_section = NULL;
38754925bf6Swillf     }
38854925bf6Swillf 
38954925bf6Swillf     if (ldap_context->bind_dn != NULL) {
39054925bf6Swillf 	krb5_xfree(ldap_context->bind_dn);
39154925bf6Swillf 	ldap_context->bind_dn = NULL;
39254925bf6Swillf     }
39354925bf6Swillf 
39454925bf6Swillf     if (ldap_context->bind_pwd != NULL) {
39554925bf6Swillf 	krb5_xfree(ldap_context->bind_pwd);
39654925bf6Swillf 	ldap_context->bind_pwd = NULL;
39754925bf6Swillf     }
39854925bf6Swillf 
39954925bf6Swillf     if (ldap_context->service_password_file != NULL) {
40054925bf6Swillf 	krb5_xfree(ldap_context->service_password_file);
40154925bf6Swillf 	ldap_context->service_password_file = NULL;
40254925bf6Swillf     }
40354925bf6Swillf 
4047c64d375Smp153739 /* Solaris Kerberos */
4057c64d375Smp153739 /* #ifdef HAVE_EDIRECTORY */
40654925bf6Swillf     if (ldap_context->root_certificate_file != NULL) {
40754925bf6Swillf 	krb5_xfree(ldap_context->root_certificate_file);
40854925bf6Swillf 	ldap_context->root_certificate_file = NULL;
40954925bf6Swillf     }
4107c64d375Smp153739 /* #endif */
41154925bf6Swillf 
41254925bf6Swillf     if (ldap_context->service_cert_path != NULL) {
41354925bf6Swillf 	krb5_xfree(ldap_context->service_cert_path);
41454925bf6Swillf 	ldap_context->service_cert_path = NULL;
41554925bf6Swillf     }
41654925bf6Swillf 
41754925bf6Swillf     if (ldap_context->service_cert_pass != NULL) {
41854925bf6Swillf 	krb5_xfree(ldap_context->service_cert_pass);
41954925bf6Swillf 	ldap_context->service_cert_pass = NULL;
42054925bf6Swillf     }
42154925bf6Swillf 
42254925bf6Swillf     if (ldap_context->certificates) {
42354925bf6Swillf 	i=0;
42454925bf6Swillf 	while (ldap_context->certificates[i] != NULL) {
42554925bf6Swillf 	    krb5_xfree(ldap_context->certificates[i]->certificate);
42654925bf6Swillf 	    krb5_xfree(ldap_context->certificates[i]);
42754925bf6Swillf 	    ++i;
42854925bf6Swillf 	}
42954925bf6Swillf 	krb5_xfree(ldap_context->certificates);
43054925bf6Swillf     }
43154925bf6Swillf 
43254925bf6Swillf     k5_mutex_destroy(&ldap_context->hndl_lock);
43354925bf6Swillf 
43454925bf6Swillf     krb5_xfree(ldap_context);
43554925bf6Swillf     return(0);
43654925bf6Swillf }
43754925bf6Swillf 
43854925bf6Swillf 
43954925bf6Swillf /*
44054925bf6Swillf  * check to see if the principal belongs to the default realm.
44154925bf6Swillf  * The default realm is present in the krb5_ldap_context structure.
44254925bf6Swillf  * The principal has a realm portion. This realm portion is compared with the default realm
44354925bf6Swillf  * to check whether the principal belong to the default realm.
44454925bf6Swillf  * Return 0 if principal belongs to default realm else 1.
44554925bf6Swillf  */
44654925bf6Swillf 
44754925bf6Swillf krb5_error_code
is_principal_in_realm(ldap_context,searchfor)44854925bf6Swillf is_principal_in_realm(ldap_context, searchfor)
44954925bf6Swillf     krb5_ldap_context          *ldap_context;
45054925bf6Swillf     krb5_const_principal       searchfor;
45154925bf6Swillf {
45254925bf6Swillf     size_t                      defrealmlen=0;
45354925bf6Swillf     char                        *defrealm=NULL;
45454925bf6Swillf 
45554925bf6Swillf #define FIND_MAX(a,b) ((a) > (b) ? (a) : (b))
45654925bf6Swillf 
45754925bf6Swillf     defrealmlen = strlen(ldap_context->lrparams->realm_name);
45854925bf6Swillf     defrealm = ldap_context->lrparams->realm_name;
45954925bf6Swillf 
46054925bf6Swillf     /*
46154925bf6Swillf      * Care should be taken for inter-realm principals as the default
46254925bf6Swillf      * realm can exist in the realm part of the principal name or can
46354925bf6Swillf      * also exist in the second portion of the name part.  However, if
46454925bf6Swillf      * the default realm exist in the second part of the principal
46554925bf6Swillf      * portion, then the first portion of the principal name SHOULD be
46654925bf6Swillf      * "krbtgt".  All this check is done in the immediate block.
46754925bf6Swillf      */
46854925bf6Swillf     if (searchfor->length == 2)
46954925bf6Swillf 	if ((strncasecmp(searchfor->data[0].data, "krbtgt",
47054925bf6Swillf 			 FIND_MAX(searchfor->data[0].length, strlen("krbtgt"))) == 0) &&
47154925bf6Swillf 	    (strncasecmp(searchfor->data[1].data, defrealm,
47254925bf6Swillf 			 FIND_MAX(searchfor->data[1].length, defrealmlen)) == 0))
47354925bf6Swillf 	    return 0;
47454925bf6Swillf 
47554925bf6Swillf     /* first check the length, if they are not equal, then they are not same */
47654925bf6Swillf     if (strlen(defrealm) != searchfor->realm.length)
47754925bf6Swillf 	return 1;
47854925bf6Swillf 
47954925bf6Swillf     /* if the length is equal, check for the contents */
48054925bf6Swillf     if (strncmp(defrealm, searchfor->realm.data,
48154925bf6Swillf 		searchfor->realm.length) != 0)
48254925bf6Swillf 	return 1;
48354925bf6Swillf     /* if we are here, then the realm portions match, return 0 */
48454925bf6Swillf     return 0;
48554925bf6Swillf }
48654925bf6Swillf 
48754925bf6Swillf 
48854925bf6Swillf /*
48954925bf6Swillf  * Deduce the subtree information from the context. A realm can have
49054925bf6Swillf  * multiple subtrees.
49154925bf6Swillf  * 1. the Realm container
49254925bf6Swillf  * 2. the actual subtrees associated with the Realm
49354925bf6Swillf  *
49454925bf6Swillf  * However, there are some conditions to be considered to deduce the
49554925bf6Swillf  * actual subtree/s associated with the realm.  The conditions are as
49654925bf6Swillf  * follows:
49754925bf6Swillf  * 1. If the subtree information of the Realm is [Root] or NULL (that
49854925bf6Swillf  *    is internal a [Root]) then the realm has only one subtree
49954925bf6Swillf  *    i.e [Root], i.e. whole of the tree.
50054925bf6Swillf  * 2. If the subtree information of the Realm is missing/absent, then the
50154925bf6Swillf  *    realm has only one, i.e., the Realm container.  NOTE: In all cases
50254925bf6Swillf  *    Realm container SHOULD be the one among the subtrees or the only
50354925bf6Swillf  *    one subtree.
50454925bf6Swillf  * 3. The subtree information of the realm is overlapping the realm
50554925bf6Swillf  *    container of the realm, then the realm has only one subtree and
50654925bf6Swillf  *    it is the subtree information associated with the realm.
50754925bf6Swillf  */
50854925bf6Swillf krb5_error_code
krb5_get_subtree_info(ldap_context,subtreearr,ntree)50954925bf6Swillf krb5_get_subtree_info(ldap_context, subtreearr, ntree)
51054925bf6Swillf     krb5_ldap_context           *ldap_context;
51154925bf6Swillf     char                        ***subtreearr;
51254925bf6Swillf     unsigned int                *ntree;
51354925bf6Swillf {
51454925bf6Swillf     int                         st=0, i=0, subtreecount=0;
51554925bf6Swillf     int				ncount=0, search_scope=0;
51654925bf6Swillf     char                        **subtree=NULL, *realm_cont_dn=NULL;
51754925bf6Swillf     char                        **subtarr=NULL;
51854925bf6Swillf     char                        *containerref=NULL;
51954925bf6Swillf     char			**newsubtree=NULL;
52054925bf6Swillf 
52154925bf6Swillf     containerref = ldap_context->lrparams->containerref;
52254925bf6Swillf     subtree = ldap_context->lrparams->subtree;
52354925bf6Swillf     realm_cont_dn = ldap_context->lrparams->realmdn;
52454925bf6Swillf     subtreecount = ldap_context->lrparams->subtreecount;
52554925bf6Swillf     search_scope = ldap_context->lrparams->search_scope;
52654925bf6Swillf 
52754925bf6Swillf     subtarr = (char **) malloc(sizeof(char *) * (subtreecount + 1 /*realm dn*/ + 1 /*containerref*/ + 1));
52854925bf6Swillf     if (subtarr == NULL) {
52954925bf6Swillf 	st = ENOMEM;
53054925bf6Swillf 	goto cleanup;
53154925bf6Swillf     }
53254925bf6Swillf     memset(subtarr, 0, (sizeof(char *) * (subtreecount+1+1+1)));
53354925bf6Swillf 
53454925bf6Swillf     /* get the complete subtree list */
53554925bf6Swillf     for (i=0; i<subtreecount && subtree[i]!=NULL; i++) {
53654925bf6Swillf 	subtarr[i] = strdup(subtree[i]);
53754925bf6Swillf 	if (subtarr[i] == NULL) {
53854925bf6Swillf 	    st = ENOMEM;
53954925bf6Swillf 	    goto cleanup;
54054925bf6Swillf 	}
54154925bf6Swillf     }
54254925bf6Swillf 
54354925bf6Swillf     subtarr[i] = strdup(realm_cont_dn);
54454925bf6Swillf     if (subtarr[i++] == NULL) {
54554925bf6Swillf 	st = ENOMEM;
54654925bf6Swillf 	goto cleanup;
54754925bf6Swillf     }
54854925bf6Swillf 
54954925bf6Swillf     if (containerref != NULL) {
55054925bf6Swillf 	subtarr[i] = strdup(containerref);
55154925bf6Swillf 	if (subtarr[i++] == NULL) {
55254925bf6Swillf 	    st = ENOMEM;
55354925bf6Swillf 	    goto cleanup;
55454925bf6Swillf 	}
55554925bf6Swillf     }
55654925bf6Swillf 
55754925bf6Swillf     ncount = i;
55854925bf6Swillf     newsubtree = (char **) malloc(sizeof(char *) * (ncount + 1));
55954925bf6Swillf     if (newsubtree == NULL) {
56054925bf6Swillf         st = ENOMEM;
56154925bf6Swillf         goto cleanup;
56254925bf6Swillf     }
56354925bf6Swillf     memset(newsubtree, 0, (sizeof(char *) * (ncount+1)));
56454925bf6Swillf     if ((st = remove_overlapping_subtrees(subtarr, newsubtree, &ncount,
56554925bf6Swillf 		search_scope)) != 0) {
56654925bf6Swillf         goto cleanup;
56754925bf6Swillf     }
56854925bf6Swillf 
56954925bf6Swillf     *ntree = ncount;
57054925bf6Swillf     *subtreearr = newsubtree;
57154925bf6Swillf 
57254925bf6Swillf cleanup:
57354925bf6Swillf     if (subtarr != NULL) {
57454925bf6Swillf 	for (i=0; subtarr[i] != NULL; i++)
57554925bf6Swillf 	    free(subtarr[i]);
57654925bf6Swillf 	free(subtarr);
57754925bf6Swillf     }
57854925bf6Swillf 
57954925bf6Swillf     if (st != 0) {
58054925bf6Swillf         if (newsubtree != NULL) {
58154925bf6Swillf 	    for (i=0; newsubtree[i] != NULL; i++)
58254925bf6Swillf 	        free(newsubtree[i]);
58354925bf6Swillf 	    free(newsubtree);
58454925bf6Swillf         }
58554925bf6Swillf     }
58654925bf6Swillf     return st;
58754925bf6Swillf }
58854925bf6Swillf 
58954925bf6Swillf /*
59054925bf6Swillf  * This function appends the content with a type into the tl_data
59154925bf6Swillf  * structure.  Based on the type the length of the content is either
59254925bf6Swillf  * pre-defined or computed from the content.  Returns 0 in case of
59354925bf6Swillf  * success and 1 if the type associated with the content is undefined.
59454925bf6Swillf  */
59554925bf6Swillf 
59654925bf6Swillf krb5_error_code
store_tl_data(tl_data,tl_type,value)59754925bf6Swillf store_tl_data(tl_data, tl_type, value)
59854925bf6Swillf     krb5_tl_data                *tl_data;
59954925bf6Swillf     int                         tl_type;
60054925bf6Swillf     void                        *value;
60154925bf6Swillf {
60254925bf6Swillf     unsigned int                currlen=0, tldatalen=0;
60354925bf6Swillf     unsigned char               *curr=NULL;
60454925bf6Swillf     void                        *reallocptr=NULL;
60554925bf6Swillf 
60654925bf6Swillf     tl_data->tl_data_type = KDB_TL_USER_INFO;
60754925bf6Swillf     switch (tl_type) {
60854925bf6Swillf     case KDB_TL_PRINCCOUNT:
60954925bf6Swillf     case KDB_TL_PRINCTYPE:
61054925bf6Swillf     case KDB_TL_MASK:
61154925bf6Swillf     {
61254925bf6Swillf 	int *iptr = (int *)value;
61354925bf6Swillf 	int ivalue = *iptr;
61454925bf6Swillf 
61554925bf6Swillf 	currlen = tl_data->tl_data_length;
61654925bf6Swillf 	tl_data->tl_data_length += 1 + 2 + 2;
61754925bf6Swillf 	/* allocate required memory */
61854925bf6Swillf 	reallocptr = tl_data->tl_data_contents;
61954925bf6Swillf 	tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
62054925bf6Swillf 					    tl_data->tl_data_length);
62154925bf6Swillf 	if (tl_data->tl_data_contents == NULL) {
62254925bf6Swillf 	    if (reallocptr)
62354925bf6Swillf 		free (reallocptr);
62454925bf6Swillf 	    return ENOMEM;
62554925bf6Swillf 	}
62654925bf6Swillf 	curr = (tl_data->tl_data_contents + currlen);
62754925bf6Swillf 
62854925bf6Swillf 	/* store the tl_type value */
62954925bf6Swillf 	memset(curr, tl_type, 1);
63054925bf6Swillf 	curr += 1;
63154925bf6Swillf 	/* store the content length */
63254925bf6Swillf 	tldatalen = 2;
63354925bf6Swillf 	STORE16_INT(curr, tldatalen);
63454925bf6Swillf 	curr += 2;
63554925bf6Swillf 	/* store the content */
63654925bf6Swillf 	STORE16_INT(curr, ivalue);
63754925bf6Swillf 	curr += 2;
63854925bf6Swillf 	break;
63954925bf6Swillf     }
64054925bf6Swillf 
64154925bf6Swillf     case KDB_TL_USERDN:
64254925bf6Swillf     case KDB_TL_LINKDN:
64354925bf6Swillf     {
64454925bf6Swillf 	char *cptr = (char *)value;
64554925bf6Swillf 
64654925bf6Swillf 	currlen = tl_data->tl_data_length;
64754925bf6Swillf 	tl_data->tl_data_length += 1 + 2 + strlen(cptr);
64854925bf6Swillf 	/* allocate required memory */
64954925bf6Swillf 	reallocptr = tl_data->tl_data_contents;
65054925bf6Swillf 	tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
65154925bf6Swillf 					    tl_data->tl_data_length);
65254925bf6Swillf 	if (tl_data->tl_data_contents == NULL) {
65354925bf6Swillf 	    if (reallocptr)
65454925bf6Swillf 		free (reallocptr);
65554925bf6Swillf 	    return ENOMEM;
65654925bf6Swillf 	}
65754925bf6Swillf 	curr = (tl_data->tl_data_contents + currlen);
65854925bf6Swillf 
65954925bf6Swillf 	/* store the tl_type value */
66054925bf6Swillf 	memset(curr, tl_type, 1);
66154925bf6Swillf 	curr += 1;
66254925bf6Swillf 	/* store the content length */
66354925bf6Swillf 	tldatalen = strlen(cptr);
66454925bf6Swillf 	STORE16_INT(curr, tldatalen);
66554925bf6Swillf 	curr += 2;
66654925bf6Swillf 	/* store the content */
66754925bf6Swillf 	memcpy(curr, cptr, tldatalen);
66854925bf6Swillf 	curr += tldatalen;
66954925bf6Swillf 	break;
67054925bf6Swillf     }
67154925bf6Swillf 
67254925bf6Swillf     default:
67354925bf6Swillf 	return 1;
67454925bf6Swillf 
67554925bf6Swillf     }
67654925bf6Swillf     return 0;
67754925bf6Swillf }
67854925bf6Swillf 
67954925bf6Swillf /*
68054925bf6Swillf  * This function scans the tl_data structure to get the value of a
68154925bf6Swillf  * type defined by the tl_type (second parameter).  The tl_data
68254925bf6Swillf  * structure has all the data in the tl_data_contents member.  The
68354925bf6Swillf  * format of the tl_data_contents is as follows.  The first byte
68454925bf6Swillf  * defines the type of the content that follows.  The next 2 bytes
68554925bf6Swillf  * define the size n (in terms of bytes) of the content that
68654925bf6Swillf  * follows.  The next n bytes define the content itself.
68754925bf6Swillf  */
68854925bf6Swillf 
68954925bf6Swillf krb5_error_code
decode_tl_data(tl_data,tl_type,data)69054925bf6Swillf decode_tl_data(tl_data, tl_type, data)
69154925bf6Swillf     krb5_tl_data                *tl_data;
69254925bf6Swillf     int                         tl_type;
69354925bf6Swillf     void                        **data;
69454925bf6Swillf {
69554925bf6Swillf     int                         subtype=0, i=0, limit=10;
69654925bf6Swillf     unsigned int                sublen=0;
69754925bf6Swillf     unsigned char               *curr=NULL;
69854925bf6Swillf     int                         *intptr=NULL;
69954925bf6Swillf     long                        *longptr=NULL;
70054925bf6Swillf     char                        *DN=NULL, **DNarr=NULL;
70154925bf6Swillf     krb5_error_code             st=-1;
70254925bf6Swillf 
70354925bf6Swillf     *data = NULL;
70454925bf6Swillf 
70554925bf6Swillf     curr = tl_data->tl_data_contents;
70654925bf6Swillf     while (curr < (tl_data->tl_data_contents + tl_data->tl_data_length)) {
70754925bf6Swillf 
70854925bf6Swillf 	/* get the type of the content */
70954925bf6Swillf 	subtype = (int) curr[0];
71054925bf6Swillf 	/* forward by 1 byte*/
71154925bf6Swillf 	curr += 1;
71254925bf6Swillf 
71354925bf6Swillf 	if (subtype == tl_type) {
71454925bf6Swillf 	    switch (subtype) {
71554925bf6Swillf 
71654925bf6Swillf 	    case KDB_TL_PRINCCOUNT:
71754925bf6Swillf 	    case KDB_TL_PRINCTYPE:
71854925bf6Swillf 	    case KDB_TL_MASK:
71954925bf6Swillf 		/* get the length of the content */
72054925bf6Swillf 		UNSTORE16_INT(curr, sublen);
72154925bf6Swillf 		/* forward by 2 bytes */
72254925bf6Swillf 		curr += 2;
72354925bf6Swillf 		/* get the actual content */
72454925bf6Swillf 		if (sublen == 2) {
72554925bf6Swillf 		    /* intptr = malloc(sublen);	  */
72654925bf6Swillf 		    intptr = malloc(sizeof(krb5_int32));
72754925bf6Swillf 		    if (intptr == NULL)
72854925bf6Swillf 			return ENOMEM;
72954925bf6Swillf 		    memset(intptr, 0, sublen);
73054925bf6Swillf 		    UNSTORE16_INT(curr, (*intptr));
73154925bf6Swillf 		    *data = intptr;
73254925bf6Swillf 		} else {
73354925bf6Swillf 		    longptr = malloc(sublen);
73454925bf6Swillf 		    if (longptr == NULL)
73554925bf6Swillf 			return ENOMEM;
73654925bf6Swillf 		    memset(longptr, 0, sublen);
73754925bf6Swillf 		    UNSTORE32_INT(curr, (*longptr));
73854925bf6Swillf 		    *data = longptr;
73954925bf6Swillf 		}
74054925bf6Swillf 		curr += sublen;
74154925bf6Swillf 		st = 0;
74254925bf6Swillf 		return st;
74354925bf6Swillf 		/*LINTED*/
74454925bf6Swillf 		break;
74554925bf6Swillf 
74654925bf6Swillf 	    case KDB_TL_CONTAINERDN:
74754925bf6Swillf 	    case KDB_TL_USERDN:
74854925bf6Swillf 		/* get the length of the content */
74954925bf6Swillf 		UNSTORE16_INT(curr, sublen);
75054925bf6Swillf 		/* forward by 2 bytes */
75154925bf6Swillf 		curr += 2;
75254925bf6Swillf 		DN = malloc (sublen + 1);
75354925bf6Swillf 		if (DN == NULL)
75454925bf6Swillf 		    return ENOMEM;
75554925bf6Swillf 		memcpy(DN, curr, sublen);
75654925bf6Swillf 		DN[sublen] = 0;
75754925bf6Swillf 		*data = DN;
75854925bf6Swillf 		curr += sublen;
75954925bf6Swillf 		st = 0;
76054925bf6Swillf 		return st;
76154925bf6Swillf 		/*LINTED*/
76254925bf6Swillf 		break;
76354925bf6Swillf 
76454925bf6Swillf 	    case KDB_TL_LINKDN:
76554925bf6Swillf 		if (DNarr == NULL) {
76654925bf6Swillf 		    DNarr = calloc(limit, sizeof(char *));
76754925bf6Swillf 		    if (DNarr == NULL)
76854925bf6Swillf 			return ENOMEM;
76954925bf6Swillf 		}
77054925bf6Swillf 		if (i == limit-1) {
77154925bf6Swillf 		    limit *= 2;
77254925bf6Swillf 		    DNarr = realloc(DNarr, sizeof(char *) * (limit));
77354925bf6Swillf 		    if (DNarr == NULL)
77454925bf6Swillf 			return ENOMEM;
77554925bf6Swillf 		}
77654925bf6Swillf 
77754925bf6Swillf 		/* get the length of the content */
77854925bf6Swillf 		UNSTORE16_INT(curr, sublen);
77954925bf6Swillf 		/* forward by 2 bytes */
78054925bf6Swillf 		curr += 2;
78154925bf6Swillf 		DNarr[i] = malloc (sublen + 1);
78254925bf6Swillf 		if (DNarr[i] == NULL) {
78354925bf6Swillf 		    int j=0;
78454925bf6Swillf 		    for (; j<i; j++)
78554925bf6Swillf 			free(DNarr[j]);
78654925bf6Swillf 		    free(DNarr);
78754925bf6Swillf 		    return ENOMEM;
78854925bf6Swillf 		}
78954925bf6Swillf 		memcpy(DNarr[i], curr, sublen);
79054925bf6Swillf 		DNarr[i][sublen] = 0;
79154925bf6Swillf 		++i;
79254925bf6Swillf 		curr += sublen;
79354925bf6Swillf 		*data = DNarr;
79454925bf6Swillf 		st=0;
79554925bf6Swillf 		break;
79654925bf6Swillf 	    }
79754925bf6Swillf 	} else {
79854925bf6Swillf 	    /* move to the current content block */
79954925bf6Swillf 	    UNSTORE16_INT(curr, sublen);
80054925bf6Swillf 	    curr += 2 + sublen;
80154925bf6Swillf 	}
80254925bf6Swillf     }
80354925bf6Swillf     return st;
80454925bf6Swillf }
80554925bf6Swillf 
80654925bf6Swillf /*
80754925bf6Swillf  * wrapper routines for decode_tl_data
80854925bf6Swillf  */
80954925bf6Swillf static krb5_error_code
krb5_get_int_from_tl_data(context,entries,type,intval)81054925bf6Swillf krb5_get_int_from_tl_data(context, entries, type, intval)
81154925bf6Swillf     krb5_context                context;
81254925bf6Swillf     krb5_db_entry               *entries;
81354925bf6Swillf     int                         type;
81454925bf6Swillf     int                         *intval;
81554925bf6Swillf {
81654925bf6Swillf     krb5_error_code             st=0;
81754925bf6Swillf     krb5_tl_data                tl_data;
81854925bf6Swillf     void                        *voidptr=NULL;
81954925bf6Swillf     int                         *intptr=NULL;
82054925bf6Swillf 
82154925bf6Swillf     tl_data.tl_data_type = KDB_TL_USER_INFO;
82254925bf6Swillf     if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
82354925bf6Swillf 	goto cleanup;
82454925bf6Swillf 
82554925bf6Swillf     if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
82654925bf6Swillf 	intptr = (int *) voidptr;
82754925bf6Swillf 	*intval = *intptr;
82854925bf6Swillf 	free(intptr);
82954925bf6Swillf     }
83054925bf6Swillf 
83154925bf6Swillf cleanup:
83254925bf6Swillf     return st;
83354925bf6Swillf }
83454925bf6Swillf 
83554925bf6Swillf /*
83654925bf6Swillf  * Get the mask representing the attributes set on the directory
83754925bf6Swillf  * object (user, policy ...).
83854925bf6Swillf  */
83954925bf6Swillf krb5_error_code
krb5_get_attributes_mask(context,entries,mask)84054925bf6Swillf krb5_get_attributes_mask(context, entries, mask)
84154925bf6Swillf     krb5_context                context;
84254925bf6Swillf     krb5_db_entry               *entries;
84354925bf6Swillf     unsigned int                *mask;
84454925bf6Swillf {
84554925bf6Swillf     return krb5_get_int_from_tl_data(context, entries, KDB_TL_MASK,
84654925bf6Swillf 	(int *)mask);
84754925bf6Swillf }
84854925bf6Swillf 
84954925bf6Swillf krb5_error_code
krb5_get_princ_type(context,entries,ptype)85054925bf6Swillf krb5_get_princ_type(context, entries, ptype)
85154925bf6Swillf     krb5_context                context;
85254925bf6Swillf     krb5_db_entry               *entries;
85354925bf6Swillf     int                         *ptype;
85454925bf6Swillf {
85554925bf6Swillf     return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCTYPE, ptype);
85654925bf6Swillf }
85754925bf6Swillf 
85854925bf6Swillf krb5_error_code
krb5_get_princ_count(context,entries,pcount)85954925bf6Swillf krb5_get_princ_count(context, entries, pcount)
86054925bf6Swillf     krb5_context                context;
86154925bf6Swillf     krb5_db_entry               *entries;
86254925bf6Swillf     int                         *pcount;
86354925bf6Swillf {
86454925bf6Swillf     return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCCOUNT, pcount);
86554925bf6Swillf }
86654925bf6Swillf 
86754925bf6Swillf krb5_error_code
krb5_get_linkdn(context,entries,link_dn)86854925bf6Swillf krb5_get_linkdn(context, entries, link_dn)
86954925bf6Swillf     krb5_context                context;
87054925bf6Swillf     krb5_db_entry               *entries;
87154925bf6Swillf     char                        ***link_dn;
87254925bf6Swillf {
87354925bf6Swillf     krb5_error_code             st=0;
87454925bf6Swillf     krb5_tl_data                tl_data;
87554925bf6Swillf     void                        *voidptr=NULL;
87654925bf6Swillf 
87754925bf6Swillf     *link_dn = NULL;
87854925bf6Swillf     tl_data.tl_data_type = KDB_TL_USER_INFO;
87954925bf6Swillf     if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
88054925bf6Swillf 	goto cleanup;
88154925bf6Swillf 
88254925bf6Swillf     if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &voidptr) == 0) {
88354925bf6Swillf 	*link_dn = (char **) voidptr;
88454925bf6Swillf     }
88554925bf6Swillf 
88654925bf6Swillf cleanup:
88754925bf6Swillf     return st;
88854925bf6Swillf }
88954925bf6Swillf 
89054925bf6Swillf static krb5_error_code
krb5_get_str_from_tl_data(context,entries,type,strval)89154925bf6Swillf krb5_get_str_from_tl_data(context, entries, type, strval)
89254925bf6Swillf     krb5_context                context;
89354925bf6Swillf     krb5_db_entry               *entries;
89454925bf6Swillf     int                         type;
89554925bf6Swillf     char                        **strval;
89654925bf6Swillf {
89754925bf6Swillf     krb5_error_code             st=0;
89854925bf6Swillf     krb5_tl_data                tl_data;
89954925bf6Swillf     void                        *voidptr=NULL;
90054925bf6Swillf 
90154925bf6Swillf     if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN) {
90254925bf6Swillf 	st = EINVAL;
90354925bf6Swillf 	goto cleanup;
90454925bf6Swillf     }
90554925bf6Swillf 
90654925bf6Swillf     tl_data.tl_data_type = KDB_TL_USER_INFO;
90754925bf6Swillf     if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
90854925bf6Swillf 	goto cleanup;
90954925bf6Swillf 
91054925bf6Swillf     if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
91154925bf6Swillf 	*strval = (char *) voidptr;
91254925bf6Swillf     }
91354925bf6Swillf 
91454925bf6Swillf cleanup:
91554925bf6Swillf     return st;
91654925bf6Swillf }
91754925bf6Swillf 
91854925bf6Swillf krb5_error_code
krb5_get_userdn(context,entries,userdn)91954925bf6Swillf krb5_get_userdn(context, entries, userdn)
92054925bf6Swillf     krb5_context                context;
92154925bf6Swillf     krb5_db_entry               *entries;
92254925bf6Swillf     char                        **userdn;
92354925bf6Swillf {
92454925bf6Swillf     *userdn = NULL;
92554925bf6Swillf     return krb5_get_str_from_tl_data(context, entries, KDB_TL_USERDN, userdn);
92654925bf6Swillf }
92754925bf6Swillf 
92854925bf6Swillf krb5_error_code
krb5_get_containerdn(context,entries,containerdn)92954925bf6Swillf krb5_get_containerdn(context, entries, containerdn)
93054925bf6Swillf     krb5_context                context;
93154925bf6Swillf     krb5_db_entry               *entries;
93254925bf6Swillf     char                        **containerdn;
93354925bf6Swillf {
93454925bf6Swillf     *containerdn = NULL;
93554925bf6Swillf     return krb5_get_str_from_tl_data(context, entries, KDB_TL_CONTAINERDN, containerdn);
93654925bf6Swillf }
93754925bf6Swillf 
93854925bf6Swillf /*
93954925bf6Swillf  * This function reads the attribute values (if the attribute is
94054925bf6Swillf  * non-null) from the dn.  The read attribute values is compared
94154925bf6Swillf  * aganist the attrvalues passed to the function and a bit mask is set
94254925bf6Swillf  * for all the matching attributes (attributes existing in both list).
94354925bf6Swillf  * The bit to be set is selected such that the index of the attribute
94454925bf6Swillf  * in the attrvalues parameter is the position of the bit.  For ex:
94554925bf6Swillf  * the first element in the attrvalues is present in both list shall
94654925bf6Swillf  * set the LSB of the bit mask.
94754925bf6Swillf  *
94854925bf6Swillf  * In case if either the attribute or the attrvalues parameter to the
94954925bf6Swillf  * function is NULL, then the existence of the object is considered
95054925bf6Swillf  * and appropriate status is returned back.
95154925bf6Swillf  */
95254925bf6Swillf 
95354925bf6Swillf krb5_error_code
checkattributevalue(ld,dn,attribute,attrvalues,mask)95454925bf6Swillf checkattributevalue (ld, dn, attribute, attrvalues, mask)
95554925bf6Swillf     LDAP                        *ld;
95654925bf6Swillf     char                        *dn;
95754925bf6Swillf     char                        *attribute;
95854925bf6Swillf     char                        **attrvalues;
95954925bf6Swillf     int                         *mask;
96054925bf6Swillf {
96154925bf6Swillf     int                         st=0, one=1;
96254925bf6Swillf     char                        **values=NULL, *attributes[2] = {NULL};
96354925bf6Swillf     LDAPMessage                 *result=NULL, *entry=NULL;
96454925bf6Swillf 
96554925bf6Swillf     if (strlen(dn) == 0) {
96654925bf6Swillf 	st = set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH);
96754925bf6Swillf 	return st;
96854925bf6Swillf     }
96954925bf6Swillf 
97054925bf6Swillf     attributes[0] = attribute;
97154925bf6Swillf 
97254925bf6Swillf     /* read the attribute values from the dn */
97354925bf6Swillf     if ((st = ldap_search_ext_s(ld,
97454925bf6Swillf 				dn,
97554925bf6Swillf 				LDAP_SCOPE_BASE,
97654925bf6Swillf 				0,
97754925bf6Swillf 				attributes,
97854925bf6Swillf 				0,
97954925bf6Swillf 				NULL,
98054925bf6Swillf 				NULL,
98154925bf6Swillf 				&timelimit,
98254925bf6Swillf 				LDAP_NO_LIMIT,
98354925bf6Swillf 				&result)) != LDAP_SUCCESS) {
98454925bf6Swillf 	st = set_ldap_error(0, st, OP_SEARCH);
98554925bf6Swillf 	return st;
98654925bf6Swillf     }
98754925bf6Swillf 
98854925bf6Swillf     /*
98954925bf6Swillf      * If the attribute/attrvalues is NULL, then check for the
99054925bf6Swillf      * existence of the object alone.
99154925bf6Swillf      */
99254925bf6Swillf     if (attribute == NULL || attrvalues == NULL)
99354925bf6Swillf 	goto cleanup;
99454925bf6Swillf 
99554925bf6Swillf     /* reset the bit mask */
99654925bf6Swillf     *mask = 0;
99754925bf6Swillf 
99854925bf6Swillf     if ((entry=ldap_first_entry(ld, result)) != NULL) {
99954925bf6Swillf 	/* read the attribute values */
100054925bf6Swillf 	if ((values=ldap_get_values(ld, entry, attribute)) != NULL) {
100154925bf6Swillf 	    int i,j;
100254925bf6Swillf 
100354925bf6Swillf 	    /*
100454925bf6Swillf 	     * Compare the read attribute values with the attrvalues
100554925bf6Swillf 	     * array and set the appropriate bit mask.
100654925bf6Swillf 	     */
100754925bf6Swillf 	    for (j=0; attrvalues[j]; ++j) {
100854925bf6Swillf 		for (i=0; values[i]; ++i) {
100954925bf6Swillf 		    if (strcasecmp(values[i], attrvalues[j]) == 0) {
101054925bf6Swillf 			*mask |= (one<<j);
101154925bf6Swillf 			break;
101254925bf6Swillf 		    }
101354925bf6Swillf 		}
101454925bf6Swillf 	    }
101554925bf6Swillf 	    ldap_value_free(values);
101654925bf6Swillf 	}
101754925bf6Swillf     }
101854925bf6Swillf 
101954925bf6Swillf cleanup:
102054925bf6Swillf     ldap_msgfree(result);
102154925bf6Swillf     return st;
102254925bf6Swillf }
102354925bf6Swillf 
102454925bf6Swillf 
102554925bf6Swillf /*
102654925bf6Swillf  * This function updates a single attribute with a single value of a
102754925bf6Swillf  * specified dn.  This function is mainly used to update
102854925bf6Swillf  * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
102954925bf6Swillf  * ADMIN, PASSWD servers are associated with some realms or vice
103054925bf6Swillf  * versa.
103154925bf6Swillf  */
103254925bf6Swillf 
103354925bf6Swillf krb5_error_code
updateAttribute(ld,dn,attribute,value)103454925bf6Swillf updateAttribute (ld, dn, attribute, value)
103554925bf6Swillf     LDAP                        *ld;
103654925bf6Swillf     char                        *dn;
103754925bf6Swillf     char                        *attribute;
103854925bf6Swillf     char                        *value;
103954925bf6Swillf {
104054925bf6Swillf     int                         st=0;
104154925bf6Swillf     LDAPMod                     modAttr, *mods[2]={NULL};
104254925bf6Swillf     char                        *values[2]={NULL};
104354925bf6Swillf 
104454925bf6Swillf     values[0] = value;
104554925bf6Swillf 
104654925bf6Swillf     /* data to update the {attr,attrval} combination */
104754925bf6Swillf     memset(&modAttr, 0, sizeof(modAttr));
104854925bf6Swillf     modAttr.mod_type = attribute;
104954925bf6Swillf     modAttr.mod_op = LDAP_MOD_ADD;
105054925bf6Swillf     modAttr.mod_values = values;
105154925bf6Swillf     mods[0] = &modAttr;
105254925bf6Swillf 
105354925bf6Swillf     /* ldap modify operation */
105454925bf6Swillf     st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
105554925bf6Swillf 
105654925bf6Swillf     /* if the {attr,attrval} combination is already present return a success
105754925bf6Swillf      * LDAP_ALREADY_EXISTS is for single-valued attribute
105854925bf6Swillf      * LDAP_TYPE_OR_VALUE_EXISTS is for multi-valued attribute
105954925bf6Swillf      */
106054925bf6Swillf     if (st == LDAP_ALREADY_EXISTS || st == LDAP_TYPE_OR_VALUE_EXISTS)
106154925bf6Swillf 	st = 0;
106254925bf6Swillf 
106354925bf6Swillf     if (st != 0) {
106454925bf6Swillf 	st = set_ldap_error (0, st, OP_MOD);
106554925bf6Swillf     }
106654925bf6Swillf 
106754925bf6Swillf     return st;
106854925bf6Swillf }
106954925bf6Swillf 
107054925bf6Swillf /*
107154925bf6Swillf  * This function deletes a single attribute with a single value of a
107254925bf6Swillf  * specified dn.  This function is mainly used to delete
107354925bf6Swillf  * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
107454925bf6Swillf  * ADMIN, PASSWD servers are disassociated with some realms or vice
107554925bf6Swillf  * versa.
107654925bf6Swillf  */
107754925bf6Swillf 
107854925bf6Swillf krb5_error_code
deleteAttribute(ld,dn,attribute,value)107954925bf6Swillf deleteAttribute (ld, dn, attribute, value)
108054925bf6Swillf     LDAP                        *ld;
108154925bf6Swillf     char                        *dn;
108254925bf6Swillf     char                        *attribute;
108354925bf6Swillf     char                        *value;
108454925bf6Swillf {
108554925bf6Swillf     krb5_error_code             st=0;
108654925bf6Swillf     LDAPMod                     modAttr, *mods[2]={NULL};
108754925bf6Swillf     char                        *values[2]={NULL};
108854925bf6Swillf 
108954925bf6Swillf     values[0] = value;
109054925bf6Swillf 
109154925bf6Swillf     /* data to delete the {attr,attrval} combination */
109254925bf6Swillf     memset(&modAttr, 0, sizeof(modAttr));
109354925bf6Swillf     modAttr.mod_type = attribute;
109454925bf6Swillf     modAttr.mod_op = LDAP_MOD_DELETE;
109554925bf6Swillf     modAttr.mod_values = values;
109654925bf6Swillf     mods[0] = &modAttr;
109754925bf6Swillf 
109854925bf6Swillf     /* ldap modify operation */
109954925bf6Swillf     st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
110054925bf6Swillf 
110154925bf6Swillf     /* if either the attribute or the attribute value is missing return a success */
110254925bf6Swillf     if (st == LDAP_NO_SUCH_ATTRIBUTE || st == LDAP_UNDEFINED_TYPE)
110354925bf6Swillf 	st = 0;
110454925bf6Swillf 
110554925bf6Swillf     if (st != 0) {
110654925bf6Swillf 	st = set_ldap_error (0, st, OP_MOD);
110754925bf6Swillf     }
110854925bf6Swillf 
110954925bf6Swillf     return st;
111054925bf6Swillf }
111154925bf6Swillf 
111254925bf6Swillf 
111354925bf6Swillf /*
111454925bf6Swillf  * This function takes in 2 string arrays, compares them to remove the
111554925bf6Swillf  * matching entries.  The first array is the original list and the
111654925bf6Swillf  * second array is the modified list.  Removing the matching entries
111754925bf6Swillf  * will result in a reduced array, where the left over first array
111854925bf6Swillf  * elements are the deleted entries and the left over second array
111954925bf6Swillf  * elements are the added entries.  These additions and deletions has
112054925bf6Swillf  * resulted in the modified second array.
112154925bf6Swillf  */
112254925bf6Swillf 
112354925bf6Swillf krb5_error_code
disjoint_members(src,dest)112454925bf6Swillf disjoint_members(src, dest)
112554925bf6Swillf     char                        **src;
112654925bf6Swillf     char                        **dest;
112754925bf6Swillf {
112854925bf6Swillf     int                         i=0, j=0, slen=0, dlen=0;
112954925bf6Swillf 
113054925bf6Swillf     /* validate the input parameters */
113154925bf6Swillf     if (src == NULL || dest == NULL)
113254925bf6Swillf 	return 0;
113354925bf6Swillf 
113454925bf6Swillf     /* compute the first array length */
113554925bf6Swillf     for (i=0;src[i]; ++i)
113654925bf6Swillf 	;
113754925bf6Swillf 
113854925bf6Swillf     /* return if the length is 0 */
113954925bf6Swillf     if (i==0)
114054925bf6Swillf 	return 0;
114154925bf6Swillf 
114254925bf6Swillf     /* index of the last element and also the length of the array */
114354925bf6Swillf     slen = i-1;
114454925bf6Swillf 
114554925bf6Swillf     /* compute the second array length */
114654925bf6Swillf     for (i=0;dest[i]; ++i)
114754925bf6Swillf 	;
114854925bf6Swillf 
114954925bf6Swillf     /* return if the length is 0 */
115054925bf6Swillf     if (i==0)
115154925bf6Swillf 	return 0;
115254925bf6Swillf 
115354925bf6Swillf     /* index of the last element and also the length of the array */
115454925bf6Swillf     dlen = i-1;
115554925bf6Swillf 
115654925bf6Swillf     /* check for the similar elements and delete them from both the arrays */
115754925bf6Swillf     for (i=0; src[i]; ++i) {
115854925bf6Swillf 
115954925bf6Swillf 	for (j=0; dest[j]; ++j) {
116054925bf6Swillf 
116154925bf6Swillf 	    /* if the element are same */
116254925bf6Swillf 	    if (strcasecmp(src[i], dest[j]) == 0) {
116354925bf6Swillf 		/*
116454925bf6Swillf 		 * If the matched element is in the middle, then copy
116554925bf6Swillf 		 * the last element to the matched index.
116654925bf6Swillf 		 */
116754925bf6Swillf 		if (i != slen) {
116854925bf6Swillf 		    free (src[i]);
116954925bf6Swillf 		    src[i] = src[slen];
117054925bf6Swillf 		    src[slen] = NULL;
117154925bf6Swillf 		} else {
117254925bf6Swillf 		    /*
117354925bf6Swillf 		     * If the matched element is the last, free it and
117454925bf6Swillf 		     * set it to NULL.
117554925bf6Swillf 		     */
117654925bf6Swillf 		    free (src[i]);
117754925bf6Swillf 		    src[i] = NULL;
117854925bf6Swillf 		}
117954925bf6Swillf 		/* reduce the array length by 1 */
118054925bf6Swillf 		slen -= 1;
118154925bf6Swillf 
118254925bf6Swillf 		/* repeat the same processing for the second array too */
118354925bf6Swillf 		if (j != dlen) {
118454925bf6Swillf 		    free(dest[j]);
118554925bf6Swillf 		    dest[j] = dest[dlen];
118654925bf6Swillf 		    dest[dlen] = NULL;
118754925bf6Swillf 		} else {
118854925bf6Swillf 		    free(dest[j]);
118954925bf6Swillf 		    dest[j] = NULL;
119054925bf6Swillf 		}
119154925bf6Swillf 		dlen -=1;
119254925bf6Swillf 
119354925bf6Swillf 		/*
119454925bf6Swillf 		 * The source array is reduced by 1, so reduce the
119554925bf6Swillf 		 * index variable used for source array by 1.  No need
119654925bf6Swillf 		 * to adjust the second array index variable as it is
119754925bf6Swillf 		 * reset while entering the inner loop.
119854925bf6Swillf 		 */
119954925bf6Swillf 		i -= 1;
120054925bf6Swillf 		break;
120154925bf6Swillf 	    }
120254925bf6Swillf 	}
120354925bf6Swillf     }
120454925bf6Swillf     return 0;
120554925bf6Swillf }
120654925bf6Swillf 
120754925bf6Swillf /*
120854925bf6Swillf  * This function replicates the contents of the src array for later
120954925bf6Swillf  * use. Mostly the contents of the src array is obtained from a
121054925bf6Swillf  * ldap_search operation and the contents are required for later use.
121154925bf6Swillf  */
121254925bf6Swillf 
121354925bf6Swillf krb5_error_code
copy_arrays(src,dest,count)121454925bf6Swillf copy_arrays(src, dest, count)
121554925bf6Swillf     char                        **src;
121654925bf6Swillf     char                        ***dest;
121754925bf6Swillf     int                         count;
121854925bf6Swillf {
121954925bf6Swillf     krb5_error_code             st=0;
122054925bf6Swillf     int                         i=0;
122154925bf6Swillf 
122254925bf6Swillf     /* validate the input parameters */
122354925bf6Swillf     if (src == NULL || dest == NULL)
122454925bf6Swillf 	return 0;
122554925bf6Swillf 
122654925bf6Swillf     /* allocate memory for the dest array */
122754925bf6Swillf     *dest = (char **) calloc((unsigned) count+1, sizeof(char *));
122854925bf6Swillf     if (*dest == NULL) {
122954925bf6Swillf 	st = ENOMEM;
123054925bf6Swillf 	goto cleanup;
123154925bf6Swillf     }
123254925bf6Swillf 
123354925bf6Swillf     /* copy the members from src to dest array. */
123454925bf6Swillf     for (i=0; i < count && src[i] != NULL; ++i) {
123554925bf6Swillf 	(*dest)[i] = strdup(src[i]);
123654925bf6Swillf 	if ((*dest)[i] == NULL) {
123754925bf6Swillf 	    st = ENOMEM;
123854925bf6Swillf 	    goto cleanup;
123954925bf6Swillf 	}
124054925bf6Swillf     }
124154925bf6Swillf 
124254925bf6Swillf cleanup:
124354925bf6Swillf     /* in case of error free up everything and return */
124454925bf6Swillf     if (st != 0) {
124554925bf6Swillf 	if (*dest != NULL) {
124654925bf6Swillf 	    for (i=0; (*dest)[i]; ++i) {
124754925bf6Swillf 		free ((*dest)[i]);
124854925bf6Swillf 		(*dest)[i] = NULL;
124954925bf6Swillf 	    }
125054925bf6Swillf 	    free (*dest);
125154925bf6Swillf 	    *dest = NULL;
125254925bf6Swillf 	}
125354925bf6Swillf     }
125454925bf6Swillf     return st;
125554925bf6Swillf }
125654925bf6Swillf 
125754925bf6Swillf static krb5_error_code
getepochtime(strtime,epochtime)125854925bf6Swillf getepochtime(strtime, epochtime)
125954925bf6Swillf     char              *strtime;
126054925bf6Swillf     krb5_timestamp    *epochtime;
126154925bf6Swillf {
126254925bf6Swillf     struct tm           tme;
126354925bf6Swillf 
126454925bf6Swillf     memset(&tme, 0, sizeof(tme));
126554925bf6Swillf     if (strptime(strtime, DATE_FORMAT, &tme) == NULL) {
126654925bf6Swillf 	*epochtime = 0;
126754925bf6Swillf 	return EINVAL;
126854925bf6Swillf     }
1269159d09a2SMark Phalan 
127054925bf6Swillf     *epochtime = krb5int_gmt_mktime(&tme);
1271159d09a2SMark Phalan 
127254925bf6Swillf     return 0;
127354925bf6Swillf }
127454925bf6Swillf 
127554925bf6Swillf /*
127654925bf6Swillf  * krb5_ldap_get_value() - get the integer value of the attribute
127754925bf6Swillf  * Returns, 0 if the attribute is present, 1 if the attribute is missing.
127854925bf6Swillf  * The retval is 0 if the attribute is missing.
127954925bf6Swillf  */
128054925bf6Swillf 
128154925bf6Swillf krb5_error_code
krb5_ldap_get_value(ld,ent,attribute,retval)128254925bf6Swillf krb5_ldap_get_value(ld, ent, attribute, retval)
128354925bf6Swillf     LDAP                        *ld;
128454925bf6Swillf     LDAPMessage                 *ent;
128554925bf6Swillf     char                        *attribute;
128654925bf6Swillf     int                         *retval;
128754925bf6Swillf {
128854925bf6Swillf     char                           **values=NULL;
128954925bf6Swillf 
129054925bf6Swillf     *retval = 0;
129154925bf6Swillf     values=ldap_get_values(ld, ent, attribute);
129254925bf6Swillf     if (values != NULL) {
129354925bf6Swillf 	if (values[0] != NULL)
129454925bf6Swillf 	    *retval = atoi(values[0]);
129554925bf6Swillf 	ldap_value_free(values);
129654925bf6Swillf 	return 0;
129754925bf6Swillf     }
129854925bf6Swillf     return 1;
129954925bf6Swillf }
130054925bf6Swillf 
130154925bf6Swillf /*
130254925bf6Swillf  * krb5_ldap_get_string() - Returns the first string of the
130354925bf6Swillf  * attribute.  Intended to
130454925bf6Swillf  *
130554925bf6Swillf  *
130654925bf6Swillf  */
130754925bf6Swillf krb5_error_code
krb5_ldap_get_string(ld,ent,attribute,retstr,attr_present)130854925bf6Swillf krb5_ldap_get_string(ld, ent, attribute, retstr, attr_present)
130954925bf6Swillf     LDAP                        *ld;
131054925bf6Swillf     LDAPMessage                 *ent;
131154925bf6Swillf     char                        *attribute;
131254925bf6Swillf     char                        **retstr;
131354925bf6Swillf     krb5_boolean                *attr_present;
131454925bf6Swillf {
131554925bf6Swillf     char                           **values=NULL;
131654925bf6Swillf     krb5_error_code                st=0;
131754925bf6Swillf 
131854925bf6Swillf     *retstr = NULL;
131954925bf6Swillf     if (attr_present != NULL)
132054925bf6Swillf 	*attr_present = FALSE;
132154925bf6Swillf 
132254925bf6Swillf     values=ldap_get_values(ld, ent, attribute);
132354925bf6Swillf     if (values != NULL) {
132454925bf6Swillf 	if (values[0] != NULL) {
132554925bf6Swillf 	    if (attr_present!= NULL)
132654925bf6Swillf 		*attr_present = TRUE;
132754925bf6Swillf 	    *retstr = strdup(values[0]);
132854925bf6Swillf 	    if (*retstr == NULL)
132954925bf6Swillf 		st = ENOMEM;
133054925bf6Swillf 	}
133154925bf6Swillf 	ldap_value_free(values);
133254925bf6Swillf     }
133354925bf6Swillf     return st;
133454925bf6Swillf }
133554925bf6Swillf 
133654925bf6Swillf /*
133754925bf6Swillf  * krb5_ldap_get_strings() - Returns all the values
133854925bf6Swillf  * of the attribute.
133954925bf6Swillf  */
134054925bf6Swillf krb5_error_code
krb5_ldap_get_strings(ld,ent,attribute,retarr,attr_present)134154925bf6Swillf krb5_ldap_get_strings(ld, ent, attribute, retarr, attr_present)
134254925bf6Swillf     LDAP                        *ld;
134354925bf6Swillf     LDAPMessage                 *ent;
134454925bf6Swillf     char                        *attribute;
134554925bf6Swillf     char                        ***retarr;
134654925bf6Swillf     krb5_boolean                *attr_present;
134754925bf6Swillf {
134854925bf6Swillf     char                        **values=NULL;
134954925bf6Swillf     krb5_error_code             st=0;
135054925bf6Swillf     unsigned int                i=0, count=0;
135154925bf6Swillf 
135254925bf6Swillf     *retarr = NULL;
135354925bf6Swillf     if (attr_present != NULL)
135454925bf6Swillf 	*attr_present = FALSE;
135554925bf6Swillf 
135654925bf6Swillf     values=ldap_get_values(ld, ent, attribute);
135754925bf6Swillf     if (values != NULL) {
135854925bf6Swillf 	if (attr_present != NULL)
135954925bf6Swillf 	    *attr_present = TRUE;
136054925bf6Swillf 
136154925bf6Swillf 	count = ldap_count_values(values);
136254925bf6Swillf 	*retarr  = (char **) calloc(count+1, sizeof(char *));
136354925bf6Swillf 	if (*retarr == NULL) {
136454925bf6Swillf 	    st = ENOMEM;
136554925bf6Swillf 	    return st;
136654925bf6Swillf 	}
136754925bf6Swillf 	for (i=0; i< count; ++i) {
136854925bf6Swillf 	    (*retarr)[i] = strdup(values[i]);
136954925bf6Swillf 	    if ((*retarr)[i] == NULL) {
137054925bf6Swillf 		st = ENOMEM;
137154925bf6Swillf 		goto cleanup;
137254925bf6Swillf 	    }
137354925bf6Swillf 	}
137454925bf6Swillf 	ldap_value_free(values);
137554925bf6Swillf     }
137654925bf6Swillf 
137754925bf6Swillf cleanup:
137854925bf6Swillf     if (st != 0) {
137954925bf6Swillf 	if (*retarr != NULL) {
138054925bf6Swillf 	    for (i=0; i< count; ++i)
138154925bf6Swillf 		if ((*retarr)[i] != NULL)
138254925bf6Swillf 		    free ((*retarr)[i]);
138354925bf6Swillf 	    free (*retarr);
138454925bf6Swillf 	}
138554925bf6Swillf     }
138654925bf6Swillf     return st;
138754925bf6Swillf }
138854925bf6Swillf 
138954925bf6Swillf krb5_error_code
krb5_ldap_get_time(ld,ent,attribute,rettime,attr_present)139054925bf6Swillf krb5_ldap_get_time(ld, ent, attribute, rettime, attr_present)
139154925bf6Swillf     LDAP                        *ld;
139254925bf6Swillf     LDAPMessage                 *ent;
139354925bf6Swillf     char                        *attribute;
139454925bf6Swillf     krb5_timestamp              *rettime;
139554925bf6Swillf     krb5_boolean                *attr_present;
139654925bf6Swillf {
139754925bf6Swillf     char                         **values=NULL;
139854925bf6Swillf     krb5_error_code              st=0;
139954925bf6Swillf 
140054925bf6Swillf     *rettime = 0;
140154925bf6Swillf     *attr_present = FALSE;
140254925bf6Swillf 
140354925bf6Swillf     values=ldap_get_values(ld, ent, attribute);
140454925bf6Swillf     if (values != NULL) {
140554925bf6Swillf 	if (values[0] != NULL) {
140654925bf6Swillf 	    *attr_present = TRUE;
140754925bf6Swillf 	    st = getepochtime(values[0], rettime);
140854925bf6Swillf 	}
140954925bf6Swillf 	ldap_value_free(values);
141054925bf6Swillf     }
141154925bf6Swillf     return st;
141254925bf6Swillf }
141354925bf6Swillf 
141454925bf6Swillf /*
141554925bf6Swillf  * Function to allocate, set the values of LDAPMod structure. The
141654925bf6Swillf  * LDAPMod structure is then added to the array at the ind
141754925bf6Swillf  */
141854925bf6Swillf 
141954925bf6Swillf krb5_error_code
krb5_add_member(mods,count)142054925bf6Swillf krb5_add_member(mods, count)
142154925bf6Swillf     LDAPMod          ***mods;
142254925bf6Swillf     int              *count;
142354925bf6Swillf {
142454925bf6Swillf     int i=0;
142554925bf6Swillf     LDAPMod **lmods=NULL;
142654925bf6Swillf 
142754925bf6Swillf     if ((*mods) != NULL) {
142854925bf6Swillf 	for (;(*mods)[i] != NULL; ++i)
142954925bf6Swillf 	    ;
143054925bf6Swillf     }
143154925bf6Swillf     lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *));
143254925bf6Swillf     if (lmods == NULL)
143354925bf6Swillf 	return ENOMEM;
143454925bf6Swillf 
143554925bf6Swillf     *mods = lmods;
143654925bf6Swillf     (*mods)[i+1] = NULL;
143754925bf6Swillf     (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod));
143854925bf6Swillf     if ((*mods)[i] == NULL) {
143954925bf6Swillf 	free(lmods);
144054925bf6Swillf 	*mods = NULL;
144154925bf6Swillf 	return ENOMEM;
144254925bf6Swillf     }
144354925bf6Swillf     *count = i;
144454925bf6Swillf     return 0;
144554925bf6Swillf }
144654925bf6Swillf 
144754925bf6Swillf krb5_error_code
krb5_add_str_mem_ldap_mod(mods,attribute,op,values)144854925bf6Swillf krb5_add_str_mem_ldap_mod(mods, attribute, op, values)
144954925bf6Swillf     LDAPMod  ***mods;
145054925bf6Swillf     char     *attribute;
145154925bf6Swillf     int      op;
145254925bf6Swillf     char     **values;
145354925bf6Swillf 
145454925bf6Swillf {
145554925bf6Swillf     int i=0, j=0;
145654925bf6Swillf     krb5_error_code   st=0;
145754925bf6Swillf 
145854925bf6Swillf     if ((st=krb5_add_member(mods, &i)) != 0)
145954925bf6Swillf 	return st;
146054925bf6Swillf 
146154925bf6Swillf     (*mods)[i]->mod_type = strdup(attribute);
146254925bf6Swillf     if ((*mods)[i]->mod_type == NULL)
146354925bf6Swillf 	return ENOMEM;
146454925bf6Swillf     (*mods)[i]->mod_op = op;
146554925bf6Swillf 
146654925bf6Swillf     (*mods)[i]->mod_values = NULL;
146754925bf6Swillf 
146854925bf6Swillf     if (values != NULL) {
146954925bf6Swillf 	for (j=0; values[j] != NULL; ++j)
147054925bf6Swillf 	    ;
147154925bf6Swillf 	(*mods)[i]->mod_values = malloc (sizeof(char *) * (j+1));
147254925bf6Swillf 	if ((*mods)[i]->mod_values == NULL) {
147354925bf6Swillf 	    free((*mods)[i]->mod_type);
147454925bf6Swillf 	    (*mods)[i]->mod_type = NULL;
147554925bf6Swillf 	    return ENOMEM;
147654925bf6Swillf 	}
147754925bf6Swillf 
147854925bf6Swillf 	for (j=0; values[j] != NULL; ++j) {
147954925bf6Swillf 	    (*mods)[i]->mod_values[j] = strdup(values[j]);
148054925bf6Swillf 	    if ((*mods)[i]->mod_values[j] == NULL){
148154925bf6Swillf 		int k=0;
148254925bf6Swillf 		for (; k<j; k++) {
148354925bf6Swillf 		    free((*mods)[i]->mod_values[k]);
148454925bf6Swillf 		    (*mods)[i]->mod_values[k] = NULL;
148554925bf6Swillf 		}
148654925bf6Swillf 		return ENOMEM;
148754925bf6Swillf 	    }
148854925bf6Swillf 	}
148954925bf6Swillf 	(*mods)[i]->mod_values[j] = NULL;
149054925bf6Swillf     }
149154925bf6Swillf     return 0;
149254925bf6Swillf }
149354925bf6Swillf 
149454925bf6Swillf krb5_error_code
krb5_add_ber_mem_ldap_mod(mods,attribute,op,ber_values)149554925bf6Swillf krb5_add_ber_mem_ldap_mod(mods, attribute, op, ber_values)
149654925bf6Swillf     LDAPMod  ***mods;
149754925bf6Swillf     char     *attribute;
149854925bf6Swillf     int      op;
149954925bf6Swillf     struct berval **ber_values;
150054925bf6Swillf 
150154925bf6Swillf {
150254925bf6Swillf     int i=0, j=0;
150354925bf6Swillf     krb5_error_code   st=0;
150454925bf6Swillf 
150554925bf6Swillf     if ((st=krb5_add_member(mods, &i)) != 0)
150654925bf6Swillf 	return st;
150754925bf6Swillf 
150854925bf6Swillf     (*mods)[i]->mod_type = strdup(attribute);
150954925bf6Swillf     if ((*mods)[i]->mod_type == NULL)
151054925bf6Swillf 	return ENOMEM;
151154925bf6Swillf     (*mods)[i]->mod_op = op;
151254925bf6Swillf 
151354925bf6Swillf     for (j=0; ber_values[j] != NULL; ++j)
151454925bf6Swillf 	;
151554925bf6Swillf     (*mods)[i]->mod_bvalues = malloc (sizeof(struct berval *) * (j+1));
151654925bf6Swillf     if ((*mods)[i]->mod_bvalues == NULL)
151754925bf6Swillf 	return ENOMEM;
151854925bf6Swillf 
151954925bf6Swillf     for (j=0; ber_values[j] != NULL; ++j) {
152054925bf6Swillf 	(*mods)[i]->mod_bvalues[j] = calloc(1, sizeof(struct berval));
152154925bf6Swillf 	if ((*mods)[i]->mod_bvalues[j] == NULL)
152254925bf6Swillf 	    return ENOMEM;
152354925bf6Swillf 
152454925bf6Swillf 	(*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len;
152554925bf6Swillf 	(*mods)[i]->mod_bvalues[j]->bv_val = malloc((*mods)[i]->mod_bvalues[j]->bv_len);
152654925bf6Swillf 	if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL)
152754925bf6Swillf 	    return ENOMEM;
152854925bf6Swillf 
152954925bf6Swillf 	memcpy((*mods)[i]->mod_bvalues[j]->bv_val, ber_values[j]->bv_val,
153054925bf6Swillf 	       ber_values[j]->bv_len);
153154925bf6Swillf     }
153254925bf6Swillf     (*mods)[i]->mod_bvalues[j] = NULL;
153354925bf6Swillf     return 0;
153454925bf6Swillf }
153554925bf6Swillf 
153654925bf6Swillf static inline char *
format_d(int val)153754925bf6Swillf format_d (int val)
153854925bf6Swillf {
153954925bf6Swillf     char tmpbuf[2+3*sizeof(val)];
154054925bf6Swillf     sprintf(tmpbuf, "%d", val);
154154925bf6Swillf     return strdup(tmpbuf);
154254925bf6Swillf }
154354925bf6Swillf 
154454925bf6Swillf krb5_error_code
krb5_add_int_arr_mem_ldap_mod(mods,attribute,op,value)154554925bf6Swillf krb5_add_int_arr_mem_ldap_mod(mods, attribute, op, value)
154654925bf6Swillf     LDAPMod  ***mods;
154754925bf6Swillf     char     *attribute;
154854925bf6Swillf     int      op;
154954925bf6Swillf     int      *value;
155054925bf6Swillf 
155154925bf6Swillf {
155254925bf6Swillf     int i=0, j=0;
155354925bf6Swillf     krb5_error_code   st=0;
155454925bf6Swillf 
155554925bf6Swillf     if ((st=krb5_add_member(mods, &i)) != 0)
155654925bf6Swillf 	return st;
155754925bf6Swillf 
155854925bf6Swillf     (*mods)[i]->mod_type = strdup(attribute);
155954925bf6Swillf     if ((*mods)[i]->mod_type == NULL)
156054925bf6Swillf 	return ENOMEM;
156154925bf6Swillf     (*mods)[i]->mod_op = op;
156254925bf6Swillf 
156354925bf6Swillf     for (j=0; value[j] != -1; ++j)
156454925bf6Swillf 	;
156554925bf6Swillf 
156654925bf6Swillf     (*mods)[i]->mod_values = malloc(sizeof(char *) * (j+1));
156754925bf6Swillf 
156854925bf6Swillf     for (j=0; value[j] != -1; ++j) {
156954925bf6Swillf 	if (((*mods)[i]->mod_values[j] = format_d(value[j])) == NULL)
157054925bf6Swillf 	    return ENOMEM;
157154925bf6Swillf     }
157254925bf6Swillf     (*mods)[i]->mod_values[j] = NULL;
157354925bf6Swillf     return 0;
157454925bf6Swillf }
157554925bf6Swillf 
157654925bf6Swillf krb5_error_code
krb5_add_int_mem_ldap_mod(mods,attribute,op,value)157754925bf6Swillf krb5_add_int_mem_ldap_mod(mods, attribute, op, value)
157854925bf6Swillf     LDAPMod  ***mods;
157954925bf6Swillf     char     *attribute;
158054925bf6Swillf     int      op;
158154925bf6Swillf     int      value;
158254925bf6Swillf 
158354925bf6Swillf {
158454925bf6Swillf     int i=0;
158554925bf6Swillf     krb5_error_code      st=0;
158654925bf6Swillf 
158754925bf6Swillf     if ((st=krb5_add_member(mods, &i)) != 0)
158854925bf6Swillf 	return st;
158954925bf6Swillf 
159054925bf6Swillf     (*mods)[i]->mod_type = strdup(attribute);
159154925bf6Swillf     if ((*mods)[i]->mod_type == NULL)
159254925bf6Swillf 	return ENOMEM;
159354925bf6Swillf 
159454925bf6Swillf     (*mods)[i]->mod_op = op;
159554925bf6Swillf     (*mods)[i]->mod_values = calloc (2, sizeof(char *));
159654925bf6Swillf     if (((*mods)[i]->mod_values[0] = format_d(value)) == NULL)
159754925bf6Swillf 	return ENOMEM;
159854925bf6Swillf     return 0;
159954925bf6Swillf }
160054925bf6Swillf 
160154925bf6Swillf /*ARGSUSED*/
160254925bf6Swillf krb5_error_code
krb5_ldap_set_option(krb5_context kcontext,int option,void * value)160354925bf6Swillf krb5_ldap_set_option(krb5_context kcontext, int option, void *value)
160454925bf6Swillf {
160554925bf6Swillf     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
160654925bf6Swillf     krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
160754925bf6Swillf     return status;
160854925bf6Swillf }
160954925bf6Swillf 
161054925bf6Swillf /*ARGSUSED*/
161154925bf6Swillf krb5_error_code
krb5_ldap_lock(krb5_context kcontext,int mode)161254925bf6Swillf krb5_ldap_lock(krb5_context kcontext, int mode)
161354925bf6Swillf {
161454925bf6Swillf     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
161554925bf6Swillf     krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
161654925bf6Swillf     return status;
161754925bf6Swillf }
161854925bf6Swillf 
161954925bf6Swillf krb5_error_code
krb5_ldap_unlock(krb5_context kcontext)162054925bf6Swillf krb5_ldap_unlock(krb5_context kcontext)
162154925bf6Swillf {
162254925bf6Swillf     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
162354925bf6Swillf     krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
162454925bf6Swillf     return status;
162554925bf6Swillf }
162654925bf6Swillf 
162754925bf6Swillf /*ARGSUSED*/
162854925bf6Swillf krb5_error_code
krb5_ldap_supported_realms(krb5_context kcontext,char ** realms)162954925bf6Swillf krb5_ldap_supported_realms(krb5_context kcontext, char **realms)
163054925bf6Swillf {
163154925bf6Swillf     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
163254925bf6Swillf     krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
163354925bf6Swillf     return status;
163454925bf6Swillf }
163554925bf6Swillf 
163654925bf6Swillf /*ARGSUSED*/
163754925bf6Swillf krb5_error_code
krb5_ldap_free_supported_realms(krb5_context kcontext,char ** realms)163854925bf6Swillf krb5_ldap_free_supported_realms(krb5_context kcontext, char **realms)
163954925bf6Swillf {
164054925bf6Swillf     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
164154925bf6Swillf     krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
164254925bf6Swillf     return status;
164354925bf6Swillf }
164454925bf6Swillf 
164554925bf6Swillf const char *
krb5_ldap_errcode_2_string(krb5_context kcontext,long err_code)164654925bf6Swillf krb5_ldap_errcode_2_string(krb5_context kcontext, long err_code)
164754925bf6Swillf {
164854925bf6Swillf     return krb5_get_error_message(kcontext, err_code);
164954925bf6Swillf }
165054925bf6Swillf 
165154925bf6Swillf void
krb5_ldap_release_errcode_string(krb5_context kcontext,const char * msg)165254925bf6Swillf krb5_ldap_release_errcode_string(krb5_context kcontext, const char *msg)
165354925bf6Swillf {
165454925bf6Swillf     krb5_free_error_message(kcontext, msg);
165554925bf6Swillf }
165654925bf6Swillf 
165754925bf6Swillf 
165854925bf6Swillf /*
165954925bf6Swillf  * Get the number of times an object has been referred to in a realm. this is
166054925bf6Swillf  * needed to find out if deleting the attribute will cause dangling links.
166154925bf6Swillf  *
166254925bf6Swillf  * An LDAP handle may be optionally specified to prevent race condition - there
166354925bf6Swillf  * are a limited number of LDAP handles.
166454925bf6Swillf  */
166554925bf6Swillf krb5_error_code
krb5_ldap_get_reference_count(krb5_context context,char * dn,char * refattr,int * count,LDAP * ld)166654925bf6Swillf krb5_ldap_get_reference_count (krb5_context context, char *dn, char *refattr,
166754925bf6Swillf 			       int *count, LDAP *ld)
166854925bf6Swillf {
166954925bf6Swillf     int                         st = 0, tempst = 0, gothandle = 0;
167054925bf6Swillf     unsigned int		i, ntrees;
167154925bf6Swillf     char                        *refcntattr[2];
167254925bf6Swillf     char                        *filter = NULL;
167354925bf6Swillf     char                        **subtree = NULL, *ptr = NULL;
167454925bf6Swillf     kdb5_dal_handle             *dal_handle = NULL;
167554925bf6Swillf     krb5_ldap_context           *ldap_context = NULL;
167654925bf6Swillf     krb5_ldap_server_handle     *ldap_server_handle = NULL;
167754925bf6Swillf     LDAPMessage                 *result = NULL;
167854925bf6Swillf 
167954925bf6Swillf 
168054925bf6Swillf     if (dn == NULL || refattr == NULL) {
168154925bf6Swillf 	st = EINVAL;
168254925bf6Swillf 	goto cleanup;
168354925bf6Swillf     }
168454925bf6Swillf 
168554925bf6Swillf     SETUP_CONTEXT();
168654925bf6Swillf     if (ld == NULL) {
168754925bf6Swillf 	GET_HANDLE();
168854925bf6Swillf 	gothandle = 1;
168954925bf6Swillf     }
169054925bf6Swillf 
169154925bf6Swillf     refcntattr [0] = refattr;
169254925bf6Swillf     refcntattr [1] = NULL;
169354925bf6Swillf 
169454925bf6Swillf     ptr = ldap_filter_correct (dn);
169554925bf6Swillf     if (ptr == NULL) {
169654925bf6Swillf 	st = ENOMEM;
169754925bf6Swillf 	goto cleanup;
169854925bf6Swillf     }
169954925bf6Swillf 
170054925bf6Swillf     filter = (char *) malloc (strlen (refattr) + strlen (ptr) + 2);
170154925bf6Swillf     if (filter == NULL) {
170254925bf6Swillf 	st = ENOMEM;
170354925bf6Swillf 	goto cleanup;
170454925bf6Swillf     }
170554925bf6Swillf 
170654925bf6Swillf     /*LINTED*/
170754925bf6Swillf     sprintf (filter, "%s=%s", refattr, ptr);
170854925bf6Swillf 
170954925bf6Swillf     if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
171054925bf6Swillf 	goto cleanup;
171154925bf6Swillf 
171254925bf6Swillf     for (i = 0, *count = 0; i < ntrees; i++) {
171354925bf6Swillf 	int n;
171454925bf6Swillf 
171554925bf6Swillf 	LDAP_SEARCH(subtree[i],
171654925bf6Swillf 		    LDAP_SCOPE_SUBTREE,
171754925bf6Swillf 		    filter,
171854925bf6Swillf 		    refcntattr);
171954925bf6Swillf 	n = ldap_count_entries (ld, result);
172054925bf6Swillf 	if (n == -1) {
172154925bf6Swillf 	    int ret, errcode = 0;
172254925bf6Swillf 	    ret = ldap_parse_result (ld, result, &errcode, NULL, NULL, NULL, NULL, 0);
172354925bf6Swillf 	    if (ret != LDAP_SUCCESS)
172454925bf6Swillf 		errcode = ret;
172554925bf6Swillf 	    st = translate_ldap_error (errcode, OP_SEARCH);
172654925bf6Swillf 	    goto cleanup;
172754925bf6Swillf 	}
172854925bf6Swillf 
172954925bf6Swillf 	ldap_msgfree(result);
173054925bf6Swillf 	result = NULL;
173154925bf6Swillf 
173254925bf6Swillf 	*count += n;
173354925bf6Swillf     }
173454925bf6Swillf 
173554925bf6Swillf cleanup:
173654925bf6Swillf     if (filter != NULL)
173754925bf6Swillf 	free (filter);
173854925bf6Swillf 
173954925bf6Swillf     if (result != NULL)
174054925bf6Swillf 	ldap_msgfree (result);
174154925bf6Swillf 
174254925bf6Swillf     if (subtree != NULL) {
174354925bf6Swillf 	for (i = 0; i < ntrees; i++)
174454925bf6Swillf 	    free (subtree[i]);
174554925bf6Swillf 	free (subtree);
174654925bf6Swillf     }
174754925bf6Swillf 
174854925bf6Swillf     if (ptr != NULL)
174954925bf6Swillf 	free (ptr);
175054925bf6Swillf 
175154925bf6Swillf     if (gothandle == 1)
175254925bf6Swillf 	krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
175354925bf6Swillf 
175454925bf6Swillf     return st;
175554925bf6Swillf }
175654925bf6Swillf 
175754925bf6Swillf /*
175854925bf6Swillf  * For now, policy objects are expected to be directly under the realm
175954925bf6Swillf  * container.
176054925bf6Swillf  */
krb5_ldap_policydn_to_name(context,policy_dn,name)176154925bf6Swillf krb5_error_code krb5_ldap_policydn_to_name (context, policy_dn, name)
176254925bf6Swillf     krb5_context                context;
176354925bf6Swillf     char                        *policy_dn;
176454925bf6Swillf     char                        **name;
176554925bf6Swillf {
176654925bf6Swillf     int len1, len2;
176754925bf6Swillf     krb5_error_code             st = 0;
176854925bf6Swillf     kdb5_dal_handle             *dal_handle=NULL;
176954925bf6Swillf     krb5_ldap_context           *ldap_context=NULL;
177054925bf6Swillf 
177154925bf6Swillf     SETUP_CONTEXT();
177254925bf6Swillf 
177354925bf6Swillf     if (ldap_context->lrparams->realmdn == NULL) {
177454925bf6Swillf 	st = EINVAL;
177554925bf6Swillf 	goto cleanup;
177654925bf6Swillf     }
177754925bf6Swillf 
177854925bf6Swillf     len1 = strlen (ldap_context->lrparams->realmdn);
177954925bf6Swillf     len2 = strlen (policy_dn);
178054925bf6Swillf     if (len1 == 0 || len2 == 0 || len1 > len2) {
178154925bf6Swillf 	st = EINVAL;
178254925bf6Swillf 	goto cleanup;
178354925bf6Swillf     }
178454925bf6Swillf 
178554925bf6Swillf     if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) {
178654925bf6Swillf 	st = EINVAL;
178754925bf6Swillf 	goto cleanup;
178854925bf6Swillf     }
178954925bf6Swillf 
179054925bf6Swillf #if defined HAVE_LDAP_STR2DN
179154925bf6Swillf     {
179254925bf6Swillf 	char *rdn;
179354925bf6Swillf 	LDAPDN dn;
179454925bf6Swillf 	rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */
179554925bf6Swillf 
179654925bf6Swillf 	if (ldap_str2dn (rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC) != 0) {
179754925bf6Swillf 	    st = EINVAL;
179854925bf6Swillf 	    goto cleanup;
179954925bf6Swillf 	}
180054925bf6Swillf 	if (dn[0] == NULL || dn[1] != NULL)
180154925bf6Swillf 	    st = EINVAL;
180254925bf6Swillf 	else if (strcasecmp (dn[0][0]->la_attr.bv_val, "cn") != 0)
180354925bf6Swillf 	    st = EINVAL;
180454925bf6Swillf 	else {
180554925bf6Swillf 	    *name = strndup(dn[0][0]->la_value.bv_val, dn[0][0]->la_value.bv_len);
180654925bf6Swillf 	    if (*name == NULL)
180754925bf6Swillf 		st = EINVAL;
180854925bf6Swillf 	}
180954925bf6Swillf 
181054925bf6Swillf 	ldap_memfree (dn);
181154925bf6Swillf     }
181254925bf6Swillf #elif defined HAVE_LDAP_EXPLODE_DN
181354925bf6Swillf     {
181454925bf6Swillf 	char **parsed_dn;
181554925bf6Swillf 
181654925bf6Swillf 	/* 1 = return DN components without type prefix */
181754925bf6Swillf 	parsed_dn = ldap_explode_dn(policy_dn, 1);
181854925bf6Swillf 	if (parsed_dn == NULL) {
181954925bf6Swillf 	    st = EINVAL;
182054925bf6Swillf 	} else {
182154925bf6Swillf 	    *name = strdup(parsed_dn[0]);
182254925bf6Swillf 	    if (*name == NULL)
182354925bf6Swillf 		st = EINVAL;
182454925bf6Swillf 
182554925bf6Swillf 	    ldap_value_free(parsed_dn);
182654925bf6Swillf 	}
182754925bf6Swillf     }
182854925bf6Swillf #else
182954925bf6Swillf     st = EINVAL;
183054925bf6Swillf #endif
183154925bf6Swillf 
183254925bf6Swillf cleanup:
183354925bf6Swillf     return st;
183454925bf6Swillf }
183554925bf6Swillf 
krb5_ldap_name_to_policydn(context,name,policy_dn)183654925bf6Swillf krb5_error_code krb5_ldap_name_to_policydn (context, name, policy_dn)
183754925bf6Swillf     krb5_context                context;
183854925bf6Swillf     char                        *name;
183954925bf6Swillf     char                        **policy_dn;
184054925bf6Swillf {
184154925bf6Swillf     int                         len;
184254925bf6Swillf     char                        *ptr = NULL;
184354925bf6Swillf     krb5_error_code             st = 0;
184454925bf6Swillf     kdb5_dal_handle             *dal_handle=NULL;
184554925bf6Swillf     krb5_ldap_context           *ldap_context=NULL;
184654925bf6Swillf 
184754925bf6Swillf     *policy_dn = NULL;
184854925bf6Swillf 
184954925bf6Swillf     /* validate the input parameters */
185054925bf6Swillf     if (name == NULL) {
185154925bf6Swillf 	st = EINVAL;
185254925bf6Swillf 	goto cleanup;
185354925bf6Swillf     }
185454925bf6Swillf 
185554925bf6Swillf     /* Used for removing policy reference from an object */
185654925bf6Swillf     if (name[0] == '\0') {
185754925bf6Swillf 	if ((*policy_dn = strdup ("")) == NULL)
185854925bf6Swillf 	    st = ENOMEM;
185954925bf6Swillf 	goto cleanup;
186054925bf6Swillf     }
186154925bf6Swillf 
186254925bf6Swillf     SETUP_CONTEXT();
186354925bf6Swillf 
186454925bf6Swillf     if (ldap_context->lrparams->realmdn == NULL) {
186554925bf6Swillf 	st = EINVAL;
186654925bf6Swillf 	goto cleanup;
186754925bf6Swillf     }
186854925bf6Swillf     len = strlen (ldap_context->lrparams->realmdn);
186954925bf6Swillf 
187054925bf6Swillf     ptr = ldap_filter_correct (name);
187154925bf6Swillf     if (ptr == NULL) {
187254925bf6Swillf 	st = ENOMEM;
187354925bf6Swillf 	goto cleanup;
187454925bf6Swillf     }
187554925bf6Swillf     len += strlen (ptr);
187654925bf6Swillf 
187754925bf6Swillf     len += sizeof ("cn=") + 3;
187854925bf6Swillf 
187954925bf6Swillf     *policy_dn = (char *) malloc (len);
188054925bf6Swillf     if (*policy_dn == NULL) {
188154925bf6Swillf 	st = ENOMEM;
188254925bf6Swillf 	goto cleanup;
188354925bf6Swillf     }
188454925bf6Swillf 
188554925bf6Swillf     /*LINTED*/
188654925bf6Swillf     sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn);
188754925bf6Swillf 
188854925bf6Swillf cleanup:
188954925bf6Swillf     if (ptr != NULL)
189054925bf6Swillf 	free (ptr);
189154925bf6Swillf     return st;
189254925bf6Swillf }
189354925bf6Swillf 
189454925bf6Swillf /* remove overlapping and repeated subtree entries from the list of subtrees */
189554925bf6Swillf static krb5_error_code
remove_overlapping_subtrees(char ** listin,char ** listop,int * subtcount,int sscope)189654925bf6Swillf remove_overlapping_subtrees(char **listin, char **listop, int *subtcount, int sscope)
189754925bf6Swillf {
189854925bf6Swillf     int     slen=0, k=0, j=0, lendiff=0;
189954925bf6Swillf     int     count = *subtcount;
190054925bf6Swillf     char    **subtree = listop;
190154925bf6Swillf 
190254925bf6Swillf     slen = count-1;
190354925bf6Swillf     for (k=0; k<=slen && listin[k]!=NULL ; k++) {
190454925bf6Swillf 	for (j=k+1; j<=slen && listin[j]!=NULL ;j++) {
190554925bf6Swillf 	    lendiff = strlen(listin[k]) - strlen(listin[j]);
190654925bf6Swillf 	    if (sscope == 2) {
190754925bf6Swillf 		if ((lendiff > 0) && (strcasecmp((listin[k])+lendiff, listin[j])==0)) {
190854925bf6Swillf 		    if (k != slen) {
190954925bf6Swillf 			free(listin[k]);
191054925bf6Swillf 			listin[k] = listin[slen];
191154925bf6Swillf 			listin[slen] = NULL;
191254925bf6Swillf 		    } else {
191354925bf6Swillf 			free(listin[k]);
191454925bf6Swillf 			listin[k] = NULL;
191554925bf6Swillf 		    }
191654925bf6Swillf 		    slen-=1;
191754925bf6Swillf 		    k-=1;
191854925bf6Swillf 		    break;
191954925bf6Swillf 		} else if ((lendiff < 0) && (strcasecmp((listin[j])+abs(lendiff), listin[k])==0)) {
192054925bf6Swillf 		    if (j != slen) {
192154925bf6Swillf 			free(listin[j]);
192254925bf6Swillf 			listin[j] = listin[slen];
192354925bf6Swillf 			listin[slen]=NULL;
192454925bf6Swillf 		    } else {
192554925bf6Swillf 			free(listin[j]);
192654925bf6Swillf 			listin[j] = NULL;
192754925bf6Swillf 		    }
192854925bf6Swillf 		    slen-=1;
192954925bf6Swillf 		    j-=1;
193054925bf6Swillf 		}
193154925bf6Swillf 	    }
193254925bf6Swillf 	    if ((lendiff == 0) && (strcasecmp(listin[j], listin[k])==0)) {
193354925bf6Swillf 		if (j != slen) {
193454925bf6Swillf 		    free(listin[j]);
193554925bf6Swillf 		    listin[j] = listin[slen];
193654925bf6Swillf 		    listin[slen]=NULL;
193754925bf6Swillf 		} else {
193854925bf6Swillf 		    free(listin[j]);
193954925bf6Swillf 		    listin[j] = NULL;
194054925bf6Swillf 		}
194154925bf6Swillf 		slen -=1;
194254925bf6Swillf 		j-=1;
194354925bf6Swillf 	    }
194454925bf6Swillf 	}
194554925bf6Swillf     }
194654925bf6Swillf     *subtcount=slen+1;
194754925bf6Swillf     for (k=0; k<*subtcount && listin[k]!=NULL; k++) {
194854925bf6Swillf 	subtree[k] = strdup(listin[k]);
194954925bf6Swillf 	if (subtree[k] == NULL) {
195054925bf6Swillf 	    return ENOMEM;
195154925bf6Swillf 	}
195254925bf6Swillf     }
195354925bf6Swillf     return 0;
195454925bf6Swillf }
195554925bf6Swillf 
195654925bf6Swillf /*
195754925bf6Swillf  * Fill out a krb5_db_entry princ entry struct given a LDAP message containing
195854925bf6Swillf  * the results of a principal search of the directory.
195954925bf6Swillf  */
196054925bf6Swillf krb5_error_code
populate_krb5_db_entry(krb5_context context,krb5_ldap_context * ldap_context,LDAP * ld,LDAPMessage * ent,krb5_const_principal princ,krb5_db_entry * entry)196154925bf6Swillf populate_krb5_db_entry (krb5_context context,
196254925bf6Swillf 			krb5_ldap_context *ldap_context,
196354925bf6Swillf 			LDAP *ld,
196454925bf6Swillf 			LDAPMessage *ent,
196554925bf6Swillf 			krb5_const_principal princ,
196654925bf6Swillf 			krb5_db_entry *entry)
196754925bf6Swillf {
196854925bf6Swillf     krb5_error_code st = 0;
196954925bf6Swillf     unsigned int    mask = 0;
197054925bf6Swillf     krb5_boolean    attr_present = FALSE;
197154925bf6Swillf     char            **values = NULL, *policydn = NULL, *pwdpolicydn = NULL;
197254925bf6Swillf     char            *polname = NULL, *tktpolname = NULL;
197354925bf6Swillf     struct berval   **bvalues = NULL;
197454925bf6Swillf     krb5_tl_data    userinfo_tl_data = {0};
197554925bf6Swillf     /* Solaris Kerberos: added next line to fix memleak */
197654925bf6Swillf     krb5_tl_data    kadm_tl_data = {NULL};
197754925bf6Swillf     char            **link_references = NULL;
197854925bf6Swillf     char *DN = NULL;
197954925bf6Swillf 
198054925bf6Swillf     if (princ == NULL) {
198154925bf6Swillf 	st = EINVAL;
198254925bf6Swillf 	goto cleanup;
198354925bf6Swillf     } else {
198454925bf6Swillf 	if ((st=krb5_copy_principal(context, princ, &(entry->princ))) != 0)
198554925bf6Swillf 	    goto cleanup;
198654925bf6Swillf     }
198754925bf6Swillf     /* get the associated directory user information */
198854925bf6Swillf     if ((values = ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
198954925bf6Swillf 	int i, pcount=0, kerberos_principal_object_type=0;
199054925bf6Swillf 	char *user;
199154925bf6Swillf 
199254925bf6Swillf 	if ((st=krb5_unparse_name(context, princ, &user)) != 0)
199354925bf6Swillf 	    goto cleanup;
199454925bf6Swillf 
199554925bf6Swillf 	for (i=0; values[i] != NULL; ++i) {
199654925bf6Swillf 	    if (strcasecmp(values[i], user) == 0) {
199754925bf6Swillf 		pcount = ldap_count_values(values);
199854925bf6Swillf 		break;
199954925bf6Swillf 	    }
200054925bf6Swillf 	}
200154925bf6Swillf 	ldap_value_free(values);
200254925bf6Swillf 	free(user);
200354925bf6Swillf 
200454925bf6Swillf 	if ((DN = ldap_get_dn(ld, ent)) == NULL) {
200554925bf6Swillf 	    ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &st);
200654925bf6Swillf 	    st = set_ldap_error(context, st, 0);
200754925bf6Swillf 	    goto cleanup;
200854925bf6Swillf 	}
200954925bf6Swillf 
201054925bf6Swillf 	if ((values=ldap_get_values(ld, ent, "objectclass")) != NULL) {
201154925bf6Swillf 	    for (i=0; values[i] != NULL; ++i)
201254925bf6Swillf 		if (strcasecmp(values[i], "krbprincipal") == 0) {
201354925bf6Swillf 		    kerberos_principal_object_type = KDB_STANDALONE_PRINCIPAL_OBJECT;
201454925bf6Swillf 		    if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE,
201554925bf6Swillf 				&kerberos_principal_object_type)) != 0)
201654925bf6Swillf 			goto cleanup;
201754925bf6Swillf 		    break;
201854925bf6Swillf 		}
201954925bf6Swillf 	    ldap_value_free(values);
202054925bf6Swillf 	}
202154925bf6Swillf 
202254925bf6Swillf 	/* add principalcount, DN and principaltype user information to tl_data */
202354925bf6Swillf 	if (((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount)) != 0) ||
202454925bf6Swillf 	    ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0))
202554925bf6Swillf 	    goto cleanup;
202654925bf6Swillf     }
202754925bf6Swillf 
202854925bf6Swillf     /* read all the kerberos attributes */
202954925bf6Swillf 
203054925bf6Swillf     /* KRBLASTSUCCESSFULAUTH */
203154925bf6Swillf     if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth",
203254925bf6Swillf 		&(entry->last_success), &attr_present)) != 0)
203354925bf6Swillf 	goto cleanup;
203454925bf6Swillf     if (attr_present == TRUE)
203554925bf6Swillf 	mask |= KDB_LAST_SUCCESS_ATTR;
203654925bf6Swillf 
203754925bf6Swillf     /* KRBLASTFAILEDAUTH */
203854925bf6Swillf     if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth",
203954925bf6Swillf 		&(entry->last_failed), &attr_present)) != 0)
204054925bf6Swillf 	goto cleanup;
204154925bf6Swillf     if (attr_present == TRUE)
204254925bf6Swillf 	mask |= KDB_LAST_FAILED_ATTR;
204354925bf6Swillf 
204454925bf6Swillf     /* KRBLOGINFAILEDCOUNT */
204554925bf6Swillf     if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount",
204654925bf6Swillf 	    /* Solaris kerberos: need the cast */
204754925bf6Swillf 	    (int *)&(entry->fail_auth_count)) == 0)
204854925bf6Swillf 	mask |= KDB_FAIL_AUTH_COUNT_ATTR;
204954925bf6Swillf 
205054925bf6Swillf     /* KRBMAXTICKETLIFE */
205154925bf6Swillf     if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entry->max_life)) == 0)
205254925bf6Swillf 	mask |= KDB_MAX_LIFE_ATTR;
205354925bf6Swillf 
205454925bf6Swillf     /* KRBMAXRENEWABLEAGE */
205554925bf6Swillf     if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage",
205654925bf6Swillf 	    &(entry->max_renewable_life)) == 0)
205754925bf6Swillf 	mask |= KDB_MAX_RLIFE_ATTR;
205854925bf6Swillf 
205954925bf6Swillf     /* KRBTICKETFLAGS */
206054925bf6Swillf     if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entry->attributes)) == 0)
206154925bf6Swillf 	mask |= KDB_TKT_FLAGS_ATTR;
206254925bf6Swillf 
206354925bf6Swillf     /* PRINCIPAL EXPIRATION TIME */
206454925bf6Swillf     if ((st=krb5_ldap_get_time(ld, ent, "krbprincipalexpiration", &(entry->expiration),
206554925bf6Swillf 		&attr_present)) != 0)
206654925bf6Swillf 	goto cleanup;
206754925bf6Swillf     if (attr_present == TRUE)
206854925bf6Swillf 	mask |= KDB_PRINC_EXPIRE_TIME_ATTR;
206954925bf6Swillf 
207054925bf6Swillf     /* PASSWORD EXPIRATION TIME */
207154925bf6Swillf     if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entry->pw_expiration),
207254925bf6Swillf 		&attr_present)) != 0)
207354925bf6Swillf 	goto cleanup;
207454925bf6Swillf     if (attr_present == TRUE)
207554925bf6Swillf 	mask |= KDB_PWD_EXPIRE_TIME_ATTR;
207654925bf6Swillf 
207754925bf6Swillf     /* KRBPOLICYREFERENCE */
207854925bf6Swillf 
207954925bf6Swillf     if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn,
208054925bf6Swillf 		&attr_present)) != 0)
208154925bf6Swillf 	goto cleanup;
208254925bf6Swillf     if (attr_present == TRUE) {
208354925bf6Swillf 	mask |= KDB_POL_REF_ATTR;
208454925bf6Swillf 	/* Ensure that the policy is inside the realm container */
208554925bf6Swillf 	if ((st = krb5_ldap_policydn_to_name (context, policydn, &tktpolname)) != 0)
208654925bf6Swillf 	    goto cleanup;
208754925bf6Swillf     }
208854925bf6Swillf 
208954925bf6Swillf     /* KRBPWDPOLICYREFERENCE */
209054925bf6Swillf     if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn,
209154925bf6Swillf 		&attr_present)) != 0)
209254925bf6Swillf 	goto cleanup;
209354925bf6Swillf     if (attr_present == TRUE) {
209454925bf6Swillf 	/* Solaris Kerberos: changed this to fix memleak */
209554925bf6Swillf 	/* krb5_tl_data  kadm_tl_data; */
209654925bf6Swillf 
209754925bf6Swillf 	mask |= KDB_PWD_POL_REF_ATTR;
209854925bf6Swillf 
209954925bf6Swillf 	/* Ensure that the policy is inside the realm container */
210054925bf6Swillf 	if ((st = krb5_ldap_policydn_to_name (context, pwdpolicydn, &polname)) != 0)
210154925bf6Swillf 	    goto cleanup;
210254925bf6Swillf 
21032dd2efa5Swillf 	/* Solaris Kerberos: adding support for key history in LDAP KDB */
21042dd2efa5Swillf 	if ((st = krb5_update_tl_kadm_data(polname, &kadm_tl_data, entry->tl_data)) != 0) {
210554925bf6Swillf 	    goto cleanup;
210654925bf6Swillf 	}
210754925bf6Swillf 	krb5_dbe_update_tl_data(context, entry, &kadm_tl_data);
210854925bf6Swillf     }
210954925bf6Swillf 
211054925bf6Swillf     /* KRBSECRETKEY */
211154925bf6Swillf     if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != NULL) {
211254925bf6Swillf 	mask |= KDB_SECRET_KEY_ATTR;
211354925bf6Swillf 	if ((st=krb5_decode_krbsecretkey(context, entry, bvalues)) != 0)
211454925bf6Swillf 	    goto cleanup;
211554925bf6Swillf     }
211654925bf6Swillf 
211754925bf6Swillf     /* LAST PASSWORD CHANGE */
211854925bf6Swillf     {
211954925bf6Swillf 	krb5_timestamp lstpwdchng=0;
212054925bf6Swillf 	if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange",
212154925bf6Swillf 		    &lstpwdchng, &attr_present)) != 0)
212254925bf6Swillf 	    goto cleanup;
212354925bf6Swillf 	if (attr_present == TRUE) {
212454925bf6Swillf 	    if ((st=krb5_dbe_update_last_pwd_change(context, entry,
212554925bf6Swillf 			lstpwdchng)))
212654925bf6Swillf 		goto cleanup;
212754925bf6Swillf 	    mask |= KDB_LAST_PWD_CHANGE_ATTR;
212854925bf6Swillf 	}
212954925bf6Swillf     }
213054925bf6Swillf 
213154925bf6Swillf     /* KRBOBJECTREFERENCES */
213254925bf6Swillf     {
213354925bf6Swillf 	int i=0;
213454925bf6Swillf 
213554925bf6Swillf 	if ((st = krb5_ldap_get_strings(ld, ent, "krbobjectreferences",
213654925bf6Swillf 		    &link_references, &attr_present)) != 0)
213754925bf6Swillf 	    goto cleanup;
213854925bf6Swillf 	if (link_references != NULL) {
213954925bf6Swillf 	    for (i=0; link_references[i] != NULL; ++i) {
214054925bf6Swillf 		if ((st = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN,
214154925bf6Swillf 			    link_references[i])) != 0)
214254925bf6Swillf 		    goto cleanup;
214354925bf6Swillf 	    }
214454925bf6Swillf 	}
214554925bf6Swillf     }
214654925bf6Swillf 
214754925bf6Swillf     /* Set tl_data */
214854925bf6Swillf     {
214954925bf6Swillf 	int i;
215054925bf6Swillf 	struct berval **ber_tl_data = NULL;
215154925bf6Swillf 	krb5_tl_data *ptr = NULL;
215254925bf6Swillf 
215354925bf6Swillf 	if ((ber_tl_data = ldap_get_values_len (ld, ent, "krbExtraData")) != NULL) {
215454925bf6Swillf 	    for (i = 0; ber_tl_data[i] != NULL; i++) {
215554925bf6Swillf 		if ((st = berval2tl_data (ber_tl_data[i], &ptr)) != 0)
215654925bf6Swillf 		    break;
215754925bf6Swillf 		if ((st = krb5_dbe_update_tl_data(context, entry, ptr)) != 0)
215854925bf6Swillf 		    break;
215954925bf6Swillf 		/* Solaris kerberos: fix memory leak */
216054925bf6Swillf 		if (ptr) {
216154925bf6Swillf 		    if (ptr->tl_data_contents)
216254925bf6Swillf 			free(ptr->tl_data_contents);
216354925bf6Swillf 		    free(ptr);
216454925bf6Swillf 		    ptr = NULL;
216554925bf6Swillf 		}
216654925bf6Swillf 	    }
216754925bf6Swillf 	    ldap_value_free_len (ber_tl_data);
216854925bf6Swillf 	    if (st != 0)
216954925bf6Swillf 		goto cleanup;
217054925bf6Swillf 	    mask |= KDB_EXTRA_DATA_ATTR;
217154925bf6Swillf 	}
217254925bf6Swillf     }
217354925bf6Swillf 
217454925bf6Swillf     /* update the mask of attributes present on the directory object to the tl_data */
217554925bf6Swillf     if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask)) != 0)
217654925bf6Swillf 	goto cleanup;
217754925bf6Swillf     if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0)
217854925bf6Swillf 	goto cleanup;
217954925bf6Swillf 
218054925bf6Swillf #ifdef HAVE_EDIRECTORY
218154925bf6Swillf     {
218254925bf6Swillf 	krb5_timestamp              expiretime=0;
218354925bf6Swillf 	char                        *is_login_disabled=NULL;
218454925bf6Swillf 
218554925bf6Swillf 	/* LOGIN EXPIRATION TIME */
218654925bf6Swillf 	if ((st=krb5_ldap_get_time(ld, ent, "loginexpirationtime", &expiretime,
218754925bf6Swillf 		    &attr_present)) != 0)
218854925bf6Swillf 	    goto cleanup;
218954925bf6Swillf 
219054925bf6Swillf 	if (attr_present == TRUE) {
219154925bf6Swillf 	    if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) {
219254925bf6Swillf 		if (expiretime < entry->expiration)
219354925bf6Swillf 		    entry->expiration = expiretime;
219454925bf6Swillf 	    } else {
219554925bf6Swillf 		entry->expiration = expiretime;
219654925bf6Swillf 	    }
219754925bf6Swillf 	}
219854925bf6Swillf 
219954925bf6Swillf 	/* LOGIN DISABLED */
220054925bf6Swillf 	if ((st=krb5_ldap_get_string(ld, ent, "logindisabled", &is_login_disabled,
220154925bf6Swillf 		    &attr_present)) != 0)
220254925bf6Swillf 	    goto cleanup;
220354925bf6Swillf 	if (attr_present == TRUE) {
220454925bf6Swillf 	    if (strcasecmp(is_login_disabled, "TRUE")== 0)
220554925bf6Swillf 		entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
220654925bf6Swillf 	    free (is_login_disabled);
220754925bf6Swillf 	}
220854925bf6Swillf     }
220954925bf6Swillf #endif
221054925bf6Swillf 
221154925bf6Swillf     if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0)
221254925bf6Swillf 	goto cleanup;
221354925bf6Swillf 
221454925bf6Swillf     /* We already know that the policy is inside the realm container. */
221554925bf6Swillf     if (polname) {
221654925bf6Swillf 	osa_policy_ent_t   pwdpol;
221754925bf6Swillf 	int                cnt=0;
221854925bf6Swillf 	krb5_timestamp     last_pw_changed;
221954925bf6Swillf 	krb5_ui_4          pw_max_life;
222054925bf6Swillf 
222154925bf6Swillf 	memset(&pwdpol, 0, sizeof(pwdpol));
222254925bf6Swillf 
222354925bf6Swillf 	if ((st=krb5_ldap_get_password_policy(context, polname, &pwdpol, &cnt)) != 0)
222454925bf6Swillf 	    goto cleanup;
222554925bf6Swillf 	pw_max_life = pwdpol->pw_max_life;
222654925bf6Swillf 	/* Solaris Kerberos: fix memory leak */
222754925bf6Swillf 	krb5_ldap_free_password_policy(context, pwdpol);
222854925bf6Swillf 
222954925bf6Swillf 	if (pw_max_life > 0) {
223054925bf6Swillf 	    if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0)
223154925bf6Swillf 		goto cleanup;
223254925bf6Swillf 
2233*2f0b63d2SToomas Soome 	    if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == KDB_PWD_EXPIRE_TIME_ATTR) {
223454925bf6Swillf 		if ((last_pw_changed + pw_max_life) < entry->pw_expiration)
223554925bf6Swillf 		    entry->pw_expiration = last_pw_changed + pw_max_life;
223654925bf6Swillf 	    } else
223754925bf6Swillf 		entry->pw_expiration = last_pw_changed + pw_max_life;
223854925bf6Swillf 	}
223954925bf6Swillf     }
224054925bf6Swillf     /* XXX so krb5_encode_princ_contents() will be happy */
224154925bf6Swillf     entry->len = KRB5_KDB_V1_BASE_LENGTH;
224254925bf6Swillf 
224354925bf6Swillf cleanup:
224454925bf6Swillf 
224554925bf6Swillf     if (DN != NULL)
224654925bf6Swillf 	ldap_memfree(DN);
224754925bf6Swillf 
224854925bf6Swillf     if (userinfo_tl_data.tl_data_contents != NULL)
224954925bf6Swillf 	free(userinfo_tl_data.tl_data_contents);
225054925bf6Swillf 
225154925bf6Swillf     /* Solaris Kerberos: added this to fix memleak */
225254925bf6Swillf     if (kadm_tl_data.tl_data_contents != NULL)
225354925bf6Swillf 	free(kadm_tl_data.tl_data_contents);
225454925bf6Swillf 
225554925bf6Swillf     if (pwdpolicydn != NULL)
225654925bf6Swillf 	free(pwdpolicydn);
225754925bf6Swillf 
225854925bf6Swillf     if (polname != NULL)
225954925bf6Swillf 	free(polname);
226054925bf6Swillf 
226154925bf6Swillf     if (tktpolname != NULL)
226254925bf6Swillf 	free (tktpolname);
226354925bf6Swillf 
226454925bf6Swillf     if (policydn != NULL)
226554925bf6Swillf 	free(policydn);
226654925bf6Swillf 
226754925bf6Swillf     if (link_references) {
226854925bf6Swillf         int i;
226954925bf6Swillf         for (i=0; link_references[i] != NULL; ++i)
227054925bf6Swillf             free (link_references[i]);
227154925bf6Swillf         free (link_references);
227254925bf6Swillf     }
227354925bf6Swillf 
227454925bf6Swillf     return (st);
227554925bf6Swillf }
227654925bf6Swillf 
227754925bf6Swillf /*
227854925bf6Swillf  * Solaris libldap does not provide the following functions which are in
227954925bf6Swillf  * OpenLDAP.  Note, Solaris Kerberos added the use_SSL to do a SSL init.  Also
228054925bf6Swillf  * added errstr to return specific error if it isn't NULL.  Yes, this is ugly
228154925bf6Swillf  * and no, the errstr should not be free()'ed.
228254925bf6Swillf  */
228354925bf6Swillf #ifndef HAVE_LDAP_INITIALIZE
228454925bf6Swillf int
ldap_initialize(LDAP ** ldp,char * url,int use_SSL,char ** errstr)228554925bf6Swillf ldap_initialize(LDAP **ldp, char *url, int use_SSL, char **errstr)
228654925bf6Swillf {
228754925bf6Swillf     int rc = LDAP_SUCCESS;
228854925bf6Swillf     LDAP *ld = NULL;
228954925bf6Swillf     LDAPURLDesc *ludp = NULL;
229054925bf6Swillf 
229154925bf6Swillf     /* For now, we don't use any DN that may be provided.  And on
229254925bf6Swillf        Solaris (based on Mozilla's LDAP client code), we need the
229354925bf6Swillf        _nodn form to parse "ldap://host" without a trailing slash.
229454925bf6Swillf 
229554925bf6Swillf        Also, this version won't handle an input string which contains
229654925bf6Swillf        multiple URLs, unlike the OpenLDAP ldap_initialize.  See
229754925bf6Swillf        https://bugzilla.mozilla.org/show_bug.cgi?id=353336#c1 .  */
229854925bf6Swillf 
229954925bf6Swillf     /* to avoid reinit and leaking handles, *ldp must be NULL */
230054925bf6Swillf     if (*ldp != NULL)
230154925bf6Swillf 	return LDAP_SUCCESS;
230254925bf6Swillf 
230354925bf6Swillf #ifdef HAVE_LDAP_URL_PARSE_NODN
230454925bf6Swillf     rc = ldap_url_parse_nodn(url, &ludp);
230554925bf6Swillf #else
230654925bf6Swillf     rc = ldap_url_parse(url, &ludp);
230754925bf6Swillf #endif
230854925bf6Swillf     if (rc == 0) {
230954925bf6Swillf 	if (use_SSL == SSL_ON)
231054925bf6Swillf 	    ld = ldapssl_init(ludp->lud_host, ludp->lud_port, 1);
231154925bf6Swillf 	else
231254925bf6Swillf 	    ld = ldap_init(ludp->lud_host, ludp->lud_port);
231354925bf6Swillf 
231454925bf6Swillf 	if (ld != NULL)
231554925bf6Swillf 	    *ldp = ld;
231654925bf6Swillf 	else {
231754925bf6Swillf 	    if (errstr != NULL)
231854925bf6Swillf 		*errstr = strerror(errno);
231954925bf6Swillf 	    rc = LDAP_OPERATIONS_ERROR;
232054925bf6Swillf 	}
232154925bf6Swillf 
232254925bf6Swillf 	ldap_free_urldesc(ludp);
232354925bf6Swillf     } else {
232454925bf6Swillf 	/* report error from ldap url parsing */
232554925bf6Swillf 	if (errstr != NULL)
232654925bf6Swillf 	    *errstr = ldap_err2string(rc);
232754925bf6Swillf 	/* convert to generic LDAP error */
232854925bf6Swillf 	rc = LDAP_OPERATIONS_ERROR;
232954925bf6Swillf     }
233054925bf6Swillf     return rc;
233154925bf6Swillf }
233254925bf6Swillf #endif /* HAVE_LDAP_INITIALIZE */
233354925bf6Swillf 
233454925bf6Swillf #ifndef HAVE_LDAP_UNBIND_EXT_S
233554925bf6Swillf int
ldap_unbind_ext_s(LDAP * ld,LDAPControl ** sctrls,LDAPControl ** cctrls)233654925bf6Swillf ldap_unbind_ext_s(LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls)
233754925bf6Swillf {
233854925bf6Swillf     return ldap_unbind_ext(ld, sctrls, cctrls);
233954925bf6Swillf }
234054925bf6Swillf #endif /* HAVE_LDAP_UNBIND_EXT_S */
2341