diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h	2009-01-31 08:55:14.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h	2011-02-26 07:57:52.000000000 +0900
@@ -101,14 +101,18 @@
 #define LDAP_SEARCH(base, scope, filter, attrs)   LDAP_SEARCH_1(base, scope, filter, attrs, CHECK_STATUS)
 
 #define LDAP_SEARCH_1(base, scope, filter, attrs, status_check)        \
-      do { \
-	  st = ldap_search_ext_s(ld, base, scope, filter, attrs, 0, NULL, NULL, &timelimit, LDAP_NO_LIMIT, &result); \
-	  if (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR) { \
-              tempst = krb5_ldap_rebind(ldap_context, &ldap_server_handle); \
-	      if (ldap_server_handle) \
-		  ld = ldap_server_handle->ldap_handle; \
-	  } \
-      }while (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR && tempst == 0); \
+    tempst = 0;                                                         \
+    st = ldap_search_ext_s(ld, base, scope, filter, attrs, 0, NULL,     \
+                           NULL, &timelimit, LDAP_NO_LIMIT, &result);   \
+    if (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR) { \
+        tempst = krb5_ldap_rebind(ldap_context, &ldap_server_handle);   \
+        if (ldap_server_handle)                                         \
+            ld = ldap_server_handle->ldap_handle;                       \
+        if (tempst == 0)                                                \
+            st = ldap_search_ext_s(ld, base, scope, filter, attrs, 0,   \
+                                   NULL, NULL, &timelimit,              \
+                                   LDAP_NO_LIMIT, &result);             \
+    }                                                                   \
       \
       if (status_check != IGNORE_STATUS) { \
         if (tempst != 0) { \
diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h.orig krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h.orig
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h.orig	1970-01-01 09:00:00.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h.orig	2009-01-31 08:55:14.000000000 +0900
@@ -0,0 +1,331 @@
+/*
+ * lib/kdb/kdb_ldap/kdb_ldap.h
+ *
+ * Copyright (c) 2004-2005, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* */
+#ifndef _KDB_LDAP_H
+#define _KDB_LDAP_H 1
+
+/* We want the interfaces marked "deprecated" in OpenLDAP.  */
+#define LDAP_DEPRECATED 1
+#include <ldap.h>
+
+/* Check for acceptable versions.
+
+   OpenLDAP version 2.2.6 is known to have some kind of problem that
+   is tickled by the use of multiple handles in this code.  Version
+   2.2.19 in Mac OS 10.4.7 seems to be buggy as well.  Version 2.2.24
+   doesn't have this problem.  Other in-between versions have not been
+   tested.  */
+#ifndef BUILD_WITH_BROKEN_LDAP
+# if defined(LDAP_API_FEATURE_X_OPENLDAP)
+#  if LDAP_VENDOR_VERSION < 20224
+#   error This code triggers bugs in old OpenLDAP implementations.  Please update to 2.2.24 or later.
+#  endif
+# endif
+#endif /* BUILD_WITH_BROKEN_LDAP */
+
+#include <k5-thread.h>
+#include <kdb5.h>
+#include "k5-int.h"
+#include "ldap_krbcontainer.h"
+#include "ldap_realm.h"
+
+extern struct timeval timelimit;
+
+#define  SERV_COUNT                  100
+#define  DEFAULT_CONNS_PER_SERVER    5
+#define  REALM_READ_REFRESH_INTERVAL (5 * 60)
+
+#ifdef HAVE_EDIRECTORY
+#define  SECURITY_CONTAINER "cn=Security"
+#define  KERBEROS_CONTAINER "cn=Kerberos,cn=Security"
+#endif
+
+#if !defined(LDAP_OPT_RESULT_CODE) && defined(LDAP_OPT_ERROR_NUMBER)
+#define LDAP_OPT_RESULT_CODE LDAP_OPT_ERROR_NUMBER
+#endif
+
+#define MAXINTLEN  10
+
+#define IGNORE_STATUS              0
+#define CHECK_STATUS               1
+
+#define SETUP_CONTEXT() if (context == NULL || context->dal_handle == NULL \
+            || context->dal_handle->db_context == NULL) { \
+        return EINVAL; \
+    } \
+    dal_handle = context->dal_handle; \
+    ldap_context = (krb5_ldap_context *) dal_handle->db_context; \
+    if (ldap_context == NULL || ldap_context->server_info_list == NULL) \
+        return KRB5_KDB_DBNOTINITED;
+
+#define GET_HANDLE()  ld = NULL; \
+    st = krb5_ldap_request_handle_from_pool(ldap_context, &ldap_server_handle); \
+    if (st != 0) { \
+        prepend_err_str(context, "LDAP handle unavailable: ", KRB5_KDB_ACCESS_ERROR, st); \
+        st = KRB5_KDB_ACCESS_ERROR; \
+        goto cleanup; \
+    } \
+    ld = ldap_server_handle->ldap_handle;
+
+extern int set_ldap_error (krb5_context ctx, int st, int op);
+extern void prepend_err_str (krb5_context ctx, const char *s, krb5_error_code err, krb5_error_code oerr);
+
+#define LDAP_SEARCH(base, scope, filter, attrs)   LDAP_SEARCH_1(base, scope, filter, attrs, CHECK_STATUS)
+
+#define LDAP_SEARCH_1(base, scope, filter, attrs, status_check)        \
+      do { \
+	  st = ldap_search_ext_s(ld, base, scope, filter, attrs, 0, NULL, NULL, &timelimit, LDAP_NO_LIMIT, &result); \
+	  if (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR) { \
+              tempst = krb5_ldap_rebind(ldap_context, &ldap_server_handle); \
+	      if (ldap_server_handle) \
+		  ld = ldap_server_handle->ldap_handle; \
+	  } \
+      }while (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR && tempst == 0); \
+      \
+      if (status_check != IGNORE_STATUS) { \
+        if (tempst != 0) { \
+            prepend_err_str(context, "LDAP handle unavailable: ", KRB5_KDB_ACCESS_ERROR, st); \
+            st = KRB5_KDB_ACCESS_ERROR; \
+            goto cleanup; \
+        } \
+        if (st != LDAP_SUCCESS) { \
+	     st = set_ldap_error(context, st, OP_SEARCH); \
+	     goto cleanup; \
+        } \
+      }
+
+
+#define CHECK_CLASS_VALIDITY(st, mask, str) \
+	if (st != 0 || mask == 0) { \
+	    if (st == 0 && mask == 0) { \
+	       st = set_ldap_error(context, LDAP_OBJECT_CLASS_VIOLATION, OP_SEARCH); \
+	    } \
+	    prepend_err_str(context, str, st, st); \
+	    goto cleanup; \
+	 }
+
+#define CHECK_NULL(ptr) if (ptr == NULL) { \
+                            st = ENOMEM; \
+                            goto cleanup; \
+                        }
+
+#define  STORE16_INT(ptr, val)	store_16_be(val, ptr)
+#define  STORE32_INT(ptr, val)  store_32_be(val, ptr)
+#define UNSTORE16_INT(ptr, val) (val = load_16_be(ptr))
+#define UNSTORE32_INT(ptr, val) (val = load_32_be(ptr))
+
+#define KRB5_CONF_KDC_BIND_DN "ldap_kdc_dn"
+#define KRB5_CONF_ADMIN_BIND_DN "ldap_kadmind_dn"
+#define KRB5_CONF_PWD_BIND_DN "ldap_passwd_dn"
+
+#define  KDB_TL_USER_INFO      0x7ffe
+
+#define KDB_TL_PRINCTYPE          0x01
+#define KDB_TL_PRINCCOUNT         0x02
+#define KDB_TL_USERDN             0x03
+#define KDB_TL_KEYINFO            0x04
+#define KDB_TL_MASK               0x05
+#define KDB_TL_CONTAINERDN        0x06
+#define KDB_TL_LINKDN             0x07
+
+
+#define CHECK_LDAP_HANDLE(lcontext)     if (!(ldap_context \
+					      && ldap_context->server_info_list)) { \
+					  return KRB5_KDB_DBNOTINITED; \
+					}
+     
+#define HNDL_LOCK(lcontext) k5_mutex_lock(&lcontext->hndl_lock)
+#define HNDL_UNLOCK(lcontext) k5_mutex_unlock(&lcontext->hndl_lock)
+
+/* To be used later */
+typedef struct _krb5_ldap_certificates{
+    char *certificate;
+    int  certtype;
+}krb5_ldap_certificates;
+
+/* ldap server info structure */
+
+typedef enum _server_type {PRIMARY, SECONDARY} krb5_ldap_server_type;
+
+typedef enum _server_status {OFF, ON, NOTSET} krb5_ldap_server_status;
+
+typedef struct _krb5_ldap_server_info krb5_ldap_server_info;
+
+typedef struct  _krb5_ldap_server_handle {
+    int                              msgid;
+    LDAP                             *ldap_handle;
+    krb5_boolean                     server_info_update_pending;
+    krb5_ldap_server_info            *server_info;
+    struct _krb5_ldap_server_handle  *next;
+} krb5_ldap_server_handle;
+
+struct _krb5_ldap_server_info {
+    krb5_ldap_server_type	 server_type;
+    krb5_ldap_server_status      server_status;
+    krb5_ui_4                    num_conns;
+    krb5_ldap_server_handle      *ldap_server_handles;
+    time_t                       downtime;
+    char			*server_name;
+#ifdef HAVE_EDIRECTORY
+    char			*root_certificate_file;
+#endif
+    struct _krb5_ldap_server_info *next;
+};
+
+
+/* ldap server structure */
+
+typedef enum {SERVICE_DN_TYPE_SERVER, SERVICE_DN_TYPE_CLIENT} krb5_ldap_servicetype; 
+
+typedef struct _krb5_ldap_context {
+  krb5_ldap_servicetype         service_type;
+  krb5_ldap_server_info         **server_info_list;
+  krb5_ui_4                     max_server_conns;
+  char                          *conf_section;
+  char 		                *bind_dn;
+  char                          *bind_pwd;
+  char 		                *service_password_file;
+  char 		                *root_certificate_file;
+  char                          *service_cert_path;
+  char                          *service_cert_pass;
+  krb5_ldap_certificates        **certificates;
+  krb5_ui_4                     cert_count; /* certificate count */
+  k5_mutex_t                    hndl_lock;
+  krb5_ldap_krbcontainer_params *krbcontainer;
+  krb5_ldap_realm_params        *lrparams;
+  krb5_context                  kcontext;   /* to set the error code and message */
+} krb5_ldap_context;
+
+
+typedef struct {
+  int           nkey;
+  struct berval **keys;
+}KEY;
+
+#define k5ldap_inited(c) (c && c->db_context \
+                         && ((kdb5_dal_handle*)c->db_context)->db_context \
+                         && ((krb5_ldap_context *) ((kdb5_dal_handle*)c->db_context)->db_context))
+
+
+/* misc functions */
+
+krb5_error_code
+krb5_ldap_db_init(krb5_context, krb5_ldap_context *);
+
+krb5_error_code
+krb5_ldap_db_single_init(krb5_ldap_context *);
+
+krb5_error_code
+krb5_ldap_rebind(krb5_ldap_context *, krb5_ldap_server_handle **);
+
+krb5_error_code
+krb5_ldap_db_get_age(krb5_context, char *, time_t *);
+
+krb5_error_code 
+krb5_ldap_lib_init(void);
+
+krb5_error_code 
+krb5_ldap_lib_cleanup(void);
+
+void * 
+krb5_ldap_alloc( krb5_context kcontext,  void *ptr, size_t size );
+
+void 
+krb5_ldap_free( krb5_context kcontext, void *ptr );
+krb5_error_code
+krb5_ldap_get_mkey(krb5_context, krb5_keyblock **);
+
+krb5_error_code
+krb5_ldap_set_mkey(krb5_context, char *, krb5_keyblock *);
+
+krb5_error_code
+krb5_ldap_get_mkey_list (krb5_context context, krb5_keylist_node **key_list);
+
+krb5_error_code
+krb5_ldap_set_mkey_list(krb5_context, krb5_keylist_node *);
+
+krb5_error_code
+krb5_ldap_create(krb5_context , char *, char **);
+
+krb5_error_code 
+krb5_ldap_open( krb5_context , char *,
+		char **db_args,
+		int mode );
+krb5_error_code 
+krb5_ldap_close( krb5_context );
+
+krb5_error_code
+krb5_ldap_free_ldap_context(krb5_ldap_context *);
+
+krb5_error_code
+krb5_ldap_read_startup_information(krb5_context );
+
+int
+has_sasl_external_mech(krb5_context, char *);
+
+krb5_error_code
+krb5_ldap_free_server_context_params(krb5_ldap_context *ldap_context);
+
+
+/* DAL functions */
+
+
+krb5_error_code
+krb5_ldap_set_option( krb5_context, int, void * );
+
+krb5_error_code
+krb5_ldap_lock( krb5_context, int );
+
+krb5_error_code
+krb5_ldap_unlock( krb5_context );
+
+krb5_error_code
+krb5_ldap_supported_realms( krb5_context, char ** );
+
+krb5_error_code
+krb5_ldap_free_supported_realms( krb5_context, char ** );
+
+const char *
+krb5_ldap_errcode_2_string( krb5_context, long );
+
+void
+krb5_ldap_release_errcode_string (krb5_context, const char *);
+
+#ifndef HAVE_LDAP_INITIALIZE
+int
+ldap_initialize(LDAP **, char *);
+#endif
+#ifndef HAVE_LDAP_UNBIND_EXT_S
+int
+ldap_unbind_ext_s(LDAP *, LDAPControl **, LDAPControl **);
+#endif
+
+#endif
diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c	2008-10-07 05:04:12.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c	2011-02-26 07:57:52.000000000 +0900
@@ -296,6 +296,7 @@
 {
     krb5_ldap_server_handle     *handle = *ldap_server_handle;
 
+    ldap_unbind_ext_s(handle->ldap_handle, NULL, NULL);
     if ((ldap_initialize(&handle->ldap_handle, handle->server_info->server_name) != LDAP_SUCCESS)
 	|| (krb5_ldap_bind(ldap_context, handle) != LDAP_SUCCESS))
 	return krb5_ldap_request_next_handle_from_pool(ldap_context, ldap_server_handle);
diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c.orig krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c.orig
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c.orig	2008-10-07 05:04:12.000000000 +0900
@@ -0,0 +1,354 @@
+/*
+ * lib/kdb/kdb_ldap/kdb_ldap_conn.c
+ *
+ * Copyright (c) 2004-2005, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "autoconf.h"
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ldap_main.h"
+#include "ldap_service_stash.h"
+#include <kdb5.h>
+
+static krb5_error_code
+krb5_validate_ldap_context(krb5_context context, krb5_ldap_context *ldap_context)
+{
+    krb5_error_code             st=0;
+    unsigned char               *password=NULL;
+
+    if (ldap_context->bind_dn == NULL) {
+	st = EINVAL;
+	krb5_set_error_message(context, st, "LDAP bind dn value missing ");
+	goto err_out;
+    }
+
+    if (ldap_context->bind_pwd == NULL && ldap_context->service_password_file == NULL) {
+	st = EINVAL;
+	krb5_set_error_message(context, st, "LDAP bind password value missing ");
+	goto err_out;
+    }
+
+    if (ldap_context->bind_pwd == NULL && ldap_context->service_password_file !=
+	NULL && ldap_context->service_cert_path == NULL) {
+	if ((st=krb5_ldap_readpassword(context, ldap_context, &password)) != 0) {
+	    prepend_err_str(context, "Error reading password from stash: ", st, st);
+	    goto err_out;
+	}
+
+	/* Check if the returned 'password' is actually the path of a certificate */
+	if (!strncmp("{FILE}", (char *)password, 6)) {
+	    /* 'password' format: <path>\0<password> */
+	    ldap_context->service_cert_path = strdup((char *)password + strlen("{FILE}"));
+	    if (password[strlen((char *)password) + 1] == '\0')
+		ldap_context->service_cert_pass = NULL;
+	    else
+		ldap_context->service_cert_pass = strdup((char *)password +
+							 strlen((char *)password) + 1);
+	    free(password);
+	} else {
+	    ldap_context->bind_pwd = (char *)password;
+	    if (ldap_context->bind_pwd == NULL) {
+		st = EINVAL;
+		krb5_set_error_message(context, st, "Error reading password from stash");
+		goto err_out;
+	    }
+	}
+    }
+
+    /* NULL password not allowed */
+    if (ldap_context->bind_pwd != NULL && strlen(ldap_context->bind_pwd) == 0) {
+	st = EINVAL;
+	krb5_set_error_message(context, st, "Service password length is zero");
+	goto err_out;
+    }
+
+err_out:
+    return st;
+}
+
+/*
+ * Internal Functions called by init functions.
+ */
+
+static krb5_error_code
+krb5_ldap_bind(ldap_context, ldap_server_handle)
+    krb5_ldap_context           *ldap_context;
+    krb5_ldap_server_handle     *ldap_server_handle;
+{
+    krb5_error_code             st=0;
+    struct berval               bv={0, NULL}, *servercreds=NULL;
+
+    if (ldap_context->service_cert_path != NULL) {
+	/* Certificate based bind (SASL EXTERNAL mechanism) */
+
+	st = ldap_sasl_bind_s(ldap_server_handle->ldap_handle,
+			      NULL,	   /* Authenticating dn */
+			      "EXTERNAL",  /* Method used for authentication */
+			      &bv,
+			      NULL,
+			      NULL,
+			      &servercreds);
+
+	if (st == LDAP_SASL_BIND_IN_PROGRESS) {
+	    st = ldap_sasl_bind_s(ldap_server_handle->ldap_handle,
+				  NULL,
+				  "EXTERNAL",
+				  servercreds,
+				  NULL,
+				  NULL,
+				  &servercreds);
+	}
+    } else {
+	/* password based simple bind */
+        bv.bv_val = ldap_context->bind_pwd;
+        bv.bv_len = strlen(ldap_context->bind_pwd);
+        st = ldap_sasl_bind_s(ldap_server_handle->ldap_handle, 
+                                ldap_context->bind_dn,
+                                NULL, &bv, NULL, 
+                                NULL, NULL);
+    }
+    return st;
+}
+
+static krb5_error_code
+krb5_ldap_initialize(ldap_context, server_info)
+    krb5_ldap_context *ldap_context;
+    krb5_ldap_server_info *server_info;
+{
+    krb5_error_code             st=0;
+    krb5_ldap_server_handle     *ldap_server_handle=NULL;
+
+
+    ldap_server_handle = calloc(1, sizeof(krb5_ldap_server_handle));
+    if (ldap_server_handle == NULL) {
+	st = ENOMEM;
+	goto err_out;
+    }
+
+    /* ldap init */
+    if ((st = ldap_initialize(&ldap_server_handle->ldap_handle, server_info->server_name)) != 0) {
+	if (ldap_context->kcontext)
+	    krb5_set_error_message (ldap_context->kcontext, KRB5_KDB_ACCESS_ERROR, "%s",
+				    ldap_err2string(st));
+	st = KRB5_KDB_ACCESS_ERROR;
+	goto err_out;
+    }
+
+    if ((st=krb5_ldap_bind(ldap_context, ldap_server_handle)) == 0) {
+	ldap_server_handle->server_info_update_pending = FALSE;
+	server_info->server_status = ON;
+	krb5_update_ldap_handle(ldap_server_handle, server_info);
+    } else {
+	if (ldap_context->kcontext)
+	    krb5_set_error_message (ldap_context->kcontext,
+				    KRB5_KDB_ACCESS_ERROR, "%s",
+				    ldap_err2string(st));
+	st = KRB5_KDB_ACCESS_ERROR;
+	server_info->server_status = OFF;
+	time(&server_info->downtime);
+	/* ldap_unbind_s(ldap_server_handle->ldap_handle); */
+	free(ldap_server_handle);
+    }
+
+err_out:
+    return st;
+}
+
+/*
+ * initialization for data base routines.
+ */
+
+krb5_error_code
+krb5_ldap_db_init(krb5_context context, krb5_ldap_context *ldap_context)
+{
+    krb5_error_code             st=0;
+    krb5_boolean                sasl_mech_supported=TRUE;
+    int                         cnt=0, version=LDAP_VERSION3;
+    struct timeval              local_timelimit = {10,0};
+
+    if ((st=krb5_validate_ldap_context(context, ldap_context)) != 0)
+	goto err_out;
+
+    ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+    ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &local_timelimit);
+#elif defined LDAP_X_OPT_CONNECT_TIMEOUT
+    ldap_set_option(NULL, LDAP_X_OPT_CONNECT_TIMEOUT, &local_timelimit);
+#endif
+
+    st = HNDL_LOCK(ldap_context);
+    if (st)
+	return st;
+    while (ldap_context->server_info_list[cnt] != NULL) {
+	krb5_ldap_server_info *server_info=NULL;
+
+	server_info = ldap_context->server_info_list[cnt];
+
+	if (server_info->server_status == NOTSET) {
+	    unsigned int conns=0;
+
+	    /*
+	     * Check if the server has to perform certificate-based authentication
+	     */
+	    if (ldap_context->service_cert_path != NULL) {
+		/* Find out if the server supports SASL EXTERNAL mechanism */
+		if (has_sasl_external_mech(context, server_info->server_name) == 1) {
+		    cnt++;
+		    sasl_mech_supported = FALSE;
+		    continue; /* Check the next LDAP server */
+		}
+		sasl_mech_supported = TRUE;
+	    }
+
+	    krb5_clear_error_message(context);
+
+	    for (conns=0; conns < ldap_context->max_server_conns; ++conns) {
+		if ((st=krb5_ldap_initialize(ldap_context, server_info)) != 0)
+		    break;
+	    } /* for (conn= ... */
+
+	    if (server_info->server_status == ON)
+		break;  /* server init successful, so break */
+	}
+	++cnt;
+    }
+    HNDL_UNLOCK(ldap_context);
+
+err_out:
+    if (sasl_mech_supported == FALSE) {
+	st = KRB5_KDB_ACCESS_ERROR;
+	krb5_set_error_message (context, st,
+				"Certificate based authentication requested but "
+				"not supported by LDAP servers");
+    }
+    return (st);
+}
+
+
+/*
+ * get a single handle. Do not lock the mutex
+ */
+
+krb5_error_code
+krb5_ldap_db_single_init(krb5_ldap_context *ldap_context)
+{
+    krb5_error_code             st=0;
+    int                         cnt=0;
+    krb5_ldap_server_info       *server_info=NULL;
+
+    while (ldap_context->server_info_list[cnt] != NULL) {
+	server_info = ldap_context->server_info_list[cnt];
+	if ((server_info->server_status == NOTSET || server_info->server_status == ON)) {
+	    if (server_info->num_conns < ldap_context->max_server_conns-1) {
+		st = krb5_ldap_initialize(ldap_context, server_info);
+		if (st == LDAP_SUCCESS)
+		    goto cleanup;
+	    }
+	}
+	++cnt;
+    }
+
+    /* If we are here, try to connect to all the servers */
+
+    cnt = 0;
+    while (ldap_context->server_info_list[cnt] != NULL) {
+	server_info = ldap_context->server_info_list[cnt];
+	st = krb5_ldap_initialize(ldap_context, server_info);
+	if (st == LDAP_SUCCESS)
+	    goto cleanup;
+	++cnt;
+    }
+cleanup:
+    return (st);
+}
+
+krb5_error_code
+krb5_ldap_rebind(ldap_context, ldap_server_handle)
+    krb5_ldap_context           *ldap_context;
+    krb5_ldap_server_handle     **ldap_server_handle;
+{
+    krb5_ldap_server_handle     *handle = *ldap_server_handle;
+
+    if ((ldap_initialize(&handle->ldap_handle, handle->server_info->server_name) != LDAP_SUCCESS)
+	|| (krb5_ldap_bind(ldap_context, handle) != LDAP_SUCCESS))
+	return krb5_ldap_request_next_handle_from_pool(ldap_context, ldap_server_handle);
+    return LDAP_SUCCESS;
+}
+
+/*
+ *     DAL API functions
+ */
+krb5_error_code krb5_ldap_lib_init()
+{
+    return 0;
+}
+
+krb5_error_code krb5_ldap_lib_cleanup()
+{
+    /* right now, no cleanup required */
+    return 0;
+}
+
+krb5_error_code
+krb5_ldap_free_ldap_context(krb5_ldap_context *ldap_context)
+{
+    if (ldap_context == NULL)
+	return 0;
+
+    krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
+    ldap_context->krbcontainer = NULL;
+
+    krb5_ldap_free_realm_params(ldap_context->lrparams);
+    ldap_context->lrparams = NULL;
+
+    krb5_ldap_free_server_params(ldap_context);
+
+    return 0;
+}
+
+krb5_error_code
+krb5_ldap_close(krb5_context context)
+{
+    kdb5_dal_handle  *dal_handle=NULL;
+    krb5_ldap_context *ldap_context=NULL;
+
+    if (context == NULL ||
+	context->dal_handle == NULL ||
+	context->dal_handle->db_context == NULL)
+	return 0;
+
+    dal_handle = context->dal_handle;
+    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
+    dal_handle->db_context = NULL;
+
+    krb5_ldap_free_ldap_context(ldap_context);
+
+    return 0;
+}
diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c	2009-02-19 03:14:48.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c	2011-02-26 07:57:52.000000000 +0900
@@ -449,12 +449,11 @@
      * portion, then the first portion of the principal name SHOULD be
      * "krbtgt".  All this check is done in the immediate block.
      */
-    if (searchfor->length == 2)
-	if ((strncasecmp(searchfor->data[0].data, "krbtgt",
-			 FIND_MAX(searchfor->data[0].length, strlen("krbtgt"))) == 0) &&
-	    (strncasecmp(searchfor->data[1].data, defrealm,
-			 FIND_MAX(searchfor->data[1].length, defrealmlen)) == 0))
+    if (searchfor->length == 2) {
+        if (data_eq_string(searchfor->data[0], "krbtgt") &&
+            data_eq_string(searchfor->data[1], defrealm))
 	    return 0;
+    }
 
     /* first check the length, if they are not equal, then they are not same */
     if (strlen(defrealm) != searchfor->realm.length)
diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c.orig krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c.orig
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c.orig	2009-02-19 03:14:48.000000000 +0900
@@ -0,0 +1,2271 @@
+/*
+ * lib/kdb/kdb_ldap/ldap_misc.c
+ *
+ * Copyright (c) 2004-2005, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#include <string.h>
+#include <time.h>
+#include "kdb_ldap.h"
+#include "ldap_misc.h"
+#include "ldap_handle.h"
+#include "ldap_err.h"
+#include "ldap_principal.h"
+#include "princ_xdr.h"
+#include "ldap_pwd_policy.h"
+
+#ifdef NEED_STRPTIME_PROTO
+extern char *strptime (const char *, const char *, struct tm *);
+#endif
+
+static krb5_error_code
+remove_overlapping_subtrees(char **listin, char **listop, int *subtcount,
+			    int sscope);
+
+/* Linux (GNU Libc) provides a length-limited variant of strdup.
+   But all the world's not Linux.  */
+#undef strndup
+#define strndup my_strndup
+#ifdef HAVE_LDAP_STR2DN
+static char *my_strndup (const char *input, size_t limit)
+{
+    size_t len = strlen(input);
+    char *result;
+    if (len > limit) {
+	result = malloc(1 + limit);
+	if (result != NULL) {
+	    memcpy(result, input, limit);
+	    result[limit] = 0;
+	}
+	return result;
+    } else
+	return strdup(input);
+}
+#endif
+
+/* Get integer or string values from the config section, falling back
+   to the default section, then to hard-coded values.  */
+static errcode_t
+prof_get_integer_def(krb5_context ctx, const char *conf_section,
+		     const char *name, int dfl, krb5_ui_4 *out)
+{
+    errcode_t err;
+    int out_temp = 0;
+
+    err = profile_get_integer (ctx->profile,
+			       KDB_MODULE_SECTION, conf_section, name,
+			       0, &out_temp);
+    if (err) {
+	krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
+				name, error_message(err));
+	return err;
+    }
+    if (out_temp != 0) {
+	*out = out_temp;
+	return 0;
+    }
+    err = profile_get_integer (ctx->profile,
+			       KDB_MODULE_DEF_SECTION, name, 0,
+			       dfl, &out_temp);
+    if (err) {
+	krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
+				name, error_message(err));
+	return err;
+    }
+    *out = out_temp;
+    return 0;
+}
+
+/* We don't have non-null defaults in any of our calls, so don't
+   bother with the extra argument.  */
+static errcode_t
+prof_get_string_def(krb5_context ctx, const char *conf_section,
+		    const char *name, char **out)
+{
+    errcode_t err;
+
+    err = profile_get_string (ctx->profile,
+			      KDB_MODULE_SECTION, conf_section, name,
+			      0, out);
+    if (err) {
+	krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
+				name, error_message(err));
+	return err;
+    }
+    if (*out != 0)
+	return 0;
+    err = profile_get_string (ctx->profile,
+			      KDB_MODULE_DEF_SECTION, name, 0,
+			      0, out);
+    if (err) {
+	krb5_set_error_message (ctx, err, "Error reading '%s' attribute: %s",
+				name, error_message(err));
+	return err;
+    }
+    return 0;
+}
+
+
+
+/*
+ * This function reads the parameters from the krb5.conf file. The
+ * parameters read here are DAL-LDAP specific attributes. Some of
+ * these are ldap_server ....
+ */
+krb5_error_code
+krb5_ldap_read_server_params(context, conf_section, srv_type)
+    krb5_context               context;
+    char                       *conf_section;
+    int                        srv_type;
+{
+    char                        *tempval=NULL, *save_ptr=NULL;
+    const char                  *delims="\t\n\f\v\r ,";
+    krb5_error_code             st=0;
+    kdb5_dal_handle             *dal_handle=NULL;
+    krb5_ldap_context           *ldap_context=NULL;
+    krb5_ldap_server_info       ***server_info=NULL;
+
+    dal_handle = context->dal_handle;
+    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
+
+    /* copy the conf_section into ldap_context for later use */
+    if (conf_section) {
+	ldap_context->conf_section = strdup (conf_section);
+	if (ldap_context->conf_section == NULL) {
+	    st = ENOMEM;
+	    goto cleanup;
+	}
+    }
+
+    /* initialize the mutexs and condition variable */
+    /* this portion logically doesn't fit here should be moved appropriately */
+
+    /* this mutex is used in ldap reconnection pool */
+    if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0) {
+	st = KRB5_KDB_SERVER_INTERNAL_ERR;
+#if 0
+	st = -1;
+	krb5_ldap_dal_err_funcp(context, krb5_err_have_str, st,
+				"k5_mutex_init failed");
+#endif
+	goto cleanup;
+    }
+
+    /*
+     * If max_server_conns is not set read it from database module
+     * section of conf file this parameter defines maximum ldap
+     * connections per ldap server.
+     */
+    if (ldap_context->max_server_conns == 0) {
+	st = prof_get_integer_def (context, conf_section,
+				   KRB5_CONF_LDAP_CONNS_PER_SERVER,
+				   DEFAULT_CONNS_PER_SERVER,
+				   &ldap_context->max_server_conns);
+	if (st)
+	    goto cleanup;
+    }
+
+    if (ldap_context->max_server_conns < 2) {
+	st = EINVAL;
+	krb5_set_error_message (context, st,
+				"Minimum connections required per server is 2");
+	goto cleanup;
+    }
+
+    /*
+     * If the bind dn is not set read it from the database module
+     * section of conf file this paramter is populated by one of the
+     * KDC, ADMIN or PASSWD dn to be used to connect to LDAP
+     * server.  The srv_type decides which dn to read.
+     */
+    if (ldap_context->bind_dn == NULL) {
+	char *name = 0;
+	if (srv_type == KRB5_KDB_SRV_TYPE_KDC)
+	    name = KRB5_CONF_LDAP_KDC_DN;
+	else if (srv_type == KRB5_KDB_SRV_TYPE_ADMIN)
+	    name = KRB5_CONF_LDAP_KADMIN_DN;
+	else if (srv_type == KRB5_KDB_SRV_TYPE_PASSWD)
+	    name = "ldap_kpasswdd_dn";
+
+	if (name) {
+	    st = prof_get_string_def (context, conf_section, name,
+				      &ldap_context->bind_dn);
+	    if (st)
+		goto cleanup;
+	}
+    }
+
+    /*
+     * Read service_password_file parameter from database module
+     * section of conf file this file contains stashed passwords of
+     * the KDC, ADMIN and PASSWD dns.
+     */
+    if (ldap_context->service_password_file == NULL) {
+	st = prof_get_string_def (context, conf_section,
+				  KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE,
+				  &ldap_context->service_password_file);
+	if (st)
+	    goto cleanup;
+    }
+
+#ifdef HAVE_EDIRECTORY
+    /*
+     * If root certificate file is not set read it from database
+     * module section of conf file this is the trusted root
+     * certificate of the Directory.
+     */
+    if (ldap_context->root_certificate_file == NULL) {
+	st = prof_get_string_def (context, conf_section,
+				  KRB5_CONF_LDAP_ROOT_CERTIFICATE_FILE,
+				  &ldap_context->root_certificate_file);
+	if (st)
+	    goto cleanup;
+    }
+#endif
+
+    /*
+     * If the ldap server parameter is not set read the list of ldap
+     * servers from the database module section of the conf file.
+     */
+
+    if (ldap_context->server_info_list == NULL) {
+	unsigned int ele=0;
+
+	server_info = &(ldap_context->server_info_list);
+	*server_info = (krb5_ldap_server_info **) calloc (SERV_COUNT+1,
+							  sizeof (krb5_ldap_server_info *));
+
+	if (*server_info == NULL) {
+	    st = ENOMEM;
+	    goto cleanup;
+	}
+
+	if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section,
+				   KRB5_CONF_LDAP_SERVERS, NULL, &tempval)) != 0) {
+	    krb5_set_error_message (context, st, "Error reading 'ldap_servers' attribute");
+	    goto cleanup;
+	}
+
+	if (tempval == NULL) {
+
+	    (*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
+								  sizeof(krb5_ldap_server_info));
+
+	    (*server_info)[ele]->server_name = strdup("ldapi://");
+	    if ((*server_info)[ele]->server_name == NULL) {
+		st = ENOMEM;
+		goto cleanup;
+	    }
+	    (*server_info)[ele]->server_status = NOTSET;
+	} else {
+	    char *item=NULL;
+
+	    item = strtok_r(tempval,delims,&save_ptr);
+	    while (item != NULL && ele<SERV_COUNT) {
+		(*server_info)[ele] = (krb5_ldap_server_info *)calloc(1,
+								      sizeof(krb5_ldap_server_info));
+		if ((*server_info)[ele] == NULL) {
+		    st = ENOMEM;
+		    goto cleanup;
+		}
+		(*server_info)[ele]->server_name = strdup(item);
+		if ((*server_info)[ele]->server_name == NULL) {
+		    st = ENOMEM;
+		    goto cleanup;
+		}
+
+		(*server_info)[ele]->server_status = NOTSET;
+		item = strtok_r(NULL,delims,&save_ptr);
+		++ele;
+	    }
+	    profile_release_string(tempval);
+	}
+    }
+
+cleanup:
+    return(st);
+}
+
+/*
+ * This function frees the krb5_ldap_context structure members.
+ */
+
+krb5_error_code
+krb5_ldap_free_server_context_params(ldap_context)
+    krb5_ldap_context           *ldap_context;
+{
+    int                         i=0;
+    krb5_ldap_server_handle     *ldap_server_handle=NULL, *next_ldap_server_handle=NULL;
+
+    if (ldap_context == NULL)
+	return 0;
+
+    /* Free all ldap servers list and the ldap handles associated with
+       the ldap server.  */
+    if (ldap_context->server_info_list) {
+	while (ldap_context->server_info_list[i]) {
+	    if (ldap_context->server_info_list[i]->server_name) {
+		free (ldap_context->server_info_list[i]->server_name);
+	    }
+#ifdef HAVE_EDIRECTORY
+	    if (ldap_context->server_info_list[i]->root_certificate_file) {
+		free (ldap_context->server_info_list[i]->root_certificate_file);
+	    }
+#endif
+	    if (ldap_context->server_info_list[i]->ldap_server_handles) {
+		ldap_server_handle = ldap_context->server_info_list[i]->ldap_server_handles;
+		while (ldap_server_handle) {
+		    ldap_unbind_ext_s(ldap_server_handle->ldap_handle, NULL, NULL);
+		    ldap_server_handle->ldap_handle = NULL;
+		    next_ldap_server_handle = ldap_server_handle->next;
+		    krb5_xfree(ldap_server_handle);
+		    ldap_server_handle = next_ldap_server_handle;
+		}
+	    }
+	    krb5_xfree(ldap_context->server_info_list[i]);
+	    i++;
+	}
+	krb5_xfree(ldap_context->server_info_list);
+    }
+
+    if (ldap_context->conf_section != NULL) {
+	krb5_xfree(ldap_context->conf_section);
+	ldap_context->conf_section = NULL;
+    }
+
+    if (ldap_context->bind_dn != NULL) {
+	krb5_xfree(ldap_context->bind_dn);
+	ldap_context->bind_dn = NULL;
+    }
+
+    if (ldap_context->bind_pwd != NULL) {
+	memset(ldap_context->bind_pwd, 0, strlen(ldap_context->bind_pwd));
+	krb5_xfree(ldap_context->bind_pwd);
+	ldap_context->bind_pwd = NULL;
+    }
+
+    if (ldap_context->service_password_file != NULL) {
+	krb5_xfree(ldap_context->service_password_file);
+	ldap_context->service_password_file = NULL;
+    }
+
+#ifdef HAVE_EDIRECTORY
+    if (ldap_context->root_certificate_file != NULL) {
+	krb5_xfree(ldap_context->root_certificate_file);
+	ldap_context->root_certificate_file = NULL;
+    }
+#endif
+
+    if (ldap_context->service_cert_path != NULL) {
+	krb5_xfree(ldap_context->service_cert_path);
+	ldap_context->service_cert_path = NULL;
+    }
+
+    if (ldap_context->service_cert_pass != NULL) {
+	krb5_xfree(ldap_context->service_cert_pass);
+	ldap_context->service_cert_pass = NULL;
+    }
+
+    if (ldap_context->certificates) {
+	i=0;
+	while (ldap_context->certificates[i] != NULL) {
+	    krb5_xfree(ldap_context->certificates[i]->certificate);
+	    krb5_xfree(ldap_context->certificates[i]);
+	    ++i;
+	}
+	krb5_xfree(ldap_context->certificates);
+    }
+
+    return(0);
+}
+
+krb5_error_code
+krb5_ldap_free_server_params(ldap_context)
+    krb5_ldap_context           *ldap_context;
+{
+    if (ldap_context == NULL)
+        return 0;
+
+    krb5_ldap_free_server_context_params(ldap_context);
+
+    k5_mutex_destroy(&ldap_context->hndl_lock);
+    krb5_xfree(ldap_context);
+    return(0);
+}
+
+/*
+ * check to see if the principal belongs to the default realm.
+ * The default realm is present in the krb5_ldap_context structure.
+ * The principal has a realm portion. This realm portion is compared with the default realm
+ * to check whether the principal belong to the default realm.
+ * Return 0 if principal belongs to default realm else 1.
+ */
+
+krb5_error_code
+is_principal_in_realm(ldap_context, searchfor)
+    krb5_ldap_context          *ldap_context;
+    krb5_const_principal       searchfor;
+{
+    size_t                      defrealmlen=0;
+    char                        *defrealm=NULL;
+
+#define FIND_MAX(a,b) ((a) > (b) ? (a) : (b))
+
+    defrealmlen = strlen(ldap_context->lrparams->realm_name);
+    defrealm = ldap_context->lrparams->realm_name;
+
+    /*
+     * Care should be taken for inter-realm principals as the default
+     * realm can exist in the realm part of the principal name or can
+     * also exist in the second portion of the name part.  However, if
+     * the default realm exist in the second part of the principal
+     * portion, then the first portion of the principal name SHOULD be
+     * "krbtgt".  All this check is done in the immediate block.
+     */
+    if (searchfor->length == 2)
+	if ((strncasecmp(searchfor->data[0].data, "krbtgt",
+			 FIND_MAX(searchfor->data[0].length, strlen("krbtgt"))) == 0) &&
+	    (strncasecmp(searchfor->data[1].data, defrealm,
+			 FIND_MAX(searchfor->data[1].length, defrealmlen)) == 0))
+	    return 0;
+
+    /* first check the length, if they are not equal, then they are not same */
+    if (strlen(defrealm) != searchfor->realm.length)
+	return 1;
+
+    /* if the length is equal, check for the contents */
+    if (strncmp(defrealm, searchfor->realm.data,
+		searchfor->realm.length) != 0)
+	return 1;
+    /* if we are here, then the realm portions match, return 0 */
+    return 0;
+}
+
+
+/*
+ * Deduce the subtree information from the context. A realm can have
+ * multiple subtrees.
+ * 1. the Realm container
+ * 2. the actual subtrees associated with the Realm
+ *
+ * However, there are some conditions to be considered to deduce the
+ * actual subtree/s associated with the realm.  The conditions are as
+ * follows:
+ * 1. If the subtree information of the Realm is [Root] or NULL (that
+ *    is internal a [Root]) then the realm has only one subtree
+ *    i.e [Root], i.e. whole of the tree.
+ * 2. If the subtree information of the Realm is missing/absent, then the
+ *    realm has only one, i.e., the Realm container.  NOTE: In all cases
+ *    Realm container SHOULD be the one among the subtrees or the only
+ *    one subtree.
+ * 3. The subtree information of the realm is overlapping the realm
+ *    container of the realm, then the realm has only one subtree and
+ *    it is the subtree information associated with the realm.
+ */
+krb5_error_code
+krb5_get_subtree_info(ldap_context, subtreearr, ntree)
+    krb5_ldap_context           *ldap_context;
+    char                        ***subtreearr;
+    unsigned int                *ntree;
+{
+    int                         st=0, i=0, subtreecount=0;
+    int				ncount=0, search_scope=0;
+    char                        **subtree=NULL, *realm_cont_dn=NULL;
+    char                        **subtarr=NULL;
+    char                        *containerref=NULL;
+    char 			**newsubtree=NULL;
+
+    containerref = ldap_context->lrparams->containerref;
+    subtree = ldap_context->lrparams->subtree;
+    realm_cont_dn = ldap_context->lrparams->realmdn;
+    subtreecount = ldap_context->lrparams->subtreecount;
+    search_scope = ldap_context->lrparams->search_scope;
+
+    subtarr = (char **) malloc(sizeof(char *) * (subtreecount + 1 /*realm dn*/ + 1 /*containerref*/ + 1));
+    if (subtarr == NULL) {
+	st = ENOMEM;
+	goto cleanup;
+    }
+    memset(subtarr, 0, (sizeof(char *) * (subtreecount+1+1+1)));
+
+    /* get the complete subtree list */
+    for (i=0; i<subtreecount && subtree[i]!=NULL; i++) {
+	subtarr[i] = strdup(subtree[i]);
+	if (subtarr[i] == NULL) {
+	    st = ENOMEM;
+	    goto cleanup;
+	}
+    }
+
+    subtarr[i] = strdup(realm_cont_dn);
+    if (subtarr[i++] == NULL) {
+	st = ENOMEM;
+	goto cleanup;
+    }
+
+    if (containerref != NULL) {
+	subtarr[i] = strdup(containerref);
+	if (subtarr[i++] == NULL) {
+	    st = ENOMEM;
+	    goto cleanup;
+	}
+    }
+
+    ncount = i;
+    newsubtree = (char **) malloc(sizeof(char *) * (ncount + 1));
+    if (newsubtree == NULL) {
+        st = ENOMEM;
+        goto cleanup;
+    }
+    memset(newsubtree, 0, (sizeof(char *) * (ncount+1)));
+    if ((st = remove_overlapping_subtrees(subtarr, newsubtree, &ncount,
+		search_scope)) != 0) {
+        goto cleanup;
+    }
+
+    *ntree = ncount;
+    *subtreearr = newsubtree;
+
+cleanup:
+    if (subtarr != NULL) {
+	for (i=0; subtarr[i] != NULL; i++)
+	    free(subtarr[i]);
+	free(subtarr);
+    }
+
+    if (st != 0) {
+        if (newsubtree != NULL) {
+	    for (i=0; newsubtree[i] != NULL; i++)
+	        free(newsubtree[i]);
+	    free(newsubtree);
+        }
+    }
+    return st;
+}
+
+/*
+ * This function appends the content with a type into the tl_data
+ * structure.  Based on the type the length of the content is either
+ * pre-defined or computed from the content.  Returns 0 in case of
+ * success and 1 if the type associated with the content is undefined.
+ */
+
+krb5_error_code
+store_tl_data(tl_data, tl_type, value)
+    krb5_tl_data                *tl_data;
+    int                         tl_type;
+    void                        *value;
+{
+    unsigned int                currlen=0, tldatalen=0;
+    unsigned char               *curr=NULL;
+    void                        *reallocptr=NULL;
+
+    tl_data->tl_data_type = KDB_TL_USER_INFO;
+    switch (tl_type) {
+    case KDB_TL_PRINCCOUNT:
+    case KDB_TL_PRINCTYPE:
+    case KDB_TL_MASK:
+    {
+	int *iptr = (int *)value;
+	int ivalue = *iptr;
+
+	currlen = tl_data->tl_data_length;
+	tl_data->tl_data_length += 1 + 2 + 2;
+	/* allocate required memory */
+	reallocptr = tl_data->tl_data_contents;
+	tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
+					    tl_data->tl_data_length);
+	if (tl_data->tl_data_contents == NULL) {
+	    if (reallocptr)
+		free (reallocptr);
+	    return ENOMEM;
+	}
+	curr = (tl_data->tl_data_contents + currlen);
+
+	/* store the tl_type value */
+	memset(curr, tl_type, 1);
+	curr += 1;
+	/* store the content length */
+	tldatalen = 2;
+	STORE16_INT(curr, tldatalen);
+	curr += 2;
+	/* store the content */
+	STORE16_INT(curr, ivalue);
+	curr += 2;
+	break;
+    }
+
+    case KDB_TL_USERDN:
+    case KDB_TL_LINKDN:
+    {
+	char *cptr = (char *)value;
+
+	currlen = tl_data->tl_data_length;
+	tl_data->tl_data_length += 1 + 2 + strlen(cptr);
+	/* allocate required memory */
+	reallocptr = tl_data->tl_data_contents;
+	tl_data->tl_data_contents = realloc(tl_data->tl_data_contents,
+					    tl_data->tl_data_length);
+	if (tl_data->tl_data_contents == NULL) {
+	    if (reallocptr)
+		free (reallocptr);
+	    return ENOMEM;
+	}
+	curr = (tl_data->tl_data_contents + currlen);
+
+	/* store the tl_type value */
+	memset(curr, tl_type, 1);
+	curr += 1;
+	/* store the content length */
+	tldatalen = strlen(cptr);
+	STORE16_INT(curr, tldatalen);
+	curr += 2;
+	/* store the content */
+	memcpy(curr, cptr, tldatalen);
+	curr += tldatalen;
+	break;
+    }
+
+    default:
+	return 1;
+
+    }
+    return 0;
+}
+
+/*
+ * This function scans the tl_data structure to get the value of a
+ * type defined by the tl_type (second parameter).  The tl_data
+ * structure has all the data in the tl_data_contents member.  The
+ * format of the tl_data_contents is as follows.  The first byte
+ * defines the type of the content that follows.  The next 2 bytes
+ * define the size n (in terms of bytes) of the content that
+ * follows.  The next n bytes define the content itself.
+ */
+
+krb5_error_code
+decode_tl_data(tl_data, tl_type, data)
+    krb5_tl_data                *tl_data;
+    int                         tl_type;
+    void                        **data;
+{
+    int                         subtype=0, i=0, limit=10;
+    unsigned int                sublen=0;
+    unsigned char               *curr=NULL;
+    int                         *intptr=NULL;
+    long                        *longptr=NULL;
+    char                        *DN=NULL, **DNarr=NULL;
+    krb5_error_code             st=-1;
+
+    *data = NULL;
+
+    curr = tl_data->tl_data_contents;
+    while (curr < (tl_data->tl_data_contents + tl_data->tl_data_length)) {
+
+	/* get the type of the content */
+	subtype = (int) curr[0];
+	/* forward by 1 byte*/
+	curr += 1;
+
+	if (subtype == tl_type) {
+	    switch (subtype) {
+
+	    case KDB_TL_PRINCCOUNT:
+	    case KDB_TL_PRINCTYPE:
+	    case KDB_TL_MASK:
+		/* get the length of the content */
+		UNSTORE16_INT(curr, sublen);
+		/* forward by 2 bytes */
+		curr += 2;
+		/* get the actual content */
+		if (sublen == 2) {
+		    /* intptr = malloc(sublen);	  */
+		    intptr = malloc(sizeof(krb5_int32));
+		    if (intptr == NULL)
+			return ENOMEM;
+		    memset(intptr, 0, sublen);
+		    UNSTORE16_INT(curr, (*intptr));
+		    *data = intptr;
+		} else {
+		    longptr = malloc(sublen);
+		    if (longptr == NULL)
+			return ENOMEM;
+		    memset(longptr, 0, sublen);
+		    UNSTORE32_INT(curr, (*longptr));
+		    *data = longptr;
+		}
+		curr += sublen;
+		st = 0;
+		return st;
+		break;
+
+	    case KDB_TL_CONTAINERDN:
+	    case KDB_TL_USERDN:
+		/* get the length of the content */
+		UNSTORE16_INT(curr, sublen);
+		/* forward by 2 bytes */
+		curr += 2;
+		DN = malloc (sublen + 1);
+		if (DN == NULL)
+		    return ENOMEM;
+		memcpy(DN, curr, sublen);
+		DN[sublen] = 0;
+		*data = DN;
+		curr += sublen;
+		st = 0;
+		return st;
+		break;
+
+	    case KDB_TL_LINKDN:
+		if (DNarr == NULL) {
+		    DNarr = calloc(limit, sizeof(char *));
+		    if (DNarr == NULL)
+			return ENOMEM;
+		}
+		if (i == limit-1) {
+		    limit *= 2;
+		    DNarr = realloc(DNarr, sizeof(char *) * (limit));
+		    if (DNarr == NULL)
+			return ENOMEM;
+		}
+
+		/* get the length of the content */
+		UNSTORE16_INT(curr, sublen);
+		/* forward by 2 bytes */
+		curr += 2;
+		DNarr[i] = malloc (sublen + 1);
+		if (DNarr[i] == NULL)
+		    return ENOMEM;
+		memcpy(DNarr[i], curr, sublen);
+		DNarr[i][sublen] = 0;
+		++i;
+		curr += sublen;
+		*data = DNarr;
+		st=0;
+		break;
+	    }
+	} else {
+	    /* move to the current content block */
+	    UNSTORE16_INT(curr, sublen);
+	    curr += 2 + sublen;
+	}
+    }
+    return st;
+}
+
+/*
+ * wrapper routines for decode_tl_data
+ */
+static krb5_error_code
+krb5_get_int_from_tl_data(context, entries, type, intval)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    int                         type;
+    int                         *intval;
+{
+    krb5_error_code             st=0;
+    krb5_tl_data                tl_data;
+    void                        *voidptr=NULL;
+    int                         *intptr=NULL;
+
+    tl_data.tl_data_type = KDB_TL_USER_INFO;
+    if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
+	goto cleanup;
+
+    if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
+	intptr = (int *) voidptr;
+	*intval = *intptr;
+	free(intptr);
+    }
+
+cleanup:
+    return st;
+}
+
+/*
+ * Get the mask representing the attributes set on the directory
+ * object (user, policy ...).
+ */
+krb5_error_code
+krb5_get_attributes_mask(context, entries, mask)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    int                         *mask;
+{
+    return krb5_get_int_from_tl_data(context, entries, KDB_TL_MASK, mask);
+}
+
+krb5_error_code
+krb5_get_princ_type(context, entries, ptype)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    int                         *ptype;
+{
+    return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCTYPE, ptype);
+}
+
+krb5_error_code
+krb5_get_princ_count(context, entries, pcount)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    int                         *pcount;
+{
+    return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCCOUNT, pcount);
+}
+
+krb5_error_code
+krb5_get_linkdn(context, entries, link_dn)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    char                        ***link_dn;
+{
+    krb5_error_code             st=0;
+    krb5_tl_data                tl_data;
+    void                        *voidptr=NULL;
+
+    *link_dn = NULL;
+    tl_data.tl_data_type = KDB_TL_USER_INFO;
+    if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
+	goto cleanup;
+
+    if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &voidptr) == 0) {
+	*link_dn = (char **) voidptr;
+    }
+
+cleanup:
+    return st;
+}
+
+static krb5_error_code
+krb5_get_str_from_tl_data(context, entries, type, strval)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    int                         type;
+    char                        **strval;
+{
+    krb5_error_code             st=0;
+    krb5_tl_data                tl_data;
+    void                        *voidptr=NULL;
+
+    if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN) {
+	st = EINVAL;
+	goto cleanup;
+    }
+
+    tl_data.tl_data_type = KDB_TL_USER_INFO;
+    if (((st=krb5_dbe_lookup_tl_data(context, entries, &tl_data)) != 0) || tl_data.tl_data_length == 0)
+	goto cleanup;
+
+    if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
+	*strval = (char *) voidptr;
+    }
+
+cleanup:
+    return st;
+}
+
+krb5_error_code
+krb5_get_userdn(context, entries, userdn)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    char                        **userdn;
+{
+    *userdn = NULL;
+    return krb5_get_str_from_tl_data(context, entries, KDB_TL_USERDN, userdn);
+}
+
+krb5_error_code
+krb5_get_containerdn(context, entries, containerdn)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    char                        **containerdn;
+{
+    *containerdn = NULL;
+    return krb5_get_str_from_tl_data(context, entries, KDB_TL_CONTAINERDN, containerdn);
+}
+
+/*
+ * This function reads the attribute values (if the attribute is
+ * non-null) from the dn.  The read attribute values is compared
+ * aganist the attrvalues passed to the function and a bit mask is set
+ * for all the matching attributes (attributes existing in both list).
+ * The bit to be set is selected such that the index of the attribute
+ * in the attrvalues parameter is the position of the bit.  For ex:
+ * the first element in the attrvalues is present in both list shall
+ * set the LSB of the bit mask.
+ *
+ * In case if either the attribute or the attrvalues parameter to the
+ * function is NULL, then the existence of the object is considered
+ * and appropriate status is returned back.
+ */
+
+krb5_error_code
+checkattributevalue (ld, dn, attribute, attrvalues, mask)
+    LDAP                        *ld;
+    char                        *dn;
+    char                        *attribute;
+    char                        **attrvalues;
+    int                         *mask;
+{
+    int                         st=0, one=1;
+    char                        **values=NULL, *attributes[2] = {NULL};
+    LDAPMessage                 *result=NULL, *entry=NULL;
+
+    if (strlen(dn) == 0) {
+	st = set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH);
+	return st;
+    }
+
+    attributes[0] = attribute;
+
+    /* read the attribute values from the dn */
+    if ((st = ldap_search_ext_s(ld,
+				dn,
+				LDAP_SCOPE_BASE,
+				0,
+				attributes,
+				0,
+				NULL,
+				NULL,
+				&timelimit,
+				LDAP_NO_LIMIT,
+				&result)) != LDAP_SUCCESS) {
+	st = set_ldap_error(0, st, OP_SEARCH);
+	return st;
+    }
+
+    /*
+     * If the attribute/attrvalues is NULL, then check for the
+     * existence of the object alone.
+     */
+    if (attribute == NULL || attrvalues == NULL)
+	goto cleanup;
+
+    /* reset the bit mask */
+    *mask = 0;
+
+    if ((entry=ldap_first_entry(ld, result)) != NULL) {
+	/* read the attribute values */
+	if ((values=ldap_get_values(ld, entry, attribute)) != NULL) {
+	    int i,j;
+
+	    /*
+	     * Compare the read attribute values with the attrvalues
+	     * array and set the appropriate bit mask.
+	     */
+	    for (j=0; attrvalues[j]; ++j) {
+		for (i=0; values[i]; ++i) {
+		    if (strcasecmp(values[i], attrvalues[j]) == 0) {
+			*mask |= (one<<j);
+			break;
+		    }
+		}
+	    }
+	    ldap_value_free(values);
+	}
+    }
+
+cleanup:
+    ldap_msgfree(result);
+    return st;
+}
+
+
+/*
+ * This function updates a single attribute with a single value of a
+ * specified dn.  This function is mainly used to update
+ * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
+ * ADMIN, PASSWD servers are associated with some realms or vice
+ * versa.
+ */
+
+krb5_error_code
+updateAttribute (ld, dn, attribute, value)
+    LDAP                        *ld;
+    char                        *dn;
+    char                        *attribute;
+    char                        *value;
+{
+    int                         st=0;
+    LDAPMod                     modAttr, *mods[2]={NULL};
+    char                        *values[2]={NULL};
+
+    values[0] = value;
+
+    /* data to update the {attr,attrval} combination */
+    memset(&modAttr, 0, sizeof(modAttr));
+    modAttr.mod_type = attribute;
+    modAttr.mod_op = LDAP_MOD_ADD;
+    modAttr.mod_values = values;
+    mods[0] = &modAttr;
+
+    /* ldap modify operation */
+    st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
+
+    /* if the {attr,attrval} combination is already present return a success
+     * LDAP_ALREADY_EXISTS is for single-valued attribute
+     * LDAP_TYPE_OR_VALUE_EXISTS is for multi-valued attribute
+     */
+    if (st == LDAP_ALREADY_EXISTS || st == LDAP_TYPE_OR_VALUE_EXISTS)
+	st = 0;
+
+    if (st != 0) {
+	st = set_ldap_error (0, st, OP_MOD);
+    }
+
+    return st;
+}
+
+/*
+ * This function deletes a single attribute with a single value of a
+ * specified dn.  This function is mainly used to delete
+ * krbRealmReferences, krbKdcServers, krbAdminServers... when KDC,
+ * ADMIN, PASSWD servers are disassociated with some realms or vice
+ * versa.
+ */
+
+krb5_error_code
+deleteAttribute (ld, dn, attribute, value)
+    LDAP                        *ld;
+    char                        *dn;
+    char                        *attribute;
+    char                        *value;
+{
+    krb5_error_code             st=0;
+    LDAPMod                     modAttr, *mods[2]={NULL};
+    char                        *values[2]={NULL};
+
+    values[0] = value;
+
+    /* data to delete the {attr,attrval} combination */
+    memset(&modAttr, 0, sizeof(modAttr));
+    modAttr.mod_type = attribute;
+    modAttr.mod_op = LDAP_MOD_DELETE;
+    modAttr.mod_values = values;
+    mods[0] = &modAttr;
+
+    /* ldap modify operation */
+    st = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
+
+    /* if either the attribute or the attribute value is missing return a success */
+    if (st == LDAP_NO_SUCH_ATTRIBUTE || st == LDAP_UNDEFINED_TYPE)
+	st = 0;
+
+    if (st != 0) {
+	st = set_ldap_error (0, st, OP_MOD);
+    }
+
+    return st;
+}
+
+
+/*
+ * This function takes in 2 string arrays, compares them to remove the
+ * matching entries.  The first array is the original list and the
+ * second array is the modified list.  Removing the matching entries
+ * will result in a reduced array, where the left over first array
+ * elements are the deleted entries and the left over second array
+ * elements are the added entries.  These additions and deletions has
+ * resulted in the modified second array.
+ */
+
+krb5_error_code
+disjoint_members(src, dest)
+    char                        **src;
+    char                        **dest;
+{
+    int                         i=0, j=0, slen=0, dlen=0;
+
+    /* validate the input parameters */
+    if (src == NULL || dest == NULL)
+	return 0;
+
+    /* compute the first array length */
+    for (i=0;src[i]; ++i)
+	;
+
+    /* return if the length is 0 */
+    if (i==0)
+	return 0;
+
+    /* index of the last element and also the length of the array */
+    slen = i-1;
+
+    /* compute the second array length */
+    for (i=0;dest[i]; ++i)
+	;
+
+    /* return if the length is 0 */
+    if (i==0)
+	return 0;
+
+    /* index of the last element and also the length of the array */
+    dlen = i-1;
+
+    /* check for the similar elements and delete them from both the arrays */
+    for (i=0; src[i]; ++i) {
+
+	for (j=0; dest[j]; ++j) {
+
+	    /* if the element are same */
+	    if (strcasecmp(src[i], dest[j]) == 0) {
+		/*
+		 * If the matched element is in the middle, then copy
+		 * the last element to the matched index.
+		 */
+		if (i != slen) {
+		    free (src[i]);
+		    src[i] = src[slen];
+		    src[slen] = NULL;
+		} else {
+		    /*
+		     * If the matched element is the last, free it and
+		     * set it to NULL.
+		     */
+		    free (src[i]);
+		    src[i] = NULL;
+		}
+		/* reduce the array length by 1 */
+		slen -= 1;
+
+		/* repeat the same processing for the second array too */
+		if (j != dlen) {
+		    free(dest[j]);
+		    dest[j] = dest[dlen];
+		    dest[dlen] = NULL;
+		} else {
+		    free(dest[j]);
+		    dest[j] = NULL;
+		}
+		dlen -=1;
+
+		/*
+		 * The source array is reduced by 1, so reduce the
+		 * index variable used for source array by 1.  No need
+		 * to adjust the second array index variable as it is
+		 * reset while entering the inner loop.
+		 */
+		i -= 1;
+		break;
+	    }
+	}
+    }
+    return 0;
+}
+
+/*
+ * This function replicates the contents of the src array for later
+ * use. Mostly the contents of the src array is obtained from a
+ * ldap_search operation and the contents are required for later use.
+ */
+
+krb5_error_code
+copy_arrays(src, dest, count)
+    char                        **src;
+    char                        ***dest;
+    int                         count;
+{
+    krb5_error_code             st=0;
+    int                         i=0;
+
+    /* validate the input parameters */
+    if (src == NULL || dest == NULL)
+	return 0;
+
+    /* allocate memory for the dest array */
+    *dest = (char **) calloc((unsigned) count+1, sizeof(char *));
+    if (*dest == NULL) {
+	st = ENOMEM;
+	goto cleanup;
+    }
+
+    /* copy the members from src to dest array. */
+    for (i=0; i < count && src[i] != NULL; ++i) {
+	(*dest)[i] = strdup(src[i]);
+	if ((*dest)[i] == NULL) {
+	    st = ENOMEM;
+	    goto cleanup;
+	}
+    }
+
+cleanup:
+    /* in case of error free up everything and return */
+    if (st != 0) {
+	if (*dest != NULL) {
+	    for (i=0; (*dest)[i]; ++i) {
+		free ((*dest)[i]);
+		(*dest)[i] = NULL;
+	    }
+	    free (*dest);
+	    *dest = NULL;
+	}
+    }
+    return st;
+}
+
+static krb5_error_code
+getepochtime(strtime, epochtime)
+    char              *strtime;
+    krb5_timestamp    *epochtime;
+{
+    struct tm           tme;
+
+    memset(&tme, 0, sizeof(tme));
+    if (strptime(strtime,"%Y%m%d%H%M%SZ", &tme) == NULL) {
+	*epochtime = 0;
+	return EINVAL;
+    }
+    *epochtime = krb5int_gmt_mktime(&tme);
+    return 0;
+}
+
+/*
+ * krb5_ldap_get_value() - get the integer value of the attribute
+ * Returns, 0 if the attribute is present, 1 if the attribute is missing.
+ * The retval is 0 if the attribute is missing.
+ */
+
+krb5_error_code
+krb5_ldap_get_value(ld, ent, attribute, retval)
+    LDAP                        *ld;
+    LDAPMessage                 *ent;
+    char                        *attribute;
+    int                         *retval;
+{
+    char                           **values=NULL;
+
+    *retval = 0;
+    values=ldap_get_values(ld, ent, attribute);
+    if (values != NULL) {
+	if (values[0] != NULL)
+	    *retval = atoi(values[0]);
+	ldap_value_free(values);
+	return 0;
+    }
+    return 1;
+}
+
+/*
+ * krb5_ldap_get_string() - Returns the first string of the
+ * attribute.  Intended to
+ *
+ *
+ */
+krb5_error_code
+krb5_ldap_get_string(ld, ent, attribute, retstr, attr_present)
+    LDAP                        *ld;
+    LDAPMessage                 *ent;
+    char                        *attribute;
+    char                        **retstr;
+    krb5_boolean                *attr_present;
+{
+    char                           **values=NULL;
+    krb5_error_code                st=0;
+
+    *retstr = NULL;
+    if (attr_present != NULL)
+	*attr_present = FALSE;
+
+    values=ldap_get_values(ld, ent, attribute);
+    if (values != NULL) {
+	if (values[0] != NULL) {
+	    if (attr_present!= NULL)
+		*attr_present = TRUE;
+	    *retstr = strdup(values[0]);
+	    if (*retstr == NULL)
+		st = ENOMEM;
+	}
+	ldap_value_free(values);
+    }
+    return st;
+}
+
+/*
+ * krb5_ldap_get_strings() - Returns all the values
+ * of the attribute.
+ */
+krb5_error_code
+krb5_ldap_get_strings(ld, ent, attribute, retarr, attr_present)
+    LDAP                        *ld;
+    LDAPMessage                 *ent;
+    char                        *attribute;
+    char                        ***retarr;
+    krb5_boolean                *attr_present;
+{
+    char                        **values=NULL;
+    krb5_error_code             st=0;
+    unsigned int                i=0, count=0;
+
+    *retarr = NULL;
+    if (attr_present != NULL)
+	*attr_present = FALSE;
+
+    values=ldap_get_values(ld, ent, attribute);
+    if (values != NULL) {
+	if (attr_present != NULL)
+	    *attr_present = TRUE;
+
+	count = ldap_count_values(values);
+	*retarr  = (char **) calloc(count+1, sizeof(char *));
+	if (*retarr == NULL) {
+	    st = ENOMEM;
+	    return st;
+	}
+	for (i=0; i< count; ++i) {
+	    (*retarr)[i] = strdup(values[i]);
+	    if ((*retarr)[i] == NULL) {
+		st = ENOMEM;
+		goto cleanup;
+	    }
+	}
+	ldap_value_free(values);
+    }
+
+cleanup:
+    if (st != 0) {
+	if (*retarr != NULL) {
+	    for (i=0; i< count; ++i)
+		if ((*retarr)[i] != NULL)
+		    free ((*retarr)[i]);
+	    free (*retarr);
+	}
+    }
+    return st;
+}
+
+krb5_error_code
+krb5_ldap_get_time(ld, ent, attribute, rettime, attr_present)
+    LDAP                        *ld;
+    LDAPMessage                 *ent;
+    char                        *attribute;
+    krb5_timestamp              *rettime;
+    krb5_boolean                *attr_present;
+{
+    char                         **values=NULL;
+    krb5_error_code              st=0;
+
+    *rettime = 0;
+    *attr_present = FALSE;
+
+    values=ldap_get_values(ld, ent, attribute);
+    if (values != NULL) {
+	if (values[0] != NULL) {
+	    *attr_present = TRUE;
+	    st = getepochtime(values[0], rettime);
+	}
+	ldap_value_free(values);
+    }
+    return st;
+}
+
+/*
+ * Function to allocate, set the values of LDAPMod structure. The
+ * LDAPMod structure is then added to the array at the ind
+ */
+
+krb5_error_code
+krb5_add_member(mods, count)
+    LDAPMod          ***mods;
+    int              *count;
+{
+    int i=0;
+    LDAPMod **lmods=NULL;
+
+    if ((*mods) != NULL) {
+	for (;(*mods)[i] != NULL; ++i)
+	    ;
+    }
+    lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *));
+    if (lmods == NULL)
+	return ENOMEM;
+
+    *mods = lmods;
+    (*mods)[i+1] = NULL;
+    (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod));
+    if ((*mods)[i] == NULL)
+	return ENOMEM;
+    *count = i;
+    return 0;
+}
+
+krb5_error_code
+krb5_add_str_mem_ldap_mod(mods, attribute, op, values)
+    LDAPMod  ***mods;
+    char     *attribute;
+    int      op;
+    char     **values;
+
+{
+    int i=0, j=0;
+    krb5_error_code   st=0;
+
+    if ((st=krb5_add_member(mods, &i)) != 0)
+	return st;
+
+    (*mods)[i]->mod_type = strdup(attribute);
+    if ((*mods)[i]->mod_type == NULL)
+	return ENOMEM;
+    (*mods)[i]->mod_op = op;
+
+    (*mods)[i]->mod_values = NULL;
+
+    if (values != NULL) {
+	for (j=0; values[j] != NULL; ++j)
+	    ;
+	(*mods)[i]->mod_values = malloc (sizeof(char *) * (j+1));
+	if ((*mods)[i]->mod_values == NULL)
+	    return ENOMEM;
+
+	for (j=0; values[j] != NULL; ++j) {
+	    (*mods)[i]->mod_values[j] = strdup(values[j]);
+	    if ((*mods)[i]->mod_values[j] == NULL)
+		return ENOMEM;
+	}
+	(*mods)[i]->mod_values[j] = NULL;
+    }
+    return 0;
+}
+
+krb5_error_code
+krb5_add_ber_mem_ldap_mod(mods, attribute, op, ber_values)
+    LDAPMod  ***mods;
+    char     *attribute;
+    int      op;
+    struct berval **ber_values;
+
+{
+    int i=0, j=0;
+    krb5_error_code   st=0;
+
+    if ((st=krb5_add_member(mods, &i)) != 0)
+	return st;
+
+    (*mods)[i]->mod_type = strdup(attribute);
+    if ((*mods)[i]->mod_type == NULL)
+	return ENOMEM;
+    (*mods)[i]->mod_op = op;
+
+    for (j=0; ber_values[j] != NULL; ++j)
+	;
+    (*mods)[i]->mod_bvalues = malloc (sizeof(struct berval *) * (j+1));
+    if ((*mods)[i]->mod_bvalues == NULL)
+	return ENOMEM;
+
+    for (j=0; ber_values[j] != NULL; ++j) {
+	(*mods)[i]->mod_bvalues[j] = calloc(1, sizeof(struct berval));
+	if ((*mods)[i]->mod_bvalues[j] == NULL)
+	    return ENOMEM;
+
+	(*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len;
+	(*mods)[i]->mod_bvalues[j]->bv_val = malloc((*mods)[i]->mod_bvalues[j]->bv_len);
+	if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL)
+	    return ENOMEM;
+
+	memcpy((*mods)[i]->mod_bvalues[j]->bv_val, ber_values[j]->bv_val,
+	       ber_values[j]->bv_len);
+    }
+    (*mods)[i]->mod_bvalues[j] = NULL;
+    return 0;
+}
+
+static inline char *
+format_d (int val)
+{
+    char tmpbuf[2+3*sizeof(val)];
+    snprintf(tmpbuf, sizeof(tmpbuf), "%d", val);
+    return strdup(tmpbuf);
+}
+
+krb5_error_code
+krb5_add_int_arr_mem_ldap_mod(mods, attribute, op, value)
+    LDAPMod  ***mods;
+    char     *attribute;
+    int      op;
+    int      *value;
+
+{
+    int i=0, j=0;
+    krb5_error_code   st=0;
+
+    if ((st=krb5_add_member(mods, &i)) != 0)
+	return st;
+
+    (*mods)[i]->mod_type = strdup(attribute);
+    if ((*mods)[i]->mod_type == NULL)
+	return ENOMEM;
+    (*mods)[i]->mod_op = op;
+
+    for (j=0; value[j] != -1; ++j)
+	;
+
+    (*mods)[i]->mod_values = malloc(sizeof(char *) * (j+1));
+
+    for (j=0; value[j] != -1; ++j) {
+	if (((*mods)[i]->mod_values[j] = format_d(value[j])) == NULL)
+	    return ENOMEM;
+    }
+    (*mods)[i]->mod_values[j] = NULL;
+    return 0;
+}
+
+krb5_error_code
+krb5_add_int_mem_ldap_mod(mods, attribute, op, value)
+    LDAPMod  ***mods;
+    char     *attribute;
+    int      op;
+    int      value;
+
+{
+    int i=0;
+    krb5_error_code      st=0;
+
+    if ((st=krb5_add_member(mods, &i)) != 0)
+	return st;
+
+    (*mods)[i]->mod_type = strdup(attribute);
+    if ((*mods)[i]->mod_type == NULL)
+	return ENOMEM;
+
+    (*mods)[i]->mod_op = op;
+    (*mods)[i]->mod_values = calloc (2, sizeof(char *));
+    if (((*mods)[i]->mod_values[0] = format_d(value)) == NULL)
+	return ENOMEM;
+    return 0;
+}
+
+krb5_error_code
+krb5_ldap_set_option(krb5_context kcontext, int option, void *value)
+{
+    krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
+    krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
+    return status;
+}
+
+krb5_error_code
+krb5_ldap_lock(krb5_context kcontext, int mode)
+{
+    krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
+    krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
+    return status;
+}
+
+krb5_error_code
+krb5_ldap_unlock(krb5_context kcontext)
+{
+    krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
+    krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
+    return status;
+}
+
+krb5_error_code
+krb5_ldap_supported_realms(krb5_context kcontext, char **realms)
+{
+    krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
+    krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
+    return status;
+}
+
+krb5_error_code
+krb5_ldap_free_supported_realms(krb5_context kcontext, char **realms)
+{
+    krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
+    krb5_set_error_message(kcontext, status, "LDAP %s", error_message(status));
+    return status;
+}
+
+const char *
+krb5_ldap_errcode_2_string(krb5_context kcontext, long err_code)
+{
+    return krb5_get_error_message(kcontext, err_code);
+}
+
+void
+krb5_ldap_release_errcode_string(krb5_context kcontext, const char *msg)
+{
+    krb5_free_error_message(kcontext, msg);
+}
+
+
+/*
+ * Get the number of times an object has been referred to in a realm. this is
+ * needed to find out if deleting the attribute will cause dangling links.
+ *
+ * An LDAP handle may be optionally specified to prevent race condition - there
+ * are a limited number of LDAP handles.
+ */
+krb5_error_code
+krb5_ldap_get_reference_count (krb5_context context, char *dn, char *refattr,
+			       int *count, LDAP *ld)
+{
+    int                         st = 0, tempst = 0, gothandle = 0;
+    unsigned int		i, ntrees;
+    char                        *refcntattr[2];
+    char                        *filter = NULL;
+    char                        **subtree = NULL, *ptr = NULL;
+    kdb5_dal_handle             *dal_handle = NULL;
+    krb5_ldap_context           *ldap_context = NULL;
+    krb5_ldap_server_handle     *ldap_server_handle = NULL;
+    LDAPMessage                 *result = NULL;
+
+
+    if (dn == NULL || refattr == NULL) {
+	st = EINVAL;
+	goto cleanup;
+    }
+
+    SETUP_CONTEXT();
+    if (ld == NULL) {
+	GET_HANDLE();
+	gothandle = 1;
+    }
+
+    refcntattr [0] = refattr;
+    refcntattr [1] = NULL;
+
+    ptr = ldap_filter_correct (dn);
+    if (ptr == NULL) {
+	st = ENOMEM;
+	goto cleanup;
+    }
+
+    if (asprintf (&filter, "%s=%s", refattr, ptr) < 0) {
+	filter = NULL;
+	st = ENOMEM;
+	goto cleanup;
+    }
+
+    if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
+	goto cleanup;
+
+    for (i = 0, *count = 0; i < ntrees; i++) {
+	int n;
+
+	LDAP_SEARCH(subtree[i],
+		    LDAP_SCOPE_SUBTREE,
+		    filter,
+		    refcntattr);
+	n = ldap_count_entries (ld, result);
+	if (n == -1) {
+	    int ret, errcode = 0;
+	    ret = ldap_parse_result (ld, result, &errcode, NULL, NULL, NULL, NULL, 0);
+	    if (ret != LDAP_SUCCESS)
+		errcode = ret;
+	    st = translate_ldap_error (errcode, OP_SEARCH);
+	    goto cleanup;
+	}
+
+	ldap_msgfree(result);
+	result = NULL;
+
+	*count += n;
+    }
+
+cleanup:
+    if (filter != NULL)
+	free (filter);
+
+    if (result != NULL)
+	ldap_msgfree (result);
+
+    if (subtree != NULL) {
+	for (i = 0; i < ntrees; i++)
+	    free (subtree[i]);
+	free (subtree);
+    }
+
+    if (ptr != NULL)
+	free (ptr);
+
+    if (gothandle == 1)
+	krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
+
+    return st;
+}
+
+/*
+ * For now, policy objects are expected to be directly under the realm
+ * container.
+ */
+krb5_error_code krb5_ldap_policydn_to_name (context, policy_dn, name)
+    krb5_context                context;
+    char                        *policy_dn;
+    char                        **name;
+{
+    int len1, len2;
+    krb5_error_code             st = 0;
+    kdb5_dal_handle             *dal_handle=NULL;
+    krb5_ldap_context           *ldap_context=NULL;
+
+    SETUP_CONTEXT();
+
+    if (ldap_context->lrparams->realmdn == NULL) {
+	st = EINVAL;
+	goto cleanup;
+    }
+
+    len1 = strlen (ldap_context->lrparams->realmdn);
+    len2 = strlen (policy_dn);
+    if (len1 == 0 || len2 == 0 || len1 > len2) {
+	st = EINVAL;
+	goto cleanup;
+    }
+
+    if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) {
+	st = EINVAL;
+	goto cleanup;
+    }
+
+#if defined HAVE_LDAP_STR2DN
+    {
+	char *rdn;
+	LDAPDN dn;
+	rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */
+
+	if (ldap_str2dn (rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC) != 0) {
+	    st = EINVAL;
+	    goto cleanup;
+	}
+	if (dn[0] == NULL || dn[1] != NULL)
+	    st = EINVAL;
+	else if (strcasecmp (dn[0][0]->la_attr.bv_val, "cn") != 0)
+	    st = EINVAL;
+	else {
+	    *name = strndup(dn[0][0]->la_value.bv_val, dn[0][0]->la_value.bv_len);
+	    if (*name == NULL)
+		st = EINVAL;
+	}
+
+	ldap_memfree (dn);
+    }
+#elif defined HAVE_LDAP_EXPLODE_DN
+    {
+	char **parsed_dn;
+
+	/* 1 = return DN components without type prefix */
+	parsed_dn = ldap_explode_dn(policy_dn, 1);
+	if (parsed_dn == NULL) {
+	    st = EINVAL;
+	} else {
+	    *name = strdup(parsed_dn[0]);
+	    if (*name == NULL)
+		st = EINVAL;
+
+	    ldap_value_free(parsed_dn);
+	}
+    }
+#else
+    st = EINVAL;
+#endif
+
+cleanup:
+    return st;
+}
+
+krb5_error_code krb5_ldap_name_to_policydn (context, name, policy_dn)
+    krb5_context                context;
+    char                        *name;
+    char                        **policy_dn;
+{
+    int                         len;
+    char                        *ptr = NULL;
+    krb5_error_code             st = 0;
+    kdb5_dal_handle             *dal_handle=NULL;
+    krb5_ldap_context           *ldap_context=NULL;
+
+    *policy_dn = NULL;
+
+    /* validate the input parameters */
+    if (name == NULL) {
+	st = EINVAL;
+	goto cleanup;
+    }
+
+    /* Used for removing policy reference from an object */
+    if (name[0] == '\0') {
+	if ((*policy_dn = strdup ("")) == NULL)
+	    st = ENOMEM;
+	goto cleanup;
+    }
+
+    SETUP_CONTEXT();
+
+    if (ldap_context->lrparams->realmdn == NULL) {
+	st = EINVAL;
+	goto cleanup;
+    }
+    len = strlen (ldap_context->lrparams->realmdn);
+
+    ptr = ldap_filter_correct (name);
+    if (ptr == NULL) {
+	st = ENOMEM;
+	goto cleanup;
+    }
+    len += strlen (ptr);
+
+    len += sizeof ("cn=") + 3;
+
+    *policy_dn = (char *) malloc (len);
+    if (*policy_dn == NULL) {
+	st = ENOMEM;
+	goto cleanup;
+    }
+
+    sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn);
+
+cleanup:
+    if (ptr != NULL)
+	free (ptr);
+    return st;
+}
+
+/* remove overlapping and repeated subtree entries from the list of subtrees */
+static krb5_error_code
+remove_overlapping_subtrees(char **listin, char **listop, int *subtcount, int sscope)
+{
+    int     slen=0, k=0, j=0, lendiff=0;
+    int     count = *subtcount;
+    char    **subtree = listop;
+
+    slen = count-1;
+    for (k=0; k<=slen && listin[k]!=NULL ; k++) {
+	for (j=k+1; j<=slen && listin[j]!=NULL ;j++) {
+	    lendiff = strlen(listin[k]) - strlen(listin[j]);
+	    if (sscope == 2) {
+		if ((lendiff > 0) && (strcasecmp((listin[k])+lendiff, listin[j])==0)) {
+		    if (k != slen) {
+			free(listin[k]);
+			listin[k] = listin[slen];
+			listin[slen] = NULL;
+		    } else {
+			free(listin[k]);
+			listin[k] = NULL;
+		    }
+		    slen-=1;
+		    k-=1;
+		    break;
+		} else if ((lendiff < 0) && (strcasecmp((listin[j])+abs(lendiff), listin[k])==0)) {
+		    if (j != slen) {
+			free(listin[j]);
+			listin[j] = listin[slen];
+			listin[slen]=NULL;
+		    } else {
+			free(listin[j]);
+			listin[j] = NULL;
+		    }
+		    slen-=1;
+		    j-=1;
+		}
+	    }
+	    if ((lendiff == 0) && (strcasecmp(listin[j], listin[k])==0)) {
+		if (j != slen) {
+		    free(listin[j]);
+		    listin[j] = listin[slen];
+		    listin[slen]=NULL;
+		} else {
+		    free(listin[j]);
+		    listin[j] = NULL;
+		}
+		slen -=1;
+		j-=1;
+	    }
+	}
+    }
+    *subtcount=slen+1;
+    for (k=0; k<*subtcount && listin[k]!=NULL; k++) {
+	subtree[k] = strdup(listin[k]);
+	if (subtree[k] == NULL) {
+	    return ENOMEM;
+	}
+    }
+    return 0;
+}
+
+/*
+ * Fill out a krb5_db_entry princ entry struct given a LDAP message containing
+ * the results of a principal search of the directory.
+ */
+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)
+{
+    krb5_error_code st = 0;
+    unsigned int    mask = 0;
+    krb5_boolean    attr_present = FALSE;
+    char            **values = NULL, *policydn = NULL, *pwdpolicydn = NULL;
+    char            *polname = NULL, *tktpolname = NULL;
+    struct berval   **bvalues = NULL;
+    krb5_tl_data    userinfo_tl_data = {0};
+    char            **link_references = NULL;
+    char *DN = NULL;
+
+    if (princ == NULL) {
+	/* XXX WAF probably should just extract princ from ldap result */
+	st = EINVAL;
+	goto cleanup;
+    } else {
+	if ((st=krb5_copy_principal(context, princ, &(entry->princ))) != 0)
+	    goto cleanup;
+    }
+    /* get the associated directory user information */
+    if ((values = ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
+	int i, pcount=0, kerberos_principal_object_type=0;
+	char *user;
+
+	if ((st=krb5_unparse_name(context, princ, &user)) != 0)
+	    goto cleanup;
+
+	for (i=0; values[i] != NULL; ++i) {
+	    if (strcasecmp(values[i], user) == 0) {
+		pcount = ldap_count_values(values);
+		break;
+	    }
+	}
+	ldap_value_free(values);
+	free(user);
+
+	if ((DN = ldap_get_dn(ld, ent)) == NULL) {
+	    ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &st);
+	    st = set_ldap_error(context, st, 0);
+	    goto cleanup;
+	}
+
+	if ((values=ldap_get_values(ld, ent, "objectclass")) != NULL) {
+	    for (i=0; values[i] != NULL; ++i)
+		if (strcasecmp(values[i], "krbprincipal") == 0) {
+		    kerberos_principal_object_type = KDB_STANDALONE_PRINCIPAL_OBJECT;
+		    if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE,
+				&kerberos_principal_object_type)) != 0)
+			goto cleanup;
+		    break;
+		}
+	    ldap_value_free(values);
+	}
+
+	/* add principalcount, DN and principaltype user information to tl_data */
+	if (((st=store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount)) != 0) ||
+	    ((st=store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, DN)) != 0))
+	    goto cleanup;
+    }
+
+    /* read all the kerberos attributes */
+
+    /* KRBLASTSUCCESSFULAUTH */
+    if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth",
+		&(entry->last_success), &attr_present)) != 0)
+	goto cleanup;
+    if (attr_present == TRUE)
+	mask |= KDB_LAST_SUCCESS_ATTR;
+
+    /* KRBLASTFAILEDAUTH */
+    if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth",
+		&(entry->last_failed), &attr_present)) != 0)
+	goto cleanup;
+    if (attr_present == TRUE)
+	mask |= KDB_LAST_FAILED_ATTR;
+
+    /* KRBLOGINFAILEDCOUNT */
+    if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount",
+	    &(entry->fail_auth_count)) == 0)
+	mask |= KDB_FAIL_AUTH_COUNT_ATTR;
+
+    /* KRBMAXTICKETLIFE */
+    if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entry->max_life)) == 0)
+	mask |= KDB_MAX_LIFE_ATTR;
+
+    /* KRBMAXRENEWABLEAGE */
+    if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage",
+	    &(entry->max_renewable_life)) == 0)
+	mask |= KDB_MAX_RLIFE_ATTR;
+
+    /* KRBTICKETFLAGS */
+    if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entry->attributes)) == 0)
+	mask |= KDB_TKT_FLAGS_ATTR;
+
+    /* PRINCIPAL EXPIRATION TIME */
+    if ((st=krb5_ldap_get_time(ld, ent, "krbprincipalexpiration", &(entry->expiration),
+		&attr_present)) != 0)
+	goto cleanup;
+    if (attr_present == TRUE)
+	mask |= KDB_PRINC_EXPIRE_TIME_ATTR;
+
+    /* PASSWORD EXPIRATION TIME */
+    if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entry->pw_expiration),
+		&attr_present)) != 0)
+	goto cleanup;
+    if (attr_present == TRUE)
+	mask |= KDB_PWD_EXPIRE_TIME_ATTR;
+
+    /* KRBPOLICYREFERENCE */
+
+    if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn,
+		&attr_present)) != 0)
+	goto cleanup;
+    if (attr_present == TRUE) {
+	mask |= KDB_POL_REF_ATTR;
+	/* Ensure that the policy is inside the realm container */
+	if ((st = krb5_ldap_policydn_to_name (context, policydn, &tktpolname)) != 0)
+	    goto cleanup;
+    }
+
+    /* KRBPWDPOLICYREFERENCE */
+    if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn,
+		&attr_present)) != 0)
+	goto cleanup;
+    if (attr_present == TRUE) {
+	krb5_tl_data  kadm_tl_data;
+
+	mask |= KDB_PWD_POL_REF_ATTR;
+
+	/* Ensure that the policy is inside the realm container */
+	if ((st = krb5_ldap_policydn_to_name (context, pwdpolicydn, &polname)) != 0)
+	    goto cleanup;
+
+	if ((st = krb5_update_tl_kadm_data(polname, &kadm_tl_data)) != 0) {
+	    goto cleanup;
+	}
+	krb5_dbe_update_tl_data(context, entry, &kadm_tl_data);
+    }
+
+    /* KRBSECRETKEY */
+    if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != NULL) {
+        krb5_kvno mkvno = 0;
+
+	mask |= KDB_SECRET_KEY_ATTR;
+	if ((st=krb5_decode_krbsecretkey(context, entry, bvalues, &userinfo_tl_data, &mkvno)) != 0)
+	    goto cleanup;
+        if (mkvno != 0) {
+            /* don't add the tl data if mkvno == 0 */
+            if ((st=krb5_dbe_update_mkvno(context, entry, mkvno)) != 0)
+                goto cleanup;
+        }
+    }
+
+    /* LAST PASSWORD CHANGE */
+    {
+	krb5_timestamp lstpwdchng=0;
+	if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange",
+		    &lstpwdchng, &attr_present)) != 0)
+	    goto cleanup;
+	if (attr_present == TRUE) {
+	    if ((st=krb5_dbe_update_last_pwd_change(context, entry,
+			lstpwdchng)))
+		goto cleanup;
+	    mask |= KDB_LAST_PWD_CHANGE_ATTR;
+	}
+    }
+
+    /* KRBOBJECTREFERENCES */
+    {
+	int i=0;
+
+	if ((st = krb5_ldap_get_strings(ld, ent, "krbobjectreferences",
+		    &link_references, &attr_present)) != 0)
+	    goto cleanup;
+	if (link_references != NULL) {
+	    for (i=0; link_references[i] != NULL; ++i) {
+		if ((st = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN,
+			    link_references[i])) != 0)
+		    goto cleanup;
+	    }
+	}
+    }
+
+    /* Set tl_data */
+    {
+	int i;
+	struct berval **ber_tl_data = NULL;
+	krb5_tl_data *ptr = NULL;
+
+	if ((ber_tl_data = ldap_get_values_len (ld, ent, "krbExtraData")) != NULL) {
+	    for (i = 0; ber_tl_data[i] != NULL; i++) {
+		if ((st = berval2tl_data (ber_tl_data[i] , &ptr)) != 0)
+		    break;
+		if ((st = krb5_dbe_update_tl_data(context, entry, ptr)) != 0)
+		    break;
+	    }
+	    ldap_value_free_len (ber_tl_data);
+	    if (st != 0)
+		goto cleanup;
+	    mask |= KDB_EXTRA_DATA_ATTR;
+	}
+    }
+
+    /* update the mask of attributes present on the directory object to the tl_data */
+    if ((st=store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask)) != 0)
+	goto cleanup;
+    if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0)
+	goto cleanup;
+
+#ifdef HAVE_EDIRECTORY
+    {
+	krb5_timestamp              expiretime=0;
+	char                        *is_login_disabled=NULL;
+
+	/* LOGIN EXPIRATION TIME */
+	if ((st=krb5_ldap_get_time(ld, ent, "loginexpirationtime", &expiretime,
+		    &attr_present)) != 0)
+	    goto cleanup;
+
+	if (attr_present == TRUE) {
+	    if ((mask & KDB_PRINC_EXPIRE_TIME_ATTR) == 1) {
+		if (expiretime < entry->expiration)
+		    entry->expiration = expiretime;
+	    } else {
+		entry->expiration = expiretime;
+	    }
+	}
+
+	/* LOGIN DISABLED */
+	if ((st=krb5_ldap_get_string(ld, ent, "logindisabled", &is_login_disabled,
+		    &attr_present)) != 0)
+	    goto cleanup;
+	if (attr_present == TRUE) {
+	    if (strcasecmp(is_login_disabled, "TRUE")== 0)
+		entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+	    free (is_login_disabled);
+	}
+    }
+#endif
+
+    if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0)
+	goto cleanup;
+
+    /* We already know that the policy is inside the realm container. */
+    if (polname) {
+	osa_policy_ent_t   pwdpol;
+	int                cnt=0;
+	krb5_timestamp     last_pw_changed;
+	krb5_ui_4          pw_max_life;
+
+	memset(&pwdpol, 0, sizeof(pwdpol));
+
+	if ((st=krb5_ldap_get_password_policy(context, polname, &pwdpol, &cnt)) != 0)
+	    goto cleanup;
+	pw_max_life = pwdpol->pw_max_life;
+	free (pwdpol);
+
+	if (pw_max_life > 0) {
+	    if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0)
+		goto cleanup;
+
+	    if ((mask & KDB_PWD_EXPIRE_TIME_ATTR) == 1) {
+		if ((last_pw_changed + pw_max_life) < entry->pw_expiration)
+		    entry->pw_expiration = last_pw_changed + pw_max_life;
+	    } else
+		entry->pw_expiration = last_pw_changed + pw_max_life;
+	}
+    }
+    /* XXX so krb5_encode_princ_contents() will be happy */
+    entry->len = KRB5_KDB_V1_BASE_LENGTH;
+
+cleanup:
+
+    if (DN != NULL)
+	ldap_memfree(DN);
+
+    if (userinfo_tl_data.tl_data_contents != NULL)
+	free(userinfo_tl_data.tl_data_contents);
+
+    if (pwdpolicydn != NULL)
+	free(pwdpolicydn);
+
+    if (polname != NULL)
+	free(polname);
+
+    if (tktpolname != NULL)
+	free (tktpolname);
+
+    if (policydn != NULL)
+	free(policydn);
+
+    if (link_references) {
+        int i;
+        for (i=0; link_references[i] != NULL; ++i)
+            free (link_references[i]);
+        free (link_references);
+    }
+
+    return (st);
+}
+
+/*
+ * Solaris libldap does not provide the following functions which are in
+ * OpenLDAP.
+ */
+#ifndef HAVE_LDAP_INITIALIZE
+int
+ldap_initialize(LDAP **ldp, char *url)
+{
+    int rc = 0;
+    LDAP *ld = NULL;
+    LDAPURLDesc *ludp = NULL;
+
+    /* For now, we don't use any DN that may be provided.  And on
+       Solaris (based on Mozilla's LDAP client code), we need the
+       _nodn form to parse "ldap://host" without a trailing slash.
+
+       Also, this version won't handle an input string which contains
+       multiple URLs, unlike the OpenLDAP ldap_initialize.  See
+       https://bugzilla.mozilla.org/show_bug.cgi?id=353336#c1 .  */
+#ifdef HAVE_LDAP_URL_PARSE_NODN
+    rc = ldap_url_parse_nodn(url, &ludp);
+#else
+    rc = ldap_url_parse(url, &ludp);
+#endif
+    if (rc == 0) {
+
+	ld = ldap_init(ludp->lud_host, ludp->lud_port);
+	if (ld != NULL) {
+	    *ldp = ld;
+#if 0
+	    printf("lud_host %s lud_port %d\n", ludp->lud_host,
+		   ludp->lud_port);
+#endif
+	}
+	else
+	    rc = KRB5_KDB_ACCESS_ERROR;
+
+	ldap_free_urldesc(ludp);
+    }
+    return rc;
+}
+#endif /* HAVE_LDAP_INITIALIZE */
+
+#ifndef HAVE_LDAP_UNBIND_EXT_S
+int
+ldap_unbind_ext_s(LDAP *ld, LDAPControl **sctrls, LDAPControl **cctrls)
+{
+    return ldap_unbind_ext(ld, sctrls, cctrls);
+}
+#endif /* HAVE_LDAP_UNBIND_EXT_S */
diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c	2010-01-12 11:49:59.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c	2011-02-26 07:57:52.000000000 +0900
@@ -106,10 +106,10 @@
     int *nentries;		/* how much room/how many found */
     krb5_boolean *more;		/* are there more? */
 {
-    char                        *user=NULL, *filter=NULL, **subtree=NULL;
+    char                        *user=NULL, *filter=NULL, *filtuser=NULL;
     unsigned int                tree=0, ntrees=1, princlen=0;
     krb5_error_code	        tempst=0, st=0;
-    char                        **values=NULL, *cname=NULL;
+    char                        **values=NULL, **subtree=NULL, *cname=NULL;
     LDAP	                *ld=NULL;
     LDAPMessage	                *result=NULL, *ent=NULL;
     krb5_ldap_context           *ldap_context=NULL;
@@ -145,12 +145,18 @@
     if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
 	goto cleanup;
 
-    princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
+    filtuser = ldap_filter_correct(user);
+    if (filtuser == NULL) {
+        st = ENOMEM;
+        goto cleanup;
+    }
+
+    princlen = strlen(FILTER) + strlen(filtuser) + 2 + 1;  /* 2 for closing brackets */
     if ((filter = malloc(princlen)) == NULL) {
 	st = ENOMEM;
 	goto cleanup;
     }
-    snprintf(filter, princlen, FILTER"%s))", user);
+    snprintf(filter, princlen, FILTER"%s))", filtuser);
 
     if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
 	goto cleanup;
@@ -234,6 +240,9 @@
     if (user)
 	free(user);
 
+    if (filtuser)
+        free(filtuser);
+
     if (cname)
 	free(cname);
 
diff -uNr krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c.orig krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c.orig
--- krb5-1.7.1.orig/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c.orig	1970-01-01 09:00:00.000000000 +0900
+++ krb5-1.7.1/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c.orig	2010-01-12 11:49:59.000000000 +0900
@@ -0,0 +1,1354 @@
+/*
+ * lib/kdb/kdb_ldap/ldap_principal2.c
+ *
+ * Copyright (c) 2004-2005, Novell, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *   * The copyright holder's name is not used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <time.h>
+#include "ldap_main.h"
+#include "kdb_ldap.h"
+#include "ldap_principal.h"
+#include "princ_xdr.h"
+#include "ldap_tkt_policy.h"
+#include "ldap_pwd_policy.h"
+#include "ldap_err.h"
+#include <kadm5/admin.h>
+
+extern char* principal_attributes[];
+extern char* max_pwd_life_attr[];
+
+static char *
+getstringtime(krb5_timestamp);
+
+krb5_error_code
+berval2tl_data(struct berval *in, krb5_tl_data **out)
+{
+    *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data));
+    if (*out == NULL)
+	return ENOMEM;
+
+    (*out)->tl_data_length = in->bv_len - 2;
+    (*out)->tl_data_contents =  (krb5_octet *) malloc
+	((*out)->tl_data_length * sizeof (krb5_octet));
+    if ((*out)->tl_data_contents == NULL) {
+	free (*out);
+	return ENOMEM;
+    }
+
+    UNSTORE16_INT (in->bv_val, (*out)->tl_data_type);
+    memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
+
+    return 0;
+}
+
+/* Return true if it's okay to return aliases according to flags. */
+static krb5_boolean
+aliases_ok(unsigned int flags)
+{
+    /*
+     * The current DAL does not have a flag to indicate whether
+     * aliases are okay.  For service name lookups (AS or TGT path),
+     * we can always return aliases.  For client name lookups, we can
+     * only return aliases if the client passed the canonicalize flag.
+     * We abuse the CLIENT_REFERRALS_ONLY flag to detect client name
+     * lookups.
+     *
+     * This method has the side effect of permitting aliases for
+     * lookups by administrative interfaces (e.g. kadmin).  Since we
+     * don't have explicit admin support for aliases yet, this is
+     * okay.
+     */
+    if (!(flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY))
+	return TRUE;
+    if (flags & KRB5_KDB_FLAG_CANONICALIZE)
+	return TRUE;
+    return FALSE;
+}
+
+/*
+ * look up a principal in the directory.
+ */
+
+krb5_error_code
+krb5_ldap_get_principal(context, searchfor, flags, entries, nentries, more)
+    krb5_context context;
+    krb5_const_principal searchfor;
+    unsigned int flags;
+    krb5_db_entry *entries;	/* filled in */
+    int *nentries;		/* how much room/how many found */
+    krb5_boolean *more;		/* are there more? */
+{
+    char                        *user=NULL, *filter=NULL, **subtree=NULL;
+    unsigned int                tree=0, ntrees=1, princlen=0;
+    krb5_error_code	        tempst=0, st=0;
+    char                        **values=NULL, *cname=NULL;
+    LDAP	                *ld=NULL;
+    LDAPMessage	                *result=NULL, *ent=NULL;
+    krb5_ldap_context           *ldap_context=NULL;
+    kdb5_dal_handle             *dal_handle=NULL;
+    krb5_ldap_server_handle     *ldap_server_handle=NULL;
+    krb5_principal		cprinc=NULL;
+
+    /* Clear the global error string */
+    krb5_clear_error_message(context);
+
+    /* set initial values */
+    *nentries = 0;
+    *more = 0;
+    memset(entries, 0, sizeof(*entries));
+
+    if (searchfor == NULL)
+	return EINVAL;
+
+    dal_handle = context->dal_handle;
+    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
+
+    CHECK_LDAP_HANDLE(ldap_context);
+
+    if (is_principal_in_realm(ldap_context, searchfor) != 0) {
+	*more = 0;
+	krb5_set_error_message (context, st, "Principal does not belong to realm");
+	goto cleanup;
+    }
+
+    if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
+	goto cleanup;
+
+    if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
+	goto cleanup;
+
+    princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
+    if ((filter = malloc(princlen)) == NULL) {
+	st = ENOMEM;
+	goto cleanup;
+    }
+    snprintf(filter, princlen, FILTER"%s))", user);
+
+    if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
+	goto cleanup;
+
+    GET_HANDLE();
+    for (tree=0; tree < ntrees && *nentries == 0; ++tree) {
+
+	LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
+	for (ent=ldap_first_entry(ld, result); ent != NULL && *nentries == 0; ent=ldap_next_entry(ld, ent)) {
+
+	    /* get the associated directory user information */
+	    if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
+		int i;
+
+		/* a wild-card in a principal name can return a list of kerberos principals.
+		 * Make sure that the correct principal is returned.
+		 * NOTE: a principalname k* in ldap server will return all the principals starting with a k
+		 */
+		for (i=0; values[i] != NULL; ++i) {
+		    if (strcmp(values[i], user) == 0) {
+			*nentries = 1;
+			break;
+		    }
+		}
+		ldap_value_free(values);
+
+		if (*nentries == 0) /* no matching principal found */
+		    continue;
+	    }
+
+	    if ((values=ldap_get_values(ld, ent, "krbcanonicalname")) != NULL) {
+		if (values[0] && strcmp(values[0], user) != 0) {
+		    /* We matched an alias, not the canonical name. */
+		    if (aliases_ok(flags)) {
+			st = krb5_ldap_parse_principal_name(values[0], &cname);
+			if (st != 0)
+			    goto cleanup;
+			st = krb5_parse_name(context, cname, &cprinc);
+			if (st != 0)
+			    goto cleanup;
+		    } else /* No canonicalization, so don't return aliases. */
+			*nentries = 0;
+		}
+		ldap_value_free(values);
+		if (*nentries == 0)
+		    continue;
+	    }
+
+	    if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent,
+					     cprinc ? cprinc : searchfor,
+					     entries)) != 0)
+		goto cleanup;
+	}
+	ldap_msgfree(result);
+	result = NULL;
+    } /* for (tree=0 ... */
+
+    /* once done, put back the ldap handle */
+    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
+    ldap_server_handle = NULL;
+
+cleanup:
+    ldap_msgfree(result);
+
+    if (*nentries == 0 || st != 0)
+	krb5_dbe_free_contents(context, entries);
+
+    if (filter)
+	free (filter);
+
+    if (subtree) {
+	for (; ntrees; --ntrees)
+	    if (subtree[ntrees-1])
+		free (subtree[ntrees-1]);
+	free (subtree);
+    }
+
+    if (ldap_server_handle)
+	krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
+
+    if (user)
+	free(user);
+
+    if (cname)
+	free(cname);
+
+    if (cprinc)
+	krb5_free_principal(context, cprinc);
+
+    return st;
+}
+
+typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
+/*
+ * ptype is creating confusions. Additionally the logic
+ * surronding ptype is redundunt and can be achevied
+ * with the help of dn and containerdn members.
+ * so dropping the ptype member
+ */
+
+typedef struct _xargs_t {
+    char           *dn;
+    char           *linkdn;
+    krb5_boolean   dn_from_kbd;
+    char           *containerdn;
+    char           *tktpolicydn;
+}xargs_t;
+
+static void
+free_xargs(xargs)
+    xargs_t xargs;
+{
+    if (xargs.dn)
+	free (xargs.dn);
+    if (xargs.linkdn)
+	free(xargs.linkdn);
+    if (xargs.containerdn)
+	free (xargs.containerdn);
+    if (xargs.tktpolicydn)
+	free (xargs.tktpolicydn);
+}
+
+static krb5_error_code
+process_db_args(context, db_args, xargs, optype)
+    krb5_context   context;
+    char           **db_args;
+    xargs_t        *xargs;
+    OPERATION      optype;
+{
+    int                   i=0;
+    krb5_error_code       st=0;
+    char                  errbuf[1024];
+    char                  *arg=NULL, *arg_val=NULL;
+    char                  **dptr=NULL;
+    unsigned int          arg_val_len=0;
+
+    if (db_args) {
+	for (i=0; db_args[i]; ++i) {
+	    arg = strtok_r(db_args[i], "=", &arg_val);
+	    if (strcmp(arg, TKTPOLICY_ARG) == 0) {
+		dptr = &xargs->tktpolicydn;
+	    } else {
+		if (strcmp(arg, USERDN_ARG) == 0) {
+		    if (optype == MODIFY_PRINCIPAL || 
+			xargs->dn != NULL || xargs->containerdn != NULL || 
+			xargs->linkdn != NULL) {
+			st = EINVAL;
+			snprintf(errbuf, sizeof(errbuf), 
+				 "%s option not supported", arg);
+			krb5_set_error_message(context, st, "%s", errbuf);
+			goto cleanup;
+		    }
+		    dptr = &xargs->dn;
+		} else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
+		    if (optype == MODIFY_PRINCIPAL ||
+			xargs->dn != NULL || xargs->containerdn != NULL) {
+			st = EINVAL;
+			snprintf(errbuf, sizeof(errbuf), 
+				 "%s option not supported", arg);
+			krb5_set_error_message(context, st, "%s", errbuf);
+			goto cleanup;
+		    }
+		    dptr = &xargs->containerdn;
+		} else if (strcmp(arg, LINKDN_ARG) == 0) {
+		    if (xargs->dn != NULL || xargs->linkdn != NULL) {
+			st = EINVAL;
+			snprintf(errbuf, sizeof(errbuf), 
+				 "%s option not supported", arg);
+			krb5_set_error_message(context, st, "%s", errbuf);
+			goto cleanup;
+		    }
+		    dptr = &xargs->linkdn;
+		} else {
+		    st = EINVAL;
+		    snprintf(errbuf, sizeof(errbuf), "unknown option: %s", arg);
+		    krb5_set_error_message(context, st, "%s", errbuf);
+		    goto cleanup;
+		}
+		
+		xargs->dn_from_kbd = TRUE;
+		if (arg_val == NULL || strlen(arg_val) == 0) {
+		    st = EINVAL;
+		    snprintf(errbuf, sizeof(errbuf), 
+			     "%s option value missing", arg);
+		    krb5_set_error_message(context, st, "%s", errbuf);
+		    goto cleanup;
+		}
+	    }
+
+	    if (arg_val == NULL) {
+		st = EINVAL;
+		snprintf(errbuf, sizeof(errbuf), 
+			 "%s option value missing", arg);
+		krb5_set_error_message(context, st, "%s", errbuf);
+		goto cleanup;
+	    }
+	    arg_val_len = strlen(arg_val) + 1;
+
+	    if (strcmp(arg, TKTPOLICY_ARG) == 0) {
+		if ((st = krb5_ldap_name_to_policydn (context, 
+						      arg_val, 
+						      dptr)) != 0)
+		    goto cleanup;
+	    } else {
+		*dptr = calloc (1, arg_val_len);
+		if (*dptr == NULL) {
+		    st = ENOMEM;
+		    goto cleanup;
+		}
+		memcpy(*dptr, arg_val, arg_val_len);
+	    }
+	}
+    }
+
+cleanup:
+    return st;
+}
+
+krb5int_access accessor;
+
+static krb5_error_code
+asn1_encode_sequence_of_keys (krb5_key_data *key_data, krb5_int16 n_key_data,
+			      krb5_int32 mkvno, krb5_data **code)
+{
+    krb5_error_code err;
+    ldap_seqof_key_data val;
+
+    /*
+     * This should be pushed back into other library initialization
+     * code.
+     */
+    err = kldap_ensure_initialized ();
+    if (err)
+	return err;
+
+    val.key_data = key_data;
+    val.n_key_data = n_key_data;
+    val.mkvno = mkvno;
+
+    return accessor.asn1_ldap_encode_sequence_of_keys(&val, code);
+}
+
+static krb5_error_code
+asn1_decode_sequence_of_keys (krb5_data *in, krb5_key_data **out,
+			      krb5_int16 *n_key_data, krb5_kvno *mkvno)
+{
+    krb5_error_code err;
+    ldap_seqof_key_data *p;
+
+    /*
+     * This should be pushed back into other library initialization
+     * code.
+     */
+    err = kldap_ensure_initialized ();
+    if (err)
+	return err;
+
+    err = accessor.asn1_ldap_decode_sequence_of_keys(in, &p);
+    if (err)
+	return err;
+    *out = p->key_data;
+    *n_key_data = p->n_key_data;
+    *mkvno = p->mkvno;
+    free(p);
+    return 0;
+}
+
+
+/* Decoding ASN.1 encoded key */
+static struct berval **
+krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data, krb5_kvno mkvno) {
+    struct berval **ret = NULL;
+    int currkvno;
+    int num_versions = 1;
+    int i, j, last;
+    krb5_error_code err = 0;
+
+    if (n_key_data <= 0)
+	return NULL;
+
+    /* Find the number of key versions */
+    for (i = 0; i < n_key_data - 1; i++)
+	if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno)
+	    num_versions++;
+
+    ret = (struct berval **) calloc (num_versions + 1, sizeof (struct berval *));
+    if (ret == NULL) {
+	err = ENOMEM;
+	goto cleanup;
+    }
+    for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) {
+	krb5_data *code;
+	if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
+	    asn1_encode_sequence_of_keys (key_data+last,
+					  (krb5_int16) i - last + 1,
+					  mkvno,
+					  &code);
+	    ret[j] = malloc (sizeof (struct berval));
+	    if (ret[j] == NULL) {
+		err = ENOMEM;
+		goto cleanup;
+	    }
+	    /*CHECK_NULL(ret[j]); */
+	    ret[j]->bv_len = code->length;
+	    ret[j]->bv_val = code->data;
+	    j++;
+	    last = i + 1;
+
+	    currkvno = key_data[i].key_data_kvno;
+	}
+    }
+    ret[num_versions] = NULL;
+
+cleanup:
+
+    if (err != 0) {
+	if (ret != NULL) {
+	    for (i = 0; i <= num_versions; i++)
+		if (ret[i] != NULL)
+		    free (ret[i]);
+	    free (ret);
+	    ret = NULL;
+	}
+    }
+
+    return ret;
+}
+
+static krb5_error_code tl_data2berval (krb5_tl_data *in, struct berval **out) {
+    *out = (struct berval *) malloc (sizeof (struct berval));
+    if (*out == NULL)
+	return ENOMEM;
+
+    (*out)->bv_len = in->tl_data_length + 2;
+    (*out)->bv_val =  (char *) malloc ((*out)->bv_len);
+    if ((*out)->bv_val == NULL) {
+	free (*out);
+	return ENOMEM;
+    }
+
+    STORE16_INT((*out)->bv_val, in->tl_data_type);
+    memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
+
+    return 0;
+}
+
+krb5_error_code
+krb5_ldap_put_principal(context, entries, nentries, db_args)
+    krb5_context               context;
+    krb5_db_entry              *entries;
+    register int               *nentries;         /* number of entry structs to update */
+    char                       **db_args;
+{
+    int 		        i=0, l=0, kerberos_principal_object_type=0;
+    krb5_error_code 	        st=0, tempst=0;
+    LDAP  		        *ld=NULL;
+    LDAPMessage                 *result=NULL, *ent=NULL;
+    char                        *user=NULL, *subtree=NULL, *principal_dn=NULL;
+    char                        **values=NULL, *strval[10]={NULL}, errbuf[1024];
+    struct berval	        **bersecretkey=NULL;
+    LDAPMod 		        **mods=NULL;
+    krb5_boolean                create_standalone_prinicipal=FALSE;
+    krb5_boolean                krb_identity_exists=FALSE, establish_links=FALSE;
+    char                        *standalone_principal_dn=NULL;
+    krb5_tl_data                *tl_data=NULL;
+    krb5_key_data               **keys=NULL;
+    kdb5_dal_handle             *dal_handle=NULL;
+    krb5_ldap_context           *ldap_context=NULL;
+    krb5_ldap_server_handle     *ldap_server_handle=NULL;
+    osa_princ_ent_rec 	        princ_ent;
+    xargs_t                     xargs = {0};
+    char                        *polname = NULL;
+    OPERATION optype;
+    krb5_boolean     		found_entry = FALSE;
+
+    /* Clear the global error string */
+    krb5_clear_error_message(context);
+
+    SETUP_CONTEXT();
+    if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL)
+	return EINVAL;
+
+    /* get ldap handle */
+    GET_HANDLE();
+
+    for (i=0; i < *nentries; ++i, ++entries) {
+	if (is_principal_in_realm(ldap_context, entries->princ) != 0) {
+	    st = EINVAL;
+	    krb5_set_error_message(context, st, "Principal does not belong to the default realm");
+	    goto cleanup;
+	}
+
+	/* get the principal information to act on */
+	if (entries->princ) {
+	    if (((st=krb5_unparse_name(context, entries->princ, &user)) != 0) ||
+		((st=krb5_ldap_unparse_principal_name(user)) != 0))
+		goto cleanup;
+	}
+
+	/* Identity the type of operation, it can be
+	 * add principal or modify principal.
+	 * hack if the entries->mask has KRB_PRINCIPAL flag set
+	 * then it is a add operation
+	 */
+	if (entries->mask & KADM5_PRINCIPAL)
+	    optype = ADD_PRINCIPAL;
+	else
+	    optype = MODIFY_PRINCIPAL;
+
+	if (((st=krb5_get_princ_type(context, entries, &kerberos_principal_object_type)) != 0) ||
+	    ((st=krb5_get_userdn(context, entries, &principal_dn)) != 0))
+	    goto cleanup;
+
+	if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
+	    goto cleanup;
+
+	if (entries->mask & KADM5_LOAD) {
+	    int              tree = 0, ntrees = 0, princlen = 0, numlentries = 0;
+	    char             **subtreelist = NULL, *filter = NULL;
+
+	    /*  A load operation is special, will do a mix-in (add krbprinc
+	     *  attrs to a non-krb object entry) if an object exists with a
+	     *  matching krbprincipalname attribute so try to find existing
+	     *  object and set principal_dn.  This assumes that the
+	     *  krbprincipalname attribute is unique (only one object entry has
+	     *  a particular krbprincipalname attribute).
+	     */
+	    if (user == NULL) {
+		/* must have principal name for search */
+		st = EINVAL;
+		krb5_set_error_message(context, st, "operation can not continue, principal name not found");
+		goto cleanup;
+	    }
+	    princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
+	    if ((filter = malloc(princlen)) == NULL) {
+		st = ENOMEM;
+		goto cleanup;
+	    }
+	    snprintf(filter, princlen, FILTER"%s))", user);
+
+	    /* get the current subtree list */
+	    if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
+		goto cleanup;
+
+	    found_entry = FALSE;
+	    /* search for entry with matching krbprincipalname attribute */
+	    for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
+		result = NULL;
+		if (principal_dn == NULL) {
+		    LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
+		} else {
+		    /* just look for entry with principal_dn */
+		    LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
+		}
+		if (st == LDAP_SUCCESS) {
+		    numlentries = ldap_count_entries(ld, result);
+		    if (numlentries > 1) {
+			ldap_msgfree(result);
+			free(filter);
+			st = EINVAL;
+			krb5_set_error_message(context, st,
+			    "operation can not continue, more than one entry with principal name \"%s\" found",
+			    user);
+			goto cleanup;
+		    } else if (numlentries == 1) {
+			found_entry = TRUE;
+			if (principal_dn == NULL) {
+			    ent = ldap_first_entry(ld, result);
+			    if (ent != NULL) {
+				/* setting principal_dn will cause that entry to be modified further down */
+				if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
+				    ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
+				    st = set_ldap_error (context, st, 0);
+				    ldap_msgfree(result);
+				    free(filter);
+				    goto cleanup;
+				}
+			    }
+			}
+		    }
+		    if (result)
+			ldap_msgfree(result);
+		} else if (st != LDAP_NO_SUCH_OBJECT) {
+		    /* could not perform search, return with failure */
+		    st = set_ldap_error (context, st, 0);
+		    free(filter);
+		    goto cleanup;
+		}
+		/* 
+		 * If it isn't found then assume a standalone princ entry is to
+		 * be created.
+		 */
+	    } /* end for (tree = 0; principal_dn == ... */
+
+	    free(filter);
+
+	    if (found_entry == FALSE && principal_dn != NULL) {
+		/* 
+		 * if principal_dn is null then there is code further down to
+		 * deal with setting standalone_principal_dn.  Also note that
+		 * this will set create_standalone_prinicipal true for
+		 * non-mix-in entries which is okay if loading from a dump.
+		 */
+		create_standalone_prinicipal = TRUE;
+		standalone_principal_dn = strdup(principal_dn);
+		CHECK_NULL(standalone_principal_dn);
+	    }
+	} /* end if (entries->mask & KADM5_LOAD */
+
+	/* time to generate the DN information with the help of
+	 * containerdn, principalcontainerreference or
+	 * realmcontainerdn information
+	 */
+	if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
+	    /* get the subtree information */
+	    if (entries->princ->length == 2 && entries->princ->data[0].length == strlen("krbtgt") &&
+		strncmp(entries->princ->data[0].data, "krbtgt", entries->princ->data[0].length) == 0) {
+		/* if the principal is a inter-realm principal, always created in the realm container */
+		subtree = strdup(ldap_context->lrparams->realmdn);
+	    } else if (xargs.containerdn) {
+		if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
+		    if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
+			int ost = st;
+			st = EINVAL;
+			snprintf(errbuf, sizeof(errbuf), "'%s' not found: ",
+				 xargs.containerdn);
+			prepend_err_str(context, errbuf, st, ost);
+		    }
+		    goto cleanup;
+		}
+		subtree = strdup(xargs.containerdn);
+	    } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
+		/*
+		 * Here the subtree should be changed with
+		 * principalcontainerreference attribute value
+		 */
+		subtree = strdup(ldap_context->lrparams->containerref);
+	    } else {
+		subtree = strdup(ldap_context->lrparams->realmdn);
+	    }
+	    CHECK_NULL(subtree);
+
+	    if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s",
+			 user, subtree) < 0)
+		standalone_principal_dn = NULL;
+	    CHECK_NULL(standalone_principal_dn);
+	    /*
+	     * free subtree when you are done using the subtree
+	     * set the boolean create_standalone_prinicipal to TRUE
+	     */
+	    create_standalone_prinicipal = TRUE;
+	    free(subtree);
+	    subtree = NULL;
+	}
+
+	/*
+	 * If the DN information is presented by the user, time to
+	 * validate the input to ensure that the DN falls under
+	 * any of the subtrees
+	 */
+	if (xargs.dn_from_kbd == TRUE) {
+	    /* make sure the DN falls in the subtree */
+	    int              tre=0, dnlen=0, subtreelen=0, ntrees=0;
+	    char             **subtreelist=NULL;
+	    char             *dn=NULL;
+	    krb5_boolean     outofsubtree=TRUE;
+
+	    if (xargs.dn != NULL) {
+		dn = xargs.dn;
+	    } else if (xargs.linkdn != NULL) {
+		dn = xargs.linkdn;
+	    } else if (standalone_principal_dn != NULL) {
+		/*
+		 * Even though the standalone_principal_dn is constructed
+		 * within this function, there is the containerdn input
+		 * from the user that can become part of the it.
+		 */
+		dn = standalone_principal_dn;
+	    }
+
+	    /* get the current subtree list */
+	    if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
+		goto cleanup;
+
+	    for (tre=0; tre<ntrees; ++tre) {
+		if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
+		    outofsubtree = FALSE;
+		    break;
+		} else {
+		    dnlen = strlen (dn);
+		    subtreelen = strlen(subtreelist[tre]);
+		    if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
+			outofsubtree = FALSE;
+			break;
+		    }
+		}
+	    }
+
+	    for (tre=0; tre < ntrees; ++tre) {
+		free(subtreelist[tre]);
+	    }
+
+	    if (outofsubtree == TRUE) {
+		st = EINVAL;
+		krb5_set_error_message(context, st, "DN is out of the realm subtree");
+		goto cleanup;
+	    }
+
+	    /*
+	     * dn value will be set either by dn, linkdn or the standalone_principal_dn
+	     * In the first 2 cases, the dn should be existing and in the last case we
+	     * are supposed to create the ldap object. so the below should not be
+	     * executed for the last case.
+	     */
+
+	    if (standalone_principal_dn == NULL) {
+		/*
+		 * If the ldap object is missing, this results in an error.
+		 */
+
+		/*
+		 * Search for krbprincipalname attribute here.
+		 * This is to find if a kerberos identity is already present
+		 * on the ldap object, in which case adding a kerberos identity
+		 * on the ldap object should result in an error.
+		 */
+		char  *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
+
+		LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
+		if (st == LDAP_SUCCESS) {
+		    ent = ldap_first_entry(ld, result);
+		    if (ent != NULL) {
+			if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
+			    ldap_value_free(values);
+			}
+
+			if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
+			    krb_identity_exists = TRUE;
+			    ldap_value_free(values);
+			}
+		    }
+		    ldap_msgfree(result);
+		} else {
+		    st = set_ldap_error(context, st, OP_SEARCH);
+		    goto cleanup;
+		}
+	    }
+	}
+
+	/*
+	 * If xargs.dn is set then the request is to add a
+	 * kerberos principal on a ldap object, but if
+	 * there is one already on the ldap object this
+	 * should result in an error.
+	 */
+
+	if (xargs.dn != NULL && krb_identity_exists == TRUE) {
+	    st = EINVAL;
+	    snprintf(errbuf, sizeof(errbuf), "ldap object is already kerberized");
+	    krb5_set_error_message(context, st, "%s", errbuf);
+	    goto cleanup;
+	}
+
+	if (xargs.linkdn != NULL) {
+	    /*
+	     * link information can be changed using modprinc.
+	     * However, link information can be changed only on the
+	     * standalone kerberos principal objects. A standalone
+	     * kerberos principal object is of type krbprincipal
+	     * structural objectclass.
+	     *
+	     * NOTE: kerberos principals on an ldap object can't be
+	     * linked to other ldap objects.
+	     */
+	    if (optype == MODIFY_PRINCIPAL &&
+		kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
+		st = EINVAL;
+		snprintf(errbuf, sizeof(errbuf),
+		    "link information can not be set/updated as the kerberos principal belongs to an ldap object");
+		krb5_set_error_message(context, st, "%s", errbuf);
+		goto cleanup;
+	    }
+            /*
+             * Check the link information. If there is already a link
+             * existing then this operation is not allowed.
+             */
+            {
+                char **linkdns=NULL;
+                int  j=0;
+
+                if ((st=krb5_get_linkdn(context, entries, &linkdns)) != 0) {
+                    snprintf(errbuf, sizeof(errbuf),
+                             "Failed getting object references");
+                    krb5_set_error_message(context, st, "%s", errbuf);
+                    goto cleanup;
+                }
+                if (linkdns != NULL) {
+                    st = EINVAL;
+                    snprintf(errbuf, sizeof(errbuf),
+                             "kerberos principal is already linked "
+                             "to a ldap object");
+                    krb5_set_error_message(context, st, "%s", errbuf);
+                    for (j=0; linkdns[j] != NULL; ++j)
+                        free (linkdns[j]);
+                    free (linkdns);
+                    goto cleanup;
+                }
+            }
+
+	    establish_links = TRUE;
+	}
+
+	if ((entries->last_success)!=0) {
+	    memset(strval, 0, sizeof(strval));
+	    if ((strval[0]=getstringtime(entries->last_success)) == NULL)
+		goto cleanup;
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
+		free (strval[0]);
+		goto cleanup;
+	    }
+	    free (strval[0]);
+	}
+
+	if (entries->last_failed!=0) {
+	    memset(strval, 0, sizeof(strval));
+	    if ((strval[0]=getstringtime(entries->last_failed)) == NULL)
+		goto cleanup;
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
+		free (strval[0]);
+		goto cleanup;
+	    }
+	    free(strval[0]);
+	}
+
+	if (entries->fail_auth_count!=0) {
+	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_REPLACE, entries->fail_auth_count)) !=0)
+		goto cleanup;
+	}
+
+	if (entries->mask & KADM5_MAX_LIFE) {
+	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entries->max_life)) != 0)
+		goto cleanup;
+	}
+
+	if (entries->mask & KADM5_MAX_RLIFE) {
+	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
+					      entries->max_renewable_life)) != 0)
+		goto cleanup;
+	}
+
+	if (entries->mask & KADM5_ATTRIBUTES) {
+	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
+					      entries->attributes)) != 0)
+		goto cleanup;
+	}
+
+	if (entries->mask & KADM5_PRINCIPAL) {
+	    memset(strval, 0, sizeof(strval));
+	    strval[0] = user;
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
+		goto cleanup;
+	}
+
+	if (entries->mask & KADM5_PRINC_EXPIRE_TIME) {
+	    memset(strval, 0, sizeof(strval));
+	    if ((strval[0]=getstringtime(entries->expiration)) == NULL)
+		goto cleanup;
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
+		free (strval[0]);
+		goto cleanup;
+	    }
+	    free (strval[0]);
+	}
+
+	if (entries->mask & KADM5_PW_EXPIRATION) {
+	    memset(strval, 0, sizeof(strval));
+	    if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
+		goto cleanup;
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
+					      LDAP_MOD_REPLACE,
+					      strval)) != 0) {
+		free (strval[0]);
+		goto cleanup;
+	    }
+	    free (strval[0]);
+	}
+
+	if (entries->mask & KADM5_POLICY) {
+	    memset(&princ_ent, 0, sizeof(princ_ent));
+	    for (tl_data=entries->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
+		if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
+		    /* FIX ME: I guess the princ_ent should be freed after this call */
+		    if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
+			goto cleanup;
+		    }
+		}
+	    }
+
+	    if (princ_ent.aux_attributes & KADM5_POLICY) {
+		memset(strval, 0, sizeof(strval));
+		if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
+		    goto cleanup;
+		strval[0] = polname;
+		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
+		    goto cleanup;
+	    } else {
+		st = EINVAL;
+		krb5_set_error_message(context, st, "Password policy value null");
+		goto cleanup;
+	    }
+	} else if (entries->mask & KADM5_LOAD && found_entry == TRUE) {
+	    /* 
+	     * a load is special in that existing entries must have attrs that
+	     * removed.
+	     */
+
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
+		goto cleanup;
+	}
+
+	if (entries->mask & KADM5_POLICY_CLR) {
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
+		goto cleanup;
+	}
+
+	if (entries->mask & KADM5_KEY_DATA || entries->mask & KADM5_KVNO) {
+            krb5_kvno mkvno;
+
+            if ((st=krb5_dbe_lookup_mkvno(context, entries, &mkvno)) != 0)
+                goto cleanup;
+	    bersecretkey = krb5_encode_krbsecretkey (entries->key_data,
+						     entries->n_key_data, mkvno);
+
+	    if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
+					      LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
+		goto cleanup;
+
+	    if (!(entries->mask & KADM5_PRINCIPAL)) {
+		memset(strval, 0, sizeof(strval));
+		if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
+		    goto cleanup;
+		if ((st=krb5_add_str_mem_ldap_mod(&mods,
+						  "krbpasswordexpiration",
+						  LDAP_MOD_REPLACE, strval)) != 0) {
+		    free (strval[0]);
+		    goto cleanup;
+		}
+		free (strval[0]);
+	    }
+
+	    /* Update last password change whenever a new key is set */
+	    {
+		krb5_timestamp last_pw_changed;
+		if ((st=krb5_dbe_lookup_last_pwd_change(context, entries,
+							&last_pw_changed)) != 0)
+		    goto cleanup;
+
+		memset(strval, 0, sizeof(strval));
+		if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
+		    goto cleanup;
+
+		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
+						  LDAP_MOD_REPLACE, strval)) != 0) {
+		    free (strval[0]);
+		    goto cleanup;
+		}
+		free (strval[0]);
+	    }
+
+	} /* Modify Key data ends here */
+
+	/* Set tl_data */
+	if (entries->tl_data != NULL) {
+	    int count = 0;
+	    struct berval **ber_tl_data = NULL;
+	    krb5_tl_data *ptr;
+	    for (ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
+		if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
+#ifdef SECURID
+		    || ptr->tl_data_type == KRB5_TL_DB_ARGS
+#endif
+		    || ptr->tl_data_type == KRB5_TL_KADM_DATA
+		    || ptr->tl_data_type == KDB_TL_USER_INFO)
+		    continue;
+		count++;
+	    }
+	    if (count != 0) {
+		int j;
+		ber_tl_data = (struct berval **) calloc (count + 1,
+							 sizeof (struct berval*));
+		if (ber_tl_data == NULL) {
+		    st = ENOMEM;
+		    goto cleanup;
+		}
+		for (j = 0, ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
+		    /* Ignore tl_data that are stored in separate directory
+		     * attributes */
+		    if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
+#ifdef SECURID
+			|| ptr->tl_data_type == KRB5_TL_DB_ARGS
+#endif
+			|| ptr->tl_data_type == KRB5_TL_KADM_DATA
+			|| ptr->tl_data_type == KDB_TL_USER_INFO)
+			continue;
+		    if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
+			break;
+		    j++;
+		}
+		if (st != 0) {
+		    for (j = 0; ber_tl_data[j] != NULL; j++) {
+			free (ber_tl_data[j]->bv_val);
+			free (ber_tl_data[j]);
+		    }
+		    free (ber_tl_data);
+		    goto cleanup;
+		}
+		ber_tl_data[count] = NULL;
+		if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
+						  LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
+						  ber_tl_data)) != 0)
+		    goto cleanup;
+	    }
+	}
+
+	/* Directory specific attribute */
+	if (xargs.tktpolicydn != NULL) {
+	    int tmask=0;
+
+	    if (strlen(xargs.tktpolicydn) != 0) {
+		st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
+		CHECK_CLASS_VALIDITY(st, tmask, "ticket policy object value: ");
+
+		strval[0] = xargs.tktpolicydn;
+		strval[1] = NULL;
+		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
+		    goto cleanup;
+
+	    } else {
+		/* if xargs.tktpolicydn is a empty string, then delete
+		 * already existing krbticketpolicyreference attr */
+		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
+		    goto cleanup;
+	    }
+
+	}
+
+	if (establish_links == TRUE) {
+	    memset(strval, 0, sizeof(strval));
+	    strval[0] = xargs.linkdn;
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
+		goto cleanup;
+	}
+
+	/*
+	 * in case mods is NULL then return
+	 * not sure but can happen in a modprinc
+	 * so no need to return an error
+	 * addprinc will at least have the principal name
+	 * and the keys passed in
+	 */
+	if (mods == NULL)
+	    goto cleanup;
+
+	if (create_standalone_prinicipal == TRUE) {
+	    memset(strval, 0, sizeof(strval));
+	    strval[0] = "krbprincipal";
+	    strval[1] = "krbprincipalaux";
+	    strval[2] = "krbTicketPolicyAux";
+
+	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
+		goto cleanup;
+
+	    st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
+	    if (st == LDAP_ALREADY_EXISTS && entries->mask & KADM5_LOAD) {
+		/* a load operation must replace an existing entry */
+		st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
+		if (st != LDAP_SUCCESS) {
+		    snprintf(errbuf, sizeof(errbuf), "Principal delete failed (trying to replace entry): %s",
+			ldap_err2string(st));
+		    st = translate_ldap_error (st, OP_ADD);
+		    krb5_set_error_message(context, st, "%s", errbuf);
+		    goto cleanup;
+		} else {
+		    st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
+		}
+	    }
+	    if (st != LDAP_SUCCESS) {
+		snprintf(errbuf, sizeof(errbuf), "Principal add failed: %s", ldap_err2string(st));
+		st = translate_ldap_error (st, OP_ADD);
+		krb5_set_error_message(context, st, "%s", errbuf);
+		goto cleanup;
+	    }
+	} else {
+	    /*
+	     * Here existing ldap object is modified and can be related
+	     * to any attribute, so always ensure that the ldap
+	     * object is extended with all the kerberos related
+	     * objectclasses so that there are no constraint
+	     * violations.
+	     */
+	    {
+		char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
+		int p, q, r=0, amask=0;
+
+		if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
+					    "objectclass", attrvalues, &amask)) != 0)
+		    goto cleanup;
+
+		memset(strval, 0, sizeof(strval));
+		for (p=1, q=0; p<=2; p<<=1, ++q) {
+		    if ((p & amask) == 0)
+			strval[r++] = attrvalues[q];
+		}
+		if (r != 0) {
+		    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
+			goto cleanup;
+		}
+	    }
+	    if (xargs.dn != NULL)
+		st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
+	    else
+		st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
+
+	    if (st != LDAP_SUCCESS) {
+		snprintf(errbuf, sizeof(errbuf), "User modification failed: %s", ldap_err2string(st));
+		st = translate_ldap_error (st, OP_MOD);
+		krb5_set_error_message(context, st, "%s", errbuf);
+		goto cleanup;
+	    }
+	}
+    }
+
+cleanup:
+    if (user)
+	free(user);
+
+    free_xargs(xargs);
+
+    if (standalone_principal_dn)
+	free(standalone_principal_dn);
+
+    if (principal_dn)
+	free (principal_dn);
+
+    if (polname != NULL)
+	free(polname);
+
+    if (subtree)
+	free (subtree);
+
+    if (bersecretkey) {
+	for (l=0; bersecretkey[l]; ++l) {
+	    if (bersecretkey[l]->bv_val)
+		free (bersecretkey[l]->bv_val);
+	    free (bersecretkey[l]);
+	}
+	free (bersecretkey);
+    }
+
+    if (keys)
+	free (keys);
+
+    ldap_mods_free(mods, 1);
+    krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
+    *nentries = i;
+    return(st);
+}
+
+krb5_error_code
+krb5_read_tkt_policy (context, ldap_context, entries, policy)
+    krb5_context                context;
+    krb5_ldap_context           *ldap_context;
+    krb5_db_entry               *entries;
+    char                        *policy;
+{
+    krb5_error_code             st=0;
+    unsigned int                mask=0, omask=0;
+    int                         tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR);
+    krb5_ldap_policy_params     *tktpoldnparam=NULL;
+
+    if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
+	goto cleanup;
+
+    if ((mask & tkt_mask) == tkt_mask)
+	goto cleanup;
+
+    if (policy != NULL) {
+	st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask);
+	if (st && st != KRB5_KDB_NOENTRY) {
+	    prepend_err_str(context, "Error reading ticket policy. ", st, st);
+	    goto cleanup;
+	}
+
+	st = 0; /* reset the return status */
+    }
+
+    if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
+	if ((omask & KDB_MAX_LIFE_ATTR) ==  KDB_MAX_LIFE_ATTR)
+	    entries->max_life = tktpoldnparam->maxtktlife;
+	else if (ldap_context->lrparams->max_life)
+	    entries->max_life = ldap_context->lrparams->max_life;
+    }
+
+    if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
+	if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR)
+	    entries->max_renewable_life = tktpoldnparam->maxrenewlife;
+	else if (ldap_context->lrparams->max_renewable_life)
+	    entries->max_renewable_life = ldap_context->lrparams->max_renewable_life;
+    }
+
+    if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
+	if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR)
+	    entries->attributes = tktpoldnparam->tktflags;
+	else if (ldap_context->lrparams->tktflags)
+	    entries->attributes |= ldap_context->lrparams->tktflags;
+    }
+    krb5_ldap_free_policy(context, tktpoldnparam);
+
+cleanup:
+    return st;
+}
+
+krb5_error_code
+krb5_decode_krbsecretkey(context, entries, bvalues, userinfo_tl_data, mkvno)
+    krb5_context                context;
+    krb5_db_entry               *entries;
+    struct berval               **bvalues;
+    krb5_tl_data                *userinfo_tl_data;
+    krb5_kvno                   *mkvno;
+{
+    char                        *user=NULL;
+    int                         i=0, j=0, noofkeys=0;
+    krb5_key_data               *key_data=NULL, *tmp;
+    krb5_error_code             st=0;
+
+    if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0)
+	goto cleanup;
+
+    for (i=0; bvalues[i] != NULL; ++i) {
+	krb5_int16 n_kd;
+	krb5_key_data *kd;
+	krb5_data in;
+
+	if (bvalues[i]->bv_len == 0)
+	    continue;
+	in.length = bvalues[i]->bv_len;
+	in.data = bvalues[i]->bv_val;
+
+	st = asn1_decode_sequence_of_keys (&in,
+					   &kd,
+					   &n_kd,
+					   mkvno);
+
+	if (st != 0) {
+	    const char *msg = error_message(st);
+	    st = -1; /* Something more appropriate ? */
+	    krb5_set_error_message (context, st,
+				    "unable to decode stored principal key data (%s)", msg);
+	    goto cleanup;
+	}
+	noofkeys += n_kd;
+	tmp = key_data;
+	key_data = realloc (key_data, noofkeys * sizeof (krb5_key_data));
+	if (key_data == NULL) {
+	    key_data = tmp;
+	    st = ENOMEM;
+	    goto cleanup;
+	}
+	for (j = 0; j < n_kd; j++)
+	    key_data[noofkeys - n_kd + j] = kd[j];
+	free (kd);
+    }
+
+    entries->n_key_data = noofkeys;
+    entries->key_data = key_data;
+
+cleanup:
+    ldap_value_free_len(bvalues);
+    free (user);
+    return st;
+}
+
+static char *
+getstringtime(epochtime)
+    krb5_timestamp    epochtime;
+{
+    struct tm           tme;
+    char                *strtime=NULL;
+    time_t		posixtime = epochtime;
+
+    strtime = calloc (50, 1);
+    if (strtime == NULL)
+	return NULL;
+
+    if (gmtime_r(&posixtime, &tme) == NULL)
+	return NULL;
+
+    strftime(strtime, 50, "%Y%m%d%H%M%SZ", &tme);
+    return strtime;
+}
+
