krb5 commit: Modernize some LDAP sources

Greg Hudson ghudson at MIT.EDU
Sat Jul 19 16:39:24 EDT 2014


https://github.com/krb5/krb5/commit/89b3b6b80d4812722e8d3b02e2134ccf5d1360c2
commit 89b3b6b80d4812722e8d3b02e2134ccf5d1360c2
Author: Greg Hudson <ghudson at mit.edu>
Date:   Mon Jun 9 15:23:25 2014 -0400

    Modernize some LDAP sources
    
    Bring ldap_misc.c up to date with current practices and make limited
    changes to other files.  Of note:
    
    * krb5_decode_krbsecretkey was freeing its bvalues argument; make that
      the caller's responsibility.
    * Make is_principal_in_realm and has_modify_increment return
      krb5_boolean, reversing the sense of their results.
    * Remove broken code path in decode_tl_data when an integer value has
      a length other than 2 (which should never happen).
    * Simplify krb5_ldap_readpassword and make it take filename/name
      parameters instead of an LDAP context.
    * Make krb5_ldap_bind (renamed to authenticate) responsible for
      setting a useful error message, so that its caller doesn't assume
      knowledge of the bind parameters.
    * Make krb5_ldap_initialize (renamed to initialize_server) responsible
      for updating the handle list, and remove the otherwise unused
      krb5_update_ldap_handle.
    * Remove remaining skeletal certificate support, including the unused
      has_sasl_external_mech function.
    * Remove unused krb5_get_containerdn and KDB_TL_CONTAINERDN.
    * Remove kdb_xdr.h; all of its prototypes were for functions that
      don't exist in the module or were duplicated in other headers.
    * Remove krb5_ldap_get_strings and use ldap_get_values directly at
      its call sites; there was no need to copy the result.

 src/plugins/kdb/ldap/libkdb_ldap/deps              |    2 +-
 src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c        |  116 +-
 src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h        |   18 +-
 src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c   |  202 +-
 src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c         |    2 +-
 src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.h         |   35 -
 src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c     |   21 -
 src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h     |    3 -
 .../kdb/ldap/libkdb_ldap/ldap_krbcontainer.c       |    2 -
 src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c       | 2081 ++++++++------------
 src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h       |   24 +-
 src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c  |    2 +-
 src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c |    5 +-
 .../kdb/ldap/libkdb_ldap/ldap_service_stash.c      |   98 +-
 .../kdb/ldap/libkdb_ldap/ldap_service_stash.h      |    3 +-
 15 files changed, 1003 insertions(+), 1611 deletions(-)

diff --git a/src/plugins/kdb/ldap/libkdb_ldap/deps b/src/plugins/kdb/ldap/libkdb_ldap/deps
index 2c1d63c..10c287d 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/deps
+++ b/src/plugins/kdb/ldap/libkdb_ldap/deps
@@ -224,7 +224,7 @@ kdb_xdr.so kdb_xdr.po $(OUTPRE)kdb_xdr.$(OBJEXT): $(BUILDTOP)/include/autoconf.h
   $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \
   $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
   $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  kdb_xdr.c kdb_xdr.h
+  kdb_xdr.c
 ldap_err.so ldap_err.po $(OUTPRE)ldap_err.$(OBJEXT): \
   $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
   ldap_err.c ldap_err.h
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c
index 8284f81..76243f9 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c
@@ -120,120 +120,66 @@ cleanup:
 }
 
 
-/*
- * Interrogate the root DSE (zero length DN) for an attribute
- * value assertion.
- */
-static int
-has_rootdse_ava(krb5_context context, char *ldap_server, char *attribute,
-                char *value)
+/* Interrogate the root DSE (zero length DN) for an attribute value assertion.
+ * Return true if it is present, false if it is absent or we can't tell. */
+static krb5_boolean
+has_rootdse_ava(krb5_context context, const char *server_name,
+                const char *attribute, const char *value)
 {
-    int               i=0, flag=0, ret=0, retval=0;
-    char              *attrs[2], **values=NULL;
-    LDAP              *ld=NULL;
-    LDAPMessage       *msg=NULL, *res=NULL;
-    struct berval     cred;
+    krb5_boolean result = FALSE;
+    char *attrs[2], **values = NULL;
+    int i, st;
+    LDAP *ld = NULL;
+    LDAPMessage *msg, *res = NULL;
+    struct berval cred;
 
     attrs[0] = attribute;
     attrs[1] = NULL;
 
-    retval = ldap_initialize(&ld, ldap_server);
-    if (retval != LDAP_SUCCESS) {
-        ret = 2; /* Don't know */
+    st = ldap_initialize(&ld, server_name);
+    if (st != LDAP_SUCCESS)
         goto cleanup;
-    }
 
+    /* Bind anonymously. */
     cred.bv_val = "";
     cred.bv_len = 0;
-
-    /* Anonymous bind */
-    retval = ldap_sasl_bind_s(ld, "", NULL, &cred, NULL, NULL, NULL);
-    if (retval != LDAP_SUCCESS) {
-        ret = 2; /* Don't know */
+    st = ldap_sasl_bind_s(ld, "", NULL, &cred, NULL, NULL, NULL);
+    if (st != LDAP_SUCCESS)
         goto cleanup;
-    }
 
-    retval = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, NULL, NULL, NULL, 0, &res);
-    if (retval != LDAP_SUCCESS) {
-        ret = 2; /* Don't know */
+    st = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, NULL,
+                           NULL, NULL, 0, &res);
+    if (st != LDAP_SUCCESS)
         goto cleanup;
-    }
 
     msg = ldap_first_message(ld, res);
-    if (msg == NULL) {
-        ret = 2; /* Don't know */
+    if (msg == NULL)
         goto cleanup;
-    }
 
     values = ldap_get_values(ld, msg, attribute);
-    if (values == NULL) {
-        ret = 1; /* Not supported */
+    if (values == NULL)
         goto cleanup;
-    }
 
     for (i = 0; values[i] != NULL; i++) {
         if (strcmp(values[i], value) == 0) {
-            flag = 1;
-            break;
+            result = TRUE;
+            goto cleanup;
         }
     }
 
-    if (flag != 1) {
-        ret = 1; /* Not supported */
-        goto cleanup;
-    }
-
 cleanup:
+    ldap_value_free(values);
+    ldap_msgfree(res);
+    ldap_unbind_ext_s(ld, NULL, NULL);
 
-    if (values != NULL)
-        ldap_value_free(values);
-
-    if (res != NULL)
-        ldap_msgfree(res);
-
-    if (ld != NULL)
-        ldap_unbind_ext_s(ld, NULL, NULL);
-
-    return ret;
-}
-
-#define ERR_MSG1 _("Unable to check if SASL EXTERNAL mechanism is supported by LDAP server. Proceeding anyway ...")
-#define ERR_MSG2 _("SASL EXTERNAL mechanism not supported by LDAP server. Can't perform certificate-based bind.")
-
-/* Function to check if a LDAP server supports the SASL external mechanism
- *Return values:
- *   0 => supports
- *   1 => does not support
- *   2 => don't know
- */
-int
-has_sasl_external_mech(krb5_context context, char *ldap_server)
-{
-    int ret;
-
-    ret = has_rootdse_ava(context, ldap_server,
-                          "supportedSASLMechanisms", "EXTERNAL");
-    switch (ret) {
-    case 1: /* not supported */
-        k5_setmsg(context, 1, "%s", ERR_MSG2);
-        break;
-    case 2: /* don't know */
-        k5_setmsg(context, 1, "%s", ERR_MSG1);
-        break;
-    default:
-        break;
-    }
-
-    return ret;
+    return result;
 }
 
-int
-has_modify_increment(context, ldap_server)
-    krb5_context     context;
-    char             *ldap_server;
+krb5_boolean
+has_modify_increment(krb5_context context, const char *server_name)
 {
-    return has_rootdse_ava(context, ldap_server,
-                           "supportedFeatures", "1.3.6.1.1.14");
+    return has_rootdse_ava(context, server_name, "supportedFeatures",
+                           "1.3.6.1.1.14");
 }
 
 void *
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
index aa8e7ce..319c701 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.h
@@ -147,7 +147,7 @@ extern void prepend_err_str (krb5_context ctx, const char *s, krb5_error_code er
 #define KDB_TL_USERDN             0x03
 #define KDB_TL_KEYINFO            0x04
 #define KDB_TL_MASK               0x05
-#define KDB_TL_CONTAINERDN        0x06
+/* 0x06 was KDB_TL_CONTAINERDN but is no longer used */
 #define KDB_TL_LINKDN             0x07
 
 
@@ -159,12 +159,6 @@ extern void prepend_err_str (krb5_context ctx, const char *s, krb5_error_code er
 #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;
@@ -206,7 +200,6 @@ typedef struct _krb5_ldap_context {
     char                          *bind_pwd;
     char                          *service_password_file;
     char                          *root_certificate_file;
-    krb5_ldap_certificates        **certificates;
     krb5_ui_4                     cert_count; /* certificate count */
     k5_mutex_t                    hndl_lock;
     char                          *container_dn;
@@ -270,13 +263,10 @@ 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 *);
-
-int
-has_modify_increment(krb5_context, char *);
+krb5_boolean
+has_modify_increment(krb5_context, const char *);
 
-krb5_error_code
+void
 krb5_ldap_free_server_context_params(krb5_ldap_context *ldap_context);
 
 krb5_error_code
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
index 3ebfb87..78ea428 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap_conn.c
@@ -37,45 +37,40 @@
 #include "ldap_service_stash.h"
 #include <kdb5.h>
 
+/* Ensure that we have the parameters we need to authenticate to the LDAP
+ * server.  Read the password if necessary. */
 static krb5_error_code
-krb5_validate_ldap_context(krb5_context context,
-                           krb5_ldap_context *ldap_context)
+validate_context(krb5_context context, krb5_ldap_context *ctx)
 {
-    krb5_error_code             st=0;
-    unsigned char               *password=NULL;
+    krb5_error_code ret;
 
-    if (ldap_context->bind_dn == NULL) {
-        st = EINVAL;
-        k5_setmsg(context, st, _("LDAP bind dn value missing "));
-        goto err_out;
+    if (ctx->bind_dn == NULL) {
+        k5_setmsg(context, EINVAL, _("LDAP bind dn value missing"));
+        return EINVAL;
     }
 
-    if (ldap_context->bind_pwd == NULL && ldap_context->service_password_file == NULL) {
-        st = EINVAL;
-        k5_setmsg(context, st, _("LDAP bind password value missing "));
-        goto err_out;
+    if (ctx->bind_pwd == NULL && ctx->service_password_file == NULL) {
+        k5_setmsg(context, EINVAL, _("LDAP bind password value missing"));
+        return EINVAL;
     }
 
-    if (ldap_context->bind_pwd == NULL &&
-        ldap_context->service_password_file != NULL) {
-        if ((st=krb5_ldap_readpassword(context, ldap_context, &password)) != 0) {
+    if (ctx->bind_pwd == NULL && ctx->service_password_file != NULL) {
+        ret = krb5_ldap_readpassword(context, ctx->service_password_file,
+                                     ctx->bind_dn, &ctx->bind_pwd);
+        if (ret) {
             prepend_err_str(context, _("Error reading password from stash: "),
-                            st, st);
-            goto err_out;
+                            ret, ret);
+            return ret;
         }
-
-        ldap_context->bind_pwd = (char *)password;
     }
 
-    /* NULL password not allowed */
-    if (ldap_context->bind_pwd != NULL && strlen(ldap_context->bind_pwd) == 0) {
-        st = EINVAL;
-        k5_setmsg(context, st, _("Service password length is zero"));
-        goto err_out;
+    /* An empty password is not allowed. */
+    if (*ctx->bind_pwd == '\0') {
+        k5_setmsg(context, EINVAL, _("Service password length is zero"));
+        return EINVAL;
     }
 
-err_out:
-    return st;
+    return 0;
 }
 
 /*
@@ -83,59 +78,60 @@ err_out:
  */
 
 static krb5_error_code
-krb5_ldap_bind(krb5_ldap_context *ldap_context,
-               krb5_ldap_server_handle *ldap_server_handle)
+authenticate(krb5_ldap_context *ctx, krb5_ldap_server_handle *server)
 {
-    struct berval               bv={0, NULL};
-
-    bv.bv_val = ldap_context->bind_pwd;
-    bv.bv_len = strlen(ldap_context->bind_pwd);
-    return ldap_sasl_bind_s(ldap_server_handle->ldap_handle,
-                            ldap_context->bind_dn, NULL, &bv, NULL,
-                            NULL, NULL);
+    int st;
+    struct berval bv;
+
+    bv.bv_val = ctx->bind_pwd;
+    bv.bv_len = strlen(ctx->bind_pwd);
+    st = ldap_sasl_bind_s(server->ldap_handle, ctx->bind_dn, NULL, &bv, NULL,
+                          NULL, NULL);
+    if (st != LDAP_SUCCESS) {
+        k5_setmsg(ctx->kcontext, KRB5_KDB_ACCESS_ERROR,
+                  _("Cannot bind to LDAP server '%s' as '%s': %s"),
+                  server->server_info->server_name, ctx->bind_dn,
+                  ldap_err2string(st));
+        return KRB5_KDB_ACCESS_ERROR;
+    }
+    return 0;
 }
 
 static krb5_error_code
-krb5_ldap_initialize(krb5_ldap_context *ldap_context,
-                     krb5_ldap_server_info *server_info)
+initialize_server(krb5_ldap_context *ldap_context, krb5_ldap_server_info *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) {
+    krb5_ldap_server_handle *server;
+    krb5_error_code ret;
+    int st;
+
+    server = calloc(1, sizeof(krb5_ldap_server_handle));
+    if (server == NULL)
+        return ENOMEM;
+    server->server_info = info;
+
+    st = ldap_initialize(&server->ldap_handle, info->server_name);
+    if (st) {
+        free(server);
         k5_setmsg(ldap_context->kcontext, KRB5_KDB_ACCESS_ERROR,
                   _("Cannot create LDAP handle for '%s': %s"),
-                  server_info->server_name, ldap_err2string(st));
-        st = KRB5_KDB_ACCESS_ERROR;
-        goto err_out;
+                  info->server_name, ldap_err2string(st));
+        return KRB5_KDB_ACCESS_ERROR;
     }
 
-    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 {
-        k5_setmsg(ldap_context->kcontext, KRB5_KDB_ACCESS_ERROR,
-                  _("Cannot bind to LDAP server '%s' as '%s': %s"),
-                  server_info->server_name, ldap_context->bind_dn,
-                  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);
+    ret = authenticate(ldap_context, server);
+    if (ret) {
+        info->server_status = OFF;
+        time(&info->downtime);
+        free(server);
+        return ret;
     }
 
-err_out:
-    return st;
+    server->server_info_update_pending = FALSE;
+    server->next = info->ldap_server_handles;
+    info->ldap_server_handles = server;
+    info->num_conns++;
+    info->server_status = ON;
+    return 0;
 }
 
 /*
@@ -143,17 +139,20 @@ err_out:
  */
 
 krb5_error_code
-krb5_ldap_db_init(krb5_context context, krb5_ldap_context *ldap_context)
+krb5_ldap_db_init(krb5_context context, krb5_ldap_context *ctx)
 {
-    krb5_error_code             st=0;
-    int                         cnt=0, version=LDAP_VERSION3;
-    struct timeval              local_timelimit = {10,0};
+    krb5_error_code ret;
+    int i, version = LDAP_VERSION3;
+    unsigned int conns;
+    krb5_ldap_server_info *info;
+    struct timeval local_timelimit = { 10, 0 };
 
-    if ((st=krb5_validate_ldap_context(context, ldap_context)) != 0)
-        return st;
+    ret = validate_context(context, ctx);
+    if (ret)
+        return ret;
 
 #ifdef LDAP_OPT_DEBUG_LEVEL
-    ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldap_context->ldap_debug);
+    ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ctx->ldap_debug);
 #endif
     ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
@@ -162,37 +161,33 @@ krb5_ldap_db_init(krb5_context context, krb5_ldap_context *ldap_context)
     ldap_set_option(NULL, LDAP_X_OPT_CONNECT_TIMEOUT, &local_timelimit);
 #endif
 
-    HNDL_LOCK(ldap_context);
-    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;
-
+    HNDL_LOCK(ctx);
+    for (i = 0; ctx->server_info_list[i] != NULL; i++) {
+        info = ctx->server_info_list[i];
+        if (info->server_status == NOTSET) {
             krb5_clear_error_message(context);
 
 #ifdef LDAP_MOD_INCREMENT
-            server_info->modify_increment =
-                (has_modify_increment(context, server_info->server_name) == 0);
+            info->modify_increment = has_modify_increment(context,
+                                                          info->server_name);
 #else
-            server_info->modify_increment = 0;
-#endif /* LDAP_MOD_INCREMENT */
+            info->modify_increment = 0;
+#endif
 
-            for (conns=0; conns < ldap_context->max_server_conns; ++conns) {
-                if ((st=krb5_ldap_initialize(ldap_context, server_info)) != 0)
+            for (conns = 0; conns < ctx->max_server_conns; conns++) {
+                ret = initialize_server(ctx, info);
+                if (ret)
                     break;
-            } /* for (conn= ... */
+            }
 
-            if (server_info->server_status == ON)
-                break;  /* server init successful, so break */
+            /* If we opened a connection, don't try any more servers. */
+            if (info->server_status == ON)
+                break;
         }
-        ++cnt;
     }
-    HNDL_UNLOCK(ldap_context);
+    HNDL_UNLOCK(ctx);
 
-    return st;
+    return ret;
 }
 
 
@@ -211,7 +206,7 @@ krb5_ldap_db_single_init(krb5_ldap_context *ldap_context)
         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);
+                st = initialize_server(ldap_context, server_info);
                 if (st == LDAP_SUCCESS)
                     goto cleanup;
             }
@@ -224,7 +219,7 @@ krb5_ldap_db_single_init(krb5_ldap_context *ldap_context)
     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);
+        st = initialize_server(ldap_context, server_info);
         if (st == LDAP_SUCCESS)
             goto cleanup;
         ++cnt;
@@ -237,12 +232,15 @@ krb5_error_code
 krb5_ldap_rebind(krb5_ldap_context *ldap_context,
                  krb5_ldap_server_handle **ldap_server_handle)
 {
-    krb5_ldap_server_handle     *handle = *ldap_server_handle;
+    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);
+    if (ldap_initialize(&handle->ldap_handle,
+                        handle->server_info->server_name) != LDAP_SUCCESS ||
+        authenticate(ldap_context, handle) != 0) {
+        return krb5_ldap_request_next_handle_from_pool(ldap_context,
+                                                       ldap_server_handle);
+    }
     return LDAP_SUCCESS;
 }
 
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c
index 4cac857..ae51905 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c
@@ -28,7 +28,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <errno.h>
-#include "kdb_xdr.h"
+#include <kdb.h>
 
 #define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n)))
 
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.h b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.h
deleted file mode 100644
index 7e45710..0000000
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-#ifndef _KDB2_XDR_H
-#define _KDB2_XDR_H
-
-#include "kdb.h"
-
-krb5_error_code
-krb5_encode_princ_dbkey(krb5_context context,
-                        krb5_data *key,
-                        krb5_const_principal principal);
-
-krb5_error_code
-krb5_decode_princ_contents(krb5_context context,
-                           krb5_data *content,
-                           krb5_db_entry *entry);
-
-void
-krb5_dbe_free_contents(krb5_context context,
-                       krb5_db_entry *entry);
-
-krb5_error_code
-krb5_encode_princ_contents(krb5_context context,
-                           krb5_data *content,
-                           krb5_db_entry *entry);
-
-
-void
-krb5_free_princ_dbkey(krb5_context context,
-                      krb5_data *key);
-
-void
-krb5_free_princ_contents(krb5_context context,
-                         krb5_data *contents);
-
-#endif
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c
index 616a7e2..77d8f81 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.c
@@ -163,27 +163,6 @@ krb5_put_ldap_handle(krb5_ldap_server_handle *ldap_server_handle)
 }
 
 /*
- * Add a new ldap server handle structure to the server info structure.
- * This function name can be changed to krb5_insert_ldap_handle.
- * Do not lock the mutex here. The caller should lock it
- */
-
-krb5_error_code
-krb5_update_ldap_handle(krb5_ldap_server_handle *ldap_server_handle,
-                        krb5_ldap_server_info *server_info)
-{
-
-    if (ldap_server_handle == NULL || server_info == NULL)
-        return 0;
-
-    ldap_server_handle->next = server_info->ldap_server_handles;
-    server_info->ldap_server_handles = ldap_server_handle;
-    server_info->num_conns++;
-    ldap_server_handle->server_info = server_info;
-    return 0;
-}
-
-/*
  * Free up all the ldap server handles of the server info.
  * This function is called when the ldap server returns LDAP_SERVER_DOWN.
  */
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h
index 73ea3d8..f56dead3 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_handle.h
@@ -32,9 +32,6 @@
 #define _LDAP_HANDLE_H_
 
 krb5_error_code
-krb5_update_ldap_handle(krb5_ldap_server_handle *, krb5_ldap_server_info *);
-
-krb5_error_code
 krb5_ldap_request_handle_from_pool(krb5_ldap_context *, krb5_ldap_server_handle **);
 
 krb5_error_code
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c
index 4ef7f2e..7668ee5 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_krbcontainer.c
@@ -40,7 +40,6 @@ krb5_error_code
 krb5_ldap_read_krbcontainer_dn(krb5_context context, char **container_dn)
 {
     krb5_error_code                 st=0;
-    LDAP                            *ld=NULL;
     char                            *dn=NULL;
     kdb5_dal_handle                 *dal_handle=NULL;
     krb5_ldap_context               *ldap_context=NULL;
@@ -48,7 +47,6 @@ krb5_ldap_read_krbcontainer_dn(krb5_context context, char **container_dn)
 
     *container_dn = NULL;
     SETUP_CONTEXT();
-    GET_HANDLE();
 
     /* read kerberos containter location from [dbmodules] section of krb5.conf file */
     if (ldap_context->conf_section) {
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
index 779121f..6c1ac5d 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
@@ -42,130 +42,96 @@
 #include <ctype.h>
 
 #ifdef NEED_STRPTIME_PROTO
-extern char *strptime (const char *, const char *, struct tm *);
+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
+static void remove_overlapping_subtrees(char **listin, int *subtcount,
+                                        int sscope);
 
-static char *
-my_strndup(const char *input, size_t limit)
+/* Set an extended error message about being unable to read name. */
+static krb5_error_code
+attr_read_error(krb5_context ctx, krb5_error_code code, const char *name)
 {
-    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);
+    k5_setmsg(ctx, code, _("Error reading '%s' attribute: %s"), name,
+              error_message(code));
+    return code;
 }
 
-/* Get integer or string values from the config section, falling back
-   to the default section, then to hard-coded values.  */
-static errcode_t
+/* Get integer or string values from the config section, falling back to the
+ * default section, then to hard-coded values. */
+static krb5_error_code
 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) {
-        k5_setmsg(ctx, err, _("Error reading '%s' attribute: %s"), name,
-                  error_message(err));
-        return err;
-    }
-    if (out_temp != 0) {
-        *out = out_temp;
+    krb5_error_code ret;
+    int val;
+
+    ret = profile_get_integer(ctx->profile, KDB_MODULE_SECTION, conf_section,
+                              name, 0, &val);
+    if (ret)
+        return attr_read_error(ctx, ret, name);
+    if (val != 0) {
+        *out = val;
         return 0;
     }
-    err = profile_get_integer (ctx->profile,
-                               KDB_MODULE_DEF_SECTION, name, 0,
-                               dfl, &out_temp);
-    if (err) {
-        k5_setmsg(ctx, err, _("Error reading '%s' attribute: %s"), name,
-                  error_message(err));
-        return err;
-    }
-    *out = out_temp;
+    ret = profile_get_integer(ctx->profile, KDB_MODULE_DEF_SECTION, name, NULL,
+                              dfl, &val);
+    if (ret)
+        return attr_read_error(ctx, ret, name);
+    *out = val;
     return 0;
 }
 
-/* Get integer or string values from the config section, falling back
-   to the default section, then to hard-coded values.  */
-static errcode_t
+/* Get integer or string values from the config section, falling back to the
+ * default section, then to hard-coded values. */
+static krb5_error_code
 prof_get_boolean_def(krb5_context ctx, const char *conf_section,
                      const char *name, krb5_boolean dfl, krb5_boolean *out)
 {
-    errcode_t err;
-    int out_temp = 0;
-
-    err = profile_get_boolean(ctx->profile, KDB_MODULE_SECTION, conf_section,
-                              name, -1, &out_temp);
-    if (err) {
-        k5_setmsg(ctx, err, _("Error reading '%s' attribute: %s"), name,
-                  error_message(err));
-        return err;
-    }
-    if (out_temp != -1) {
-        *out = out_temp;
+    krb5_error_code ret;
+    int val = 0;
+
+    ret = profile_get_boolean(ctx->profile, KDB_MODULE_SECTION, conf_section,
+                              name, -1, &val);
+    if (ret)
+        return attr_read_error(ctx, ret, name);
+    if (val != -1) {
+        *out = val;
         return 0;
     }
-    err = profile_get_boolean(ctx->profile, KDB_MODULE_DEF_SECTION, name, 0,
-                              dfl, &out_temp);
-    if (err) {
-        k5_setmsg(ctx, err, _("Error reading '%s' attribute: %s"), name,
-                  error_message(err));
-        return err;
-    }
-    *out = out_temp;
+    ret = profile_get_boolean(ctx->profile, KDB_MODULE_DEF_SECTION, name, NULL,
+                              dfl, &val);
+    if (ret)
+        return attr_read_error(ctx, ret, name);
+    *out = val;
     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
+/* We don't have non-null defaults in any of our calls, so don't bother with
+ * the extra argument. */
+static krb5_error_code
 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) {
-        k5_setmsg(ctx, err, _("Error reading '%s' attribute: %s"), name,
-                  error_message(err));
-        return err;
-    }
-    if (*out != 0)
+    krb5_error_code ret;
+
+    ret = profile_get_string(ctx->profile, KDB_MODULE_SECTION, conf_section,
+                             name, NULL, out);
+    if (ret)
+        return attr_read_error(ctx, ret, name);
+    if (*out != NULL)
         return 0;
-    err = profile_get_string (ctx->profile,
-                              KDB_MODULE_DEF_SECTION, name, 0,
-                              0, out);
-    if (err) {
-        k5_setmsg(ctx, err, _("Error reading '%s' attribute: %s"), name,
-                  error_message(err));
-        return err;
-    }
+    ret = profile_get_string(ctx->profile, KDB_MODULE_DEF_SECTION, name, NULL,
+                             NULL, out);
+    if (ret)
+        return attr_read_error(ctx, ret, name);
     return 0;
 }
 
 static krb5_error_code
 get_db_opt(const char *input, char **opt_out, char **val_out)
 {
+    krb5_error_code ret;
     const char *pos;
     char *opt, *val = NULL;
     size_t len;
@@ -181,7 +147,9 @@ get_db_opt(const char *input, char **opt_out, char **val_out)
         /* Ignore trailing spaces. */
         while (len > 0 && isspace((unsigned char)input[len - 1]))
             len--;
-        opt = strndup(input, len);
+        opt = k5memdup0(input, len, &ret);
+        if (opt == NULL)
+            return ret;
 
         pos++;                  /* Move past '='. */
         while (isspace(*pos))   /* Ignore leading spaces. */
@@ -202,17 +170,17 @@ get_db_opt(const char *input, char **opt_out, char **val_out)
 static krb5_error_code
 add_server_entry(krb5_context context, const char *name)
 {
-    krb5_ldap_context *lctx = context->dal_handle->db_context;
+    krb5_ldap_context *ctx = context->dal_handle->db_context;
     krb5_ldap_server_info **sp, **list, *server;
     size_t count = 0;
 
     /* Allocate list space for the new entry and null terminator. */
-    for (sp = lctx->server_info_list; sp != NULL && *sp != NULL; sp++)
+    for (sp = ctx->server_info_list; sp != NULL && *sp != NULL; sp++)
         count++;
-    list = realloc(lctx->server_info_list, (count + 2) * sizeof(*list));
+    list = realloc(ctx->server_info_list, (count + 2) * sizeof(*list));
     if (list == NULL)
         return ENOMEM;
-    lctx->server_info_list = list;
+    ctx->server_info_list = list;
 
     server = calloc(1, sizeof(krb5_ldap_server_info));
     if (server == NULL)
@@ -232,59 +200,58 @@ krb5_error_code
 krb5_ldap_parse_db_params(krb5_context context, char **db_args)
 {
     char *opt = NULL, *val = NULL;
-    krb5_error_code status = 0;
-    krb5_ldap_context *lctx = context->dal_handle->db_context;
+    krb5_error_code ret = 0;
+    krb5_ldap_context *ctx = context->dal_handle->db_context;
 
     if (db_args == NULL)
         return 0;
     for (; *db_args != NULL; db_args++) {
-        status = get_db_opt(*db_args, &opt, &val);
-        if (status)
+        ret = get_db_opt(*db_args, &opt, &val);
+        if (ret)
             goto cleanup;
 
         /* Check for options which don't require values. */
         if (!strcmp(opt, "temporary")) {
             /* "temporary" is passed by kdb5_util load without -update,
              * which we don't support. */
-            status = EINVAL;
-            k5_setmsg(context, status,
-                      _("KDB module requires -update argument"));
+            ret = EINVAL;
+            k5_setmsg(context, ret, _("KDB module requires -update argument"));
             goto cleanup;
         }
 
         if (val == NULL) {
-            status = EINVAL;
-            k5_setmsg(context, status, _("'%s' value missing"), opt);
+            ret = EINVAL;
+            k5_setmsg(context, ret, _("'%s' value missing"), opt);
             goto cleanup;
         }
 
         /* Check for options which do require arguments. */
         if (!strcmp(opt, "binddn")) {
-            free(lctx->bind_dn);
-            lctx->bind_dn = strdup(val);
-            if (lctx->bind_dn == NULL) {
-                status = ENOMEM;
+            free(ctx->bind_dn);
+            ctx->bind_dn = strdup(val);
+            if (ctx->bind_dn == NULL) {
+                ret = ENOMEM;
                 goto cleanup;
             }
         } else if (!strcmp(opt, "nconns")) {
-            lctx->max_server_conns = atoi(val) ? atoi(val) :
+            ctx->max_server_conns = atoi(val) ? atoi(val) :
                 DEFAULT_CONNS_PER_SERVER;
         } else if (!strcmp(opt, "bindpwd")) {
-            free(lctx->bind_pwd);
-            lctx->bind_pwd = strdup(val);
-            if (lctx->bind_pwd == NULL) {
-                status = ENOMEM;
+            free(ctx->bind_pwd);
+            ctx->bind_pwd = strdup(val);
+            if (ctx->bind_pwd == NULL) {
+                ret = ENOMEM;
                 goto cleanup;
             }
         } else if (!strcmp(opt, "host")) {
-            status = add_server_entry(context, val);
-            if (status)
+            ret = add_server_entry(context, val);
+            if (ret)
                 goto cleanup;
         } else if (!strcmp(opt, "debug")) {
-            lctx->ldap_debug = atoi(val);
+            ctx->ldap_debug = atoi(val);
         } else {
-            status = EINVAL;
-            k5_setmsg(context, status, _("unknown option '%s'"), opt);
+            ret = EINVAL;
+            k5_setmsg(context, ret, _("unknown option '%s'"), opt);
             goto cleanup;
         }
 
@@ -296,7 +263,14 @@ krb5_ldap_parse_db_params(krb5_context context, char **db_args)
 cleanup:
     free(opt);
     free(val);
-    return status;
+    return ret;
+}
+
+/* Pick kdc_var or kadmind_var depending on the server type. */
+static inline const char *
+choose_var(int srv_type, const char *kdc_var, const char *kadmind_var)
+{
+    return (srv_type == KRB5_KDB_SRV_TYPE_KDC) ? kdc_var : kadmind_var;
 }
 
 /*
@@ -308,264 +282,151 @@ krb5_error_code
 krb5_ldap_read_server_params(krb5_context context, char *conf_section,
                              int srv_type)
 {
-    char                        *tempval=NULL, *save_ptr=NULL, *item=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;
-
-    dal_handle = context->dal_handle;
-    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
+    char *servers, *save_ptr, *item;
+    const char *delims = "\t\n\f\v\r ,", *name;
+    krb5_error_code ret = 0;
+    kdb5_dal_handle *dal_handle = context->dal_handle;
+    krb5_ldap_context *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;
-        }
+    if (conf_section != NULL) {
+        ldap_context->conf_section = strdup(conf_section);
+        if (ldap_context->conf_section == NULL)
+            return ENOMEM;
     }
 
-    /* initialize the mutexs and condition variable */
-    /* this portion logically doesn't fit here should be moved appropriately */
+    /* This mutex is used in the LDAP connection pool. */
+    if (k5_mutex_init(&(ldap_context->hndl_lock)) != 0)
+        return KRB5_KDB_SERVER_INTERNAL_ERR;
 
-    /* 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.
-     */
+    /* Read the maximum number of LDAP connections per server. */
     if (ldap_context->max_server_conns == 0) {
-        st = prof_get_integer_def (context, conf_section,
+        ret = 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 (ret)
+            return ret;
     }
 
     if (ldap_context->max_server_conns < 2) {
-        st = EINVAL;
-        k5_setmsg(context, st,
+        k5_setmsg(context, EINVAL,
                   _("Minimum connections required per server is 2"));
-        goto cleanup;
+        return EINVAL;
     }
 
-    /*
-     * 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.
-     */
+    /* Read the DN used to connect to the LDAP server. */
     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_KADMIND_DN;
-
-        if (name) {
-            st = prof_get_string_def (context, conf_section, name,
-                                      &ldap_context->bind_dn);
-            if (st)
-                goto cleanup;
-        }
+        name = choose_var(srv_type, KRB5_CONF_LDAP_KDC_DN,
+                          KRB5_CONF_LDAP_KADMIND_DN);
+        ret = prof_get_string_def(context, conf_section, name,
+                                  &ldap_context->bind_dn);
+        if (ret)
+            return ret;
     }
 
-    /*
-     * Read service_password_file parameter from database module
-     * section of conf file this file contains stashed passwords of
-     * the KDC, ADMIN and PASSWD dns.
-     */
+    /* Read the filename containing stashed DN passwords. */
     if (ldap_context->service_password_file == NULL) {
-        st = prof_get_string_def (context, conf_section,
+        ret = prof_get_string_def(context, conf_section,
                                   KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE,
                                   &ldap_context->service_password_file);
-        if (st)
-            goto cleanup;
+        if (ret)
+            return ret;
     }
 
-    /*
-     * If the ldap server parameter is not set read the list of ldap
-     * servers from the database module section of the conf file.
-     */
-
+    /* Read the LDAP server URL list. */
     if (ldap_context->server_info_list == NULL) {
-        if ((st=profile_get_string(context->profile, KDB_MODULE_SECTION, conf_section,
-                                   KRB5_CONF_LDAP_SERVERS, NULL, &tempval)) != 0) {
-            k5_setmsg(context, st,
-                      _("Error reading 'ldap_servers' attribute"));
-            goto cleanup;
-        }
-
-        if (tempval == NULL) {
-            st = add_server_entry(context, "ldapi://");
-            if (st)
-                goto cleanup;
+        ret = profile_get_string(context->profile, KDB_MODULE_SECTION,
+                                 conf_section, KRB5_CONF_LDAP_SERVERS, NULL,
+                                 &servers);
+        if (ret)
+            return attr_read_error(context, ret, KRB5_CONF_LDAP_SERVERS);
+
+        if (servers == NULL) {
+            ret = add_server_entry(context, "ldapi://");
+            if (ret)
+                return ret;
         } else {
-            item = strtok_r(tempval, delims, &save_ptr);
+            item = strtok_r(servers, delims, &save_ptr);
             while (item != NULL) {
-                st = add_server_entry(context, item);
-                if (st)
-                    goto cleanup;
-                item = strtok_r(NULL,delims,&save_ptr);
+                ret = add_server_entry(context, item);
+                if (ret) {
+                    profile_release_string(servers);
+                    return ret;
+                }
+                item = strtok_r(NULL, delims, &save_ptr);
             }
-            profile_release_string(tempval);
+            profile_release_string(servers);
         }
     }
 
-    if ((st = prof_get_boolean_def(context, conf_section,
-                                   KRB5_CONF_DISABLE_LAST_SUCCESS, FALSE,
-                                   &ldap_context->disable_last_success)))
-        goto cleanup;
-
-    if ((st = prof_get_boolean_def(context, conf_section,
-                                   KRB5_CONF_DISABLE_LOCKOUT, FALSE,
-                                   &ldap_context->disable_lockout)))
-        goto cleanup;
+    ret = prof_get_boolean_def(context, conf_section,
+                               KRB5_CONF_DISABLE_LAST_SUCCESS, FALSE,
+                               &ldap_context->disable_last_success);
+    if (ret)
+        return ret;
 
-cleanup:
-    return(st);
+    return prof_get_boolean_def(context, conf_section,
+                                KRB5_CONF_DISABLE_LOCKOUT, FALSE,
+                                &ldap_context->disable_lockout);
 }
 
-/*
- * This function frees the krb5_ldap_context structure members.
- */
-
-krb5_error_code
-krb5_ldap_free_server_context_params(krb5_ldap_context *ldap_context)
+void
+krb5_ldap_free_server_context_params(krb5_ldap_context *ctx)
 {
-    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);
-            }
-            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;
-                    free(ldap_server_handle);
-                    ldap_server_handle = next_ldap_server_handle;
-                }
-            }
-            free(ldap_context->server_info_list[i]);
-            i++;
+    int i;
+    krb5_ldap_server_info **list;
+    krb5_ldap_server_handle *h, *next;
+
+    if (ctx == NULL)
+        return;
+
+    list = ctx->server_info_list;
+    for (i = 0; list != NULL && list[i] != NULL; i++) {
+        free(list[i]->server_name);
+        for (h = list[i]->ldap_server_handles; h != NULL; h = next) {
+            next = h->next;
+            ldap_unbind_ext_s(h->ldap_handle, NULL, NULL);
+            free(h);
         }
-        free(ldap_context->server_info_list);
-    }
-
-    if (ldap_context->conf_section != NULL) {
-        free(ldap_context->conf_section);
-        ldap_context->conf_section = NULL;
+        free(list[i]);
     }
+    free(list);
+    ctx->server_info_list = NULL;
 
-    if (ldap_context->bind_dn != NULL) {
-        free(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));
-        free(ldap_context->bind_pwd);
-        ldap_context->bind_pwd = NULL;
-    }
-
-    if (ldap_context->service_password_file != NULL) {
-        free(ldap_context->service_password_file);
-        ldap_context->service_password_file = NULL;
-    }
-
-    if (ldap_context->certificates) {
-        i=0;
-        while (ldap_context->certificates[i] != NULL) {
-            free(ldap_context->certificates[i]->certificate);
-            free(ldap_context->certificates[i]);
-            ++i;
-        }
-        free(ldap_context->certificates);
-    }
-
-    return(0);
+    free(ctx->conf_section);
+    free(ctx->bind_dn);
+    zapfreestr(ctx->bind_pwd);
+    free(ctx->service_password_file);
+    ctx->conf_section = ctx->bind_dn = ctx->bind_pwd = NULL;
+    ctx->service_password_file = NULL;
 }
 
-krb5_error_code
-krb5_ldap_free_server_params(krb5_ldap_context *ldap_context)
+void
+krb5_ldap_free_server_params(krb5_ldap_context *ctx)
 {
-    if (ldap_context == NULL)
-        return 0;
-
-    krb5_ldap_free_server_context_params(ldap_context);
-
-    k5_mutex_destroy(&ldap_context->hndl_lock);
-    free(ldap_context);
-    return(0);
+    if (ctx == NULL)
+        return;
+    krb5_ldap_free_server_context_params(ctx);
+    k5_mutex_destroy(&ctx->hndl_lock);
+    free(ctx);
 }
 
-/*
- * 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
+/* Return true if princ is in the default realm of ldap_context or is a
+ * cross-realm TGS principal for that realm. */
+krb5_boolean
 is_principal_in_realm(krb5_ldap_context *ldap_context,
-                      krb5_const_principal searchfor)
+                      krb5_const_principal princ)
 {
-    char                        *defrealm=NULL;
-
-#define FIND_MAX(a,b) ((a) > (b) ? (a) : (b))
-
-    defrealm = ldap_context->lrparams->realm_name;
+    const char *realm = 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 (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)
-        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;
+    if (princ->length == 2 &&
+        data_eq_string(princ->data[0], "krbtgt") &&
+        data_eq_string(princ->data[1], realm))
+        return TRUE;
+    return data_eq_string(princ->realm, realm);
 }
 
-
 /*
  * Deduce the subtree information from the context. A realm can have
  * multiple subtrees.
@@ -590,12 +451,10 @@ krb5_error_code
 krb5_get_subtree_info(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;
+    krb5_error_code ret;
+    int subtreecount, count = 0, search_scope;
+    char **subtree, *realm_cont_dn, *containerref;
+    char **subtarr = NULL;
 
     containerref = ldap_context->lrparams->containerref;
     subtree = ldap_context->lrparams->subtree;
@@ -603,292 +462,208 @@ krb5_get_subtree_info(krb5_ldap_context *ldap_context, char ***subtreearr,
     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;
+    /* Leave space for realm DN, containerref, and null terminator. */
+    subtarr = k5calloc(subtreecount + 3, sizeof(char *), &ret);
+    if (subtarr == NULL)
         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;
+    /* Get the complete subtree list. */
+    while (count < subtreecount && subtree[count] != NULL) {
+        subtarr[count] = strdup(subtree[count]);
+        if (subtarr[count++] == NULL) {
+            ret = ENOMEM;
             goto cleanup;
         }
     }
 
-    subtarr[i] = strdup(realm_cont_dn);
-    if (subtarr[i++] == NULL) {
-        st = ENOMEM;
+    subtarr[count] = strdup(realm_cont_dn);
+    if (subtarr[count++] == NULL) {
+        ret = ENOMEM;
         goto cleanup;
     }
 
     if (containerref != NULL) {
-        subtarr[i] = strdup(containerref);
-        if (subtarr[i++] == NULL) {
-            st = ENOMEM;
+        subtarr[count] = strdup(containerref);
+        if (subtarr[count++] == NULL) {
+            ret = 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;
+    remove_overlapping_subtrees(subtarr, &count, search_scope);
+    *ntree = count;
+    *subtreearr = subtarr;
+    subtarr = NULL;
+    count = 0;
 
 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;
+    while (count > 0)
+        free(subtarr[--count]);
+    free(subtarr);
+    return ret;
 }
 
-/*
- * 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.
- */
+/* Reallocate tl and return a pointer to the new space, or NULL on failure. */
+static unsigned char *
+expand_tl_data(krb5_tl_data *tl, uint16_t len)
+{
+    unsigned char *newptr;
+
+    if (len > UINT16_MAX - tl->tl_data_length)
+        return NULL;
+    newptr = realloc(tl->tl_data_contents, tl->tl_data_length + len);
+    if (newptr == NULL)
+        return NULL;
+    tl->tl_data_contents = newptr;
+    tl->tl_data_length += len;
+    return tl->tl_data_contents + tl->tl_data_length - len;
+}
 
+/* Append a one-byte type, a two-byte length, and a value to a KDB_TL_USER_INFO
+ * tl_data item.  The length is inferred from type and value. */
 krb5_error_code
-store_tl_data(krb5_tl_data *tl_data, int tl_type, void *value)
+store_tl_data(krb5_tl_data *tl, int type, void *value)
 {
-    unsigned int                currlen=0, tldatalen=0;
-    unsigned char               *curr=NULL;
-    void                        *reallocptr=NULL;
+    unsigned char *ptr;
+    int ival;
+    char *str;
+    size_t len;
 
-    tl_data->tl_data_type = KDB_TL_USER_INFO;
-    switch (tl_type) {
+    tl->tl_data_type = KDB_TL_USER_INFO;
+    switch (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);
+        ival = *(int *)value;
+        if (ival > UINT16_MAX)
+            return EINVAL;
+        ptr = expand_tl_data(tl, 5);
+        if (ptr == NULL)
             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;
+        *ptr = type;
+        store_16_be(2, ptr + 1);
+        store_16_be(ival, ptr + 3);
         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);
+        str = value;
+        len = strlen(str);
+        if (len > UINT16_MAX - 3)
             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;
+        ptr = expand_tl_data(tl, 3 + len);
+        if (ptr == NULL)
+            return ENOMEM;
+        *ptr = type;
+        store_16_be(len, ptr + 1);
+        memcpy(ptr + 3, str, len);
         break;
-    }
 
     default:
-        return 1;
-
+        return EINVAL;
     }
     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(krb5_tl_data *tl_data, int tl_type, void **data)
+/* Scan tl for a value of the given type and return it in allocated memory.
+ * For KDB_TL_LINKDN, return a list of all values found. */
+static krb5_error_code
+decode_tl_data(krb5_tl_data *tl, int type, void **data_out)
 {
-    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 = k5memdup0(curr, sublen, &st);
-                if (DN == NULL)
-                    return st;
-                *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;
-                }
+    krb5_error_code ret;
+    const unsigned char *ptr, *end;
+    uint16_t len;
+    size_t linkcount = 0, i;
+    char **dnlist = NULL, **newlist;
+    int *intptr;
+
+    *data_out = NULL;
+
+    /* Find the first matching subfield or return ENOENT.  For KDB_TL_LINKDN,
+     * keep iterating after finding a match as it may be repeated. */
+    ptr = tl->tl_data_contents;
+    end = ptr + tl->tl_data_length;
+    for (;;) {
+        if (end - ptr < 3)
+            break;
+        len = load_16_be(ptr + 1);
+        if (len > (end - ptr) - 3)
+            break;
+        if (*ptr != type) {
+            ptr += 3 + len;
+            continue;
+        }
+        ptr += 3;
+
+        switch (type) {
+        case KDB_TL_PRINCCOUNT:
+        case KDB_TL_PRINCTYPE:
+        case KDB_TL_MASK:
+            if (len != 2)
+                return EINVAL;
+            intptr = malloc(sizeof(int));
+            if (intptr == NULL)
+                return ENOMEM;
+            *intptr = load_16_be(ptr);
+            *data_out = intptr;
+            return 0;
 
-                /* get the length of the content */
-                UNSTORE16_INT(curr, sublen);
-                /* forward by 2 bytes */
-                curr += 2;
-                DNarr[i] = k5memdup0(curr, sublen, &st);
-                if (DNarr[i] == NULL)
-                    return st;
-                ++i;
-                curr += sublen;
-                *data = DNarr;
-                st=0;
-                break;
-            }
-        } else {
-            /* move to the current content block */
-            UNSTORE16_INT(curr, sublen);
-            curr += 2 + sublen;
+        case KDB_TL_USERDN:
+            *data_out = k5memdup0(ptr, len, &ret);
+            return ret;
+
+        case KDB_TL_LINKDN:
+            newlist = realloc(dnlist, (linkcount + 2) * sizeof(char *));
+            if (newlist == NULL)
+                goto oom;
+            dnlist = newlist;
+            dnlist[linkcount] = k5memdup0(ptr, len, &ret);
+            if (dnlist[linkcount] == NULL)
+                goto oom;
+            dnlist[linkcount + 1] = NULL;
+            linkcount++;
+            break;
         }
+
+        ptr += len;
     }
-    return st;
+
+    if (type != KDB_TL_LINKDN || dnlist == NULL)
+        return ENOENT;
+    *data_out = dnlist;
+    return 0;
+
+oom:
+    for (i = 0; i < linkcount; i++)
+        free(dnlist[i]);
+    free(dnlist);
+    return ENOMEM;
 }
 
 /*
  * wrapper routines for decode_tl_data
  */
 static krb5_error_code
-krb5_get_int_from_tl_data(krb5_context context, krb5_db_entry *entries,
-                          int type, int *intval)
+get_int_from_tl_data(krb5_context context, krb5_db_entry *entry, int type,
+                     int *intval)
 {
-    krb5_error_code             st=0;
-    krb5_tl_data                tl_data;
-    void                        *voidptr=NULL;
-    int                         *intptr=NULL;
+    krb5_error_code ret;
+    krb5_tl_data tl_data;
+    void *ptr;
+    int *intptr;
 
     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;
+    ret = krb5_dbe_lookup_tl_data(context, entry, &tl_data);
+    if (ret || tl_data.tl_data_length == 0)
+        return ret;
 
-    if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
-        intptr = (int *) voidptr;
+    if (decode_tl_data(&tl_data, type, &ptr) == 0) {
+        intptr = ptr;
         *intval = *intptr;
         free(intptr);
     }
 
-cleanup:
-    return st;
+    return 0;
 }
 
 /*
@@ -896,171 +671,132 @@ cleanup:
  * object (user, policy ...).
  */
 krb5_error_code
-krb5_get_attributes_mask(krb5_context context, krb5_db_entry *entries,
+krb5_get_attributes_mask(krb5_context context, krb5_db_entry *entry,
                          int *mask)
 {
-    return krb5_get_int_from_tl_data(context, entries, KDB_TL_MASK, mask);
+    return get_int_from_tl_data(context, entry, KDB_TL_MASK, mask);
 }
 
 krb5_error_code
-krb5_get_princ_type(krb5_context context, krb5_db_entry *entries, int *ptype)
+krb5_get_princ_type(krb5_context context, krb5_db_entry *entry, int *ptype)
 {
-    return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCTYPE, ptype);
+    return get_int_from_tl_data(context, entry, KDB_TL_PRINCTYPE, ptype);
 }
 
 krb5_error_code
-krb5_get_princ_count(krb5_context context, krb5_db_entry *entries, int *pcount)
+krb5_get_princ_count(krb5_context context, krb5_db_entry *entry, int *pcount)
 {
-    return krb5_get_int_from_tl_data(context, entries, KDB_TL_PRINCCOUNT, pcount);
+    return get_int_from_tl_data(context, entry, KDB_TL_PRINCCOUNT, pcount);
 }
 
 krb5_error_code
-krb5_get_linkdn(krb5_context context, krb5_db_entry *entries, char ***link_dn)
+krb5_get_linkdn(krb5_context context, krb5_db_entry *entry, char ***link_dn)
 {
-    krb5_error_code             st=0;
-    krb5_tl_data                tl_data;
-    void                        *voidptr=NULL;
+    krb5_error_code ret;
+    krb5_tl_data tl_data;
+    void *ptr;
 
     *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;
+    ret = krb5_dbe_lookup_tl_data(context, entry, &tl_data);
+    if (ret || tl_data.tl_data_length == 0)
+        return ret;
 
-    if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &voidptr) == 0) {
-        *link_dn = (char **) voidptr;
-    }
+    if (decode_tl_data(&tl_data, KDB_TL_LINKDN, &ptr) == 0)
+        *link_dn = ptr;
 
-cleanup:
-    return st;
+    return 0;
 }
 
 static krb5_error_code
-krb5_get_str_from_tl_data(krb5_context context, krb5_db_entry *entries,
-                          int type, char **strval)
+get_str_from_tl_data(krb5_context context, krb5_db_entry *entry, int type,
+                     char **strval)
 {
-    krb5_error_code             st=0;
-    krb5_tl_data                tl_data;
-    void                        *voidptr=NULL;
+    krb5_error_code ret;
+    krb5_tl_data tl_data;
+    void *ptr;
 
-    if (type != KDB_TL_USERDN && type != KDB_TL_CONTAINERDN) {
-        st = EINVAL;
-        goto cleanup;
-    }
+    if (type != KDB_TL_USERDN)
+        return EINVAL;
 
     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;
+    ret = krb5_dbe_lookup_tl_data(context, entry, &tl_data);
+    if (ret || tl_data.tl_data_length == 0)
+        return ret;
 
-    if (decode_tl_data(&tl_data, type, &voidptr) == 0) {
-        *strval = (char *) voidptr;
-    }
+    if (decode_tl_data(&tl_data, type, &ptr) == 0)
+        *strval = ptr;
 
-cleanup:
-    return st;
+    return 0;
 }
 
 krb5_error_code
-krb5_get_userdn(krb5_context context, krb5_db_entry *entries, char **userdn)
+krb5_get_userdn(krb5_context context, krb5_db_entry *entry, char **userdn)
 {
     *userdn = NULL;
-    return krb5_get_str_from_tl_data(context, entries, KDB_TL_USERDN, userdn);
-}
-
-krb5_error_code
-krb5_get_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);
+    return get_str_from_tl_data(context, entry, KDB_TL_USERDN, userdn);
 }
 
 /*
- * 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.
+ * If attribute or attrvalues is NULL, just check for the existence of dn.
+ * Otherwise, read values for attribute from dn; then set the bit 1<<n in mask
+ * for each attrvalues[n] which is present in the values read.
  */
-
 krb5_error_code
 checkattributevalue(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;
+    krb5_error_code ret;
+    int one = 1, i, j;
+    char **values = NULL, *attributes[2] = { NULL };
+    LDAPMessage *result = NULL, *entry;
 
-    if (strlen(dn) == 0) {
-        st = set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH);
-        return st;
-    }
+    if (strlen(dn) == 0)
+        return set_ldap_error(0, LDAP_NO_SUCH_OBJECT, OP_SEARCH);
 
     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);
-        goto cleanup;
+    /* Read values for attribute from the dn, or check for its existence. */
+    ret = ldap_search_ext_s(ld, dn, LDAP_SCOPE_BASE, 0, attributes, 0, NULL,
+                            NULL, &timelimit, LDAP_NO_LIMIT, &result);
+    if (ret != LDAP_SUCCESS) {
+        ldap_msgfree(result);
+        return set_ldap_error(0, ret, OP_SEARCH);
     }
 
-    /*
-     * If the attribute/attrvalues is NULL, then check for the
-     * existence of the object alone.
-     */
+    /* Don't touch *mask if we are only checking for existence. */
     if (attribute == NULL || attrvalues == NULL)
-        goto cleanup;
+        goto done;
 
-    /* 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;
-                    }
-                }
+    entry = ldap_first_entry(ld, result);
+    if (entry == NULL)
+        goto done;
+    values = ldap_get_values(ld, entry, attribute);
+    if (values == NULL)
+        goto done;
+
+    /* Set bits in mask for each matching value we read. */
+    for (i = 0; attrvalues[i]; i++) {
+        for (j = 0; values[j]; j++) {
+            if (strcasecmp(attrvalues[i], values[j]) == 0) {
+                *mask |= (one << i);
+                break;
             }
-            ldap_value_free(values);
         }
     }
 
-cleanup:
+done:
     ldap_msgfree(result);
-    return st;
+    ldap_value_free(values);
+    return 0;
 }
 
-
 static krb5_error_code
 getepochtime(char *strtime, krb5_timestamp *epochtime)
 {
-    struct tm           tme;
+    struct tm tme;
 
     memset(&tme, 0, sizeof(tme));
     if (strptime(strtime,"%Y%m%d%H%M%SZ", &tme) == NULL) {
@@ -1071,251 +807,194 @@ getepochtime(char *strtime, krb5_timestamp *epochtime)
     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.
- */
-
+/* Get the integer value of attribute from int.  If it is not found, return
+ * ENOENT and set *val_out to 0. */
 krb5_error_code
-krb5_ldap_get_value(LDAP *ld, LDAPMessage *ent, char *attribute, int *retval)
+krb5_ldap_get_value(LDAP *ld, LDAPMessage *ent, char *attribute, int *val_out)
 {
-    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;
+    char **values;
+
+    *val_out = 0;
+    values = ldap_get_values(ld, ent, attribute);
+    if (values == NULL)
+        return ENOENT;
+    if (values[0] != NULL)
+        *val_out = atoi(values[0]);
+    ldap_value_free(values);
+    return 0;
 }
 
-/*
- * krb5_ldap_get_string() - Returns the first string of the
- * attribute.  Intended to
- *
- *
- */
+/* Return the first string value of attribute in ent. */
 krb5_error_code
 krb5_ldap_get_string(LDAP *ld, LDAPMessage *ent, char *attribute,
-                     char **retstr, krb5_boolean *attr_present)
+                     char **str_out, krb5_boolean *attr_present)
 {
-    char                           **values=NULL;
-    krb5_error_code                st=0;
+    char **values;
+    krb5_error_code ret = 0;
 
-    *retstr = NULL;
+    *str_out = 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(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) {
+    values = ldap_get_values(ld, ent, attribute);
+    if (values == NULL)
+        return 0;
+    if (values[0] != 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);
+        *str_out = strdup(values[0]);
+        if (*str_out == NULL)
+            ret = ENOMEM;
     }
-
-cleanup:
-    if (st != 0) {
-        if (*retarr != NULL) {
-            for (i=0; i< count; ++i)
-                if ((*retarr)[i] != NULL)
-                    free ((*retarr)[i]);
-            free (*retarr);
-        }
-    }
-    return st;
+    ldap_value_free(values);
+    return ret;
 }
 
-krb5_error_code
-krb5_ldap_get_time(LDAP *ld, LDAPMessage *ent, char *attribute,
-                   krb5_timestamp *rettime, krb5_boolean *attr_present)
+static krb5_error_code
+get_time(LDAP *ld, LDAPMessage *ent, char *attribute, krb5_timestamp *time_out,
+         krb5_boolean *attr_present)
 {
-    char                         **values=NULL;
-    krb5_error_code              st=0;
+    char **values = NULL;
+    krb5_error_code ret = 0;
 
-    *rettime = 0;
+    *time_out = 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);
+    values = ldap_get_values(ld, ent, attribute);
+    if (values == NULL)
+        return 0;
+    if (values[0] != NULL) {
+        *attr_present = TRUE;
+        ret = getepochtime(values[0], time_out);
     }
-    return st;
+    ldap_value_free(values);
+    return ret;
 }
 
-/*
- * 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(LDAPMod ***mods, int *count)
+/* Add an entry to *list_inout and return it in *mod_out. */
+static krb5_error_code
+alloc_mod(LDAPMod ***list_inout, LDAPMod **mod_out)
 {
-    int i=0;
-    LDAPMod **lmods=NULL;
+    size_t count;
+    LDAPMod **mods = *list_inout;
 
-    if ((*mods) != NULL) {
-        for (;(*mods)[i] != NULL; ++i)
-            ;
-    }
-    lmods = (LDAPMod **) realloc((*mods), (2+i) * sizeof(LDAPMod *));
-    if (lmods == NULL)
+    *mod_out = NULL;
+
+    for (count = 0; mods != NULL && mods[count] != NULL; count++);
+    mods = realloc(mods, (count + 2) * sizeof(*mods));
+    if (mods == NULL)
         return ENOMEM;
+    *list_inout = mods;
 
-    *mods = lmods;
-    (*mods)[i+1] = NULL;
-    (*mods)[i] = (LDAPMod *) calloc(1, sizeof (LDAPMod));
-    if ((*mods)[i] == NULL)
+    mods[count] = calloc(1, sizeof(LDAPMod));
+    if (mods[count] == NULL)
         return ENOMEM;
-    *count = i;
+    mods[count + 1] = NULL;
+    *mod_out = mods[count];
     return 0;
 }
 
 krb5_error_code
-krb5_add_str_mem_ldap_mod(LDAPMod ***mods, char *attribute, int op,
+krb5_add_str_mem_ldap_mod(LDAPMod ***list, char *attribute, int op,
                           char **values)
 {
-    int i=0, j=0;
-    krb5_error_code   st=0;
+    krb5_error_code ret;
+    LDAPMod *mod;
+    size_t count, i;
 
-    if ((st=krb5_add_member(mods, &i)) != 0)
-        return st;
+    ret = alloc_mod(list, &mod);
+    if (ret)
+        return ret;
 
-    (*mods)[i]->mod_type = strdup(attribute);
-    if ((*mods)[i]->mod_type == NULL)
+    mod->mod_type = strdup(attribute);
+    if (mod->mod_type == NULL)
         return ENOMEM;
-    (*mods)[i]->mod_op = op;
+    mod->mod_op = op;
+
+    mod->mod_values = NULL;
+    if (values == NULL)
+        return 0;
 
-    (*mods)[i]->mod_values = NULL;
+    for (count = 0; values[count] != NULL; count++);
+    mod->mod_values = calloc(count + 1, sizeof(char *));
+    if (mod->mod_values == NULL)
+        return ENOMEM;
 
-    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)
+    for (i = 0; i < count; i++) {
+        mod->mod_values[i] = strdup(values[i]);
+        if (mod->mod_values[i] == 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;
     }
+    mod->mod_values[i] = NULL;
     return 0;
 }
 
 krb5_error_code
-krb5_add_ber_mem_ldap_mod(LDAPMod ***mods, char *attribute, int op,
+krb5_add_ber_mem_ldap_mod(LDAPMod ***list, char *attribute, int op,
                           struct berval **ber_values)
 {
-    int i=0, j=0;
-    krb5_error_code   st=0;
+    krb5_error_code ret;
+    LDAPMod *mod;
+    size_t count, i;
 
-    if ((st=krb5_add_member(mods, &i)) != 0)
-        return st;
+    ret = alloc_mod(list, &mod);
+    if (ret)
+        return ret;
 
-    (*mods)[i]->mod_type = strdup(attribute);
-    if ((*mods)[i]->mod_type == NULL)
+    mod->mod_type = strdup(attribute);
+    if (mod->mod_type == NULL)
         return ENOMEM;
-    (*mods)[i]->mod_op = op;
+    mod->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)
+    for (count = 0; ber_values[count] != NULL; count++);
+    mod->mod_bvalues = calloc(count + 1, sizeof(struct berval *));
+    if (mod->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)
+    for (i = 0; i < count; i++) {
+        mod->mod_bvalues[i] = calloc(1, sizeof(struct berval));
+        if (mod->mod_bvalues[i] == NULL)
             return ENOMEM;
 
-        (*mods)[i]->mod_bvalues[j]->bv_len = ber_values[j]->bv_len;
-        (*mods)[i]->mod_bvalues[j]->bv_val =
-            k5memdup(ber_values[j]->bv_val, ber_values[j]->bv_len, &st);
-        if ((*mods)[i]->mod_bvalues[j]->bv_val == NULL)
-            return ENOMEM;
+        mod->mod_bvalues[i]->bv_len = ber_values[i]->bv_len;
+        mod->mod_bvalues[i]->bv_val = k5memdup(ber_values[i]->bv_val,
+                                               ber_values[i]->bv_len, &ret);
+        if (mod->mod_bvalues[i]->bv_val == NULL)
+            return ret;
     }
-    (*mods)[i]->mod_bvalues[j] = NULL;
+    mod->mod_bvalues[i] = NULL;
     return 0;
 }
 
 static inline char *
-format_d (int val)
+format_d(int val)
 {
-    char tmpbuf[2+3*sizeof(val)];
+    char tmpbuf[3 * sizeof(val) + 2];
+
     snprintf(tmpbuf, sizeof(tmpbuf), "%d", val);
     return strdup(tmpbuf);
 }
 
 krb5_error_code
-krb5_add_int_mem_ldap_mod(LDAPMod ***mods, char *attribute, int op, int value)
+krb5_add_int_mem_ldap_mod(LDAPMod ***list, char *attribute, int op, int value)
 {
-    int i=0;
-    krb5_error_code      st=0;
+    krb5_error_code ret;
+    LDAPMod *mod;
 
-    if ((st=krb5_add_member(mods, &i)) != 0)
-        return st;
+    ret = alloc_mod(list, &mod);
+    if (ret)
+        return ret;
 
-    (*mods)[i]->mod_type = strdup(attribute);
-    if ((*mods)[i]->mod_type == NULL)
+    mod->mod_type = strdup(attribute);
+    if (mod->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)
+    mod->mod_op = op;
+    mod->mod_values = calloc(2, sizeof(char *));
+    if (mod->mod_values == NULL)
+        return ENOMEM;
+    mod->mod_values[0] = format_d(value);
+    if (mod->mod_values[0] == NULL)
         return ENOMEM;
     return 0;
 }
@@ -1324,6 +1003,7 @@ krb5_error_code
 krb5_ldap_lock(krb5_context kcontext, int mode)
 {
     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
+
     k5_setmsg(kcontext, status, "LDAP %s", error_message(status));
     return status;
 }
@@ -1332,13 +1012,14 @@ krb5_error_code
 krb5_ldap_unlock(krb5_context kcontext)
 {
     krb5_error_code status = KRB5_PLUGIN_OP_NOTSUPP;
+
     k5_setmsg(kcontext, status, "LDAP %s", error_message(status));
     return status;
 }
 
 
 /*
- * Get the number of times an object has been referred to in a realm. this is
+ * 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
@@ -1348,16 +1029,14 @@ 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;
-
+    int n, st, tempst, gothandle = 0;
+    unsigned int i, ntrees = 0;
+    char *refcntattr[2];
+    char *filter = NULL, *corrected = NULL, **subtree = 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;
@@ -1370,38 +1049,35 @@ krb5_ldap_get_reference_count(krb5_context context, char *dn, char *refattr,
         gothandle = 1;
     }
 
-    refcntattr [0] = refattr;
-    refcntattr [1] = NULL;
+    refcntattr[0] = refattr;
+    refcntattr[1] = NULL;
 
-    ptr = ldap_filter_correct (dn);
-    if (ptr == NULL) {
+    corrected = ldap_filter_correct(dn);
+    if (corrected == NULL) {
         st = ENOMEM;
         goto cleanup;
     }
 
-    if (asprintf (&filter, "%s=%s", refattr, ptr) < 0) {
+    if (asprintf(&filter, "%s=%s", refattr, corrected) < 0) {
         filter = NULL;
         st = ENOMEM;
         goto cleanup;
     }
 
-    if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
+    st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees);
+    if (st)
         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);
+        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);
+            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);
+            st = translate_ldap_error(errcode, OP_SEARCH);
             goto cleanup;
         }
 
@@ -1412,81 +1088,67 @@ krb5_ldap_get_reference_count(krb5_context context, char *dn, char *refattr,
     }
 
 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)
+    free(filter);
+    ldap_msgfree(result);
+    for (i = 0; i < ntrees; i++)
+        free(subtree[i]);
+    free(subtree);
+    free(corrected);
+    if (gothandle)
         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.
- */
+/* Extract a name from policy_dn, which must be directly under the realm
+ * container. */
 krb5_error_code
-krb5_ldap_policydn_to_name(krb5_context context, char *policy_dn, char **name)
+krb5_ldap_policydn_to_name(krb5_context context, const char *policy_dn,
+                           char **name_out)
 {
-    int len1, len2;
-    krb5_error_code             st = 0;
-    kdb5_dal_handle             *dal_handle=NULL;
-    krb5_ldap_context           *ldap_context=NULL;
+    size_t len1, len2, plen;
+    krb5_error_code ret;
+    kdb5_dal_handle *dal_handle;
+    krb5_ldap_context *ldap_context;
+    const char *realmdn;
 
+    *name_out = 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;
-    }
+    realmdn = ldap_context->lrparams->realmdn;
+    if (realmdn == NULL)
+        return EINVAL;
 
-    if (strcmp (ldap_context->lrparams->realmdn, policy_dn + (len2 - len1)) != 0) {
-        st = EINVAL;
-        goto cleanup;
-    }
+    /* policyn_dn should be "cn=<policyname>,<realmdn>". */
+    len1 = strlen(realmdn);
+    len2 = strlen(policy_dn);
+    if (len1 == 0 || len2 == 0 || len1 + 1 >= len2)
+        return EINVAL;
+    plen = len2 - len1 - 1;
+    if (policy_dn[plen] != ',' || strcmp(realmdn, policy_dn + plen + 1) != 0)
+        return EINVAL;
 
 #if defined HAVE_LDAP_STR2DN
     {
         char *rdn;
         LDAPDN dn;
-        rdn = strndup(policy_dn, len2 - len1 - 1); /* 1 character for ',' */
 
-        st = ldap_str2dn(rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC);
+        rdn = k5memdup0(policy_dn, plen, &ret);
+        if (rdn == NULL)
+            return ret;
+        ret = ldap_str2dn(rdn, &dn, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PEDANTIC);
         free(rdn);
-        if (st != 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;
+        if (ret)
+            return EINVAL;
+        if (dn[0] == NULL || dn[1] != NULL ||
+            dn[0][0]->la_attr.bv_len != 2 ||
+            strncasecmp(dn[0][0]->la_attr.bv_val, "cn", 2) != 0) {
+            ret = EINVAL;
+        } else {
+            *name_out = k5memdup0(dn[0][0]->la_value.bv_val,
+                                  dn[0][0]->la_value.bv_len, &ret);
         }
-
         ldap_dnfree(dn);
+        return ret;
     }
 #elif defined HAVE_LDAP_EXPLODE_DN
     {
@@ -1494,140 +1156,93 @@ krb5_ldap_policydn_to_name(krb5_context context, char *policy_dn, char **name)
 
         /* 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);
-        }
+        if (parsed_dn == NULL)
+            return EINVAL;
+        *name_out = strdup(parsed_dn[0]);
+        if (*name_out == NULL)
+            return ENOMEM;
+        ldap_value_free(parsed_dn);
+        return 0;
     }
 #else
-    st = EINVAL;
+    return EINVAL;
 #endif
-
-cleanup:
-    return st;
 }
 
+/* Compute the policy DN for the given policy name. */
 krb5_error_code
 krb5_ldap_name_to_policydn(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;
+    int st;
+    char *corrected;
+    kdb5_dal_handle *dal_handle;
+    krb5_ldap_context *ldap_context;
 
     *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;
+        *policy_dn = strdup("");
+        return (*policy_dn == NULL) ? ENOMEM : 0;
     }
 
     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);
+    if (ldap_context->lrparams->realmdn == NULL)
+        return EINVAL;
 
-    len += sizeof ("cn=") + 3;
+    corrected = ldap_filter_correct(name);
+    if (corrected == NULL)
+        return ENOMEM;
 
-    *policy_dn = (char *) malloc (len);
-    if (*policy_dn == NULL) {
-        st = ENOMEM;
-        goto cleanup;
+    st = asprintf(policy_dn, "cn=%s,%s", corrected,
+                  ldap_context->lrparams->realmdn);
+    free(corrected);
+    if (st == -1) {
+        *policy_dn = NULL;
+        return ENOMEM;
     }
+    return 0;
+}
 
-    sprintf (*policy_dn, "cn=%s,%s", ptr, ldap_context->lrparams->realmdn);
-
-cleanup:
-    if (ptr != NULL)
-        free (ptr);
-    return st;
+/* Return true if dn1 is a subtree of dn2. */
+static inline krb5_boolean
+is_subtree(const char *dn1, size_t len1, const char *dn2, size_t len2)
+{
+    return len1 > len2 && dn1[len1 - len2 - 1] == ',' &&
+        strcasecmp(dn1 + (len1 - len2), dn2) == 0;
 }
 
-/* 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)
+/* Remove overlapping and repeated subtree entries from the list of subtrees.
+ * If sscope is not 2 (sub), only remove repeated entries. */
+static void
+remove_overlapping_subtrees(char **list, 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;
+    size_t ilen, jlen;
+    int i, j;
+    int count = *subtcount;
+
+    for (i = 0; i < count && list[i] != NULL; i++) {
+        ilen = strlen(list[i]);
+        for (j = i + 1; j < count && list[j] != NULL; j++) {
+            jlen = strlen(list[j]);
+            /* Remove list[j] if it is identical to list[i] or a subtree of it.
+             * Remove list[i] if it is a subtree of list[j]. */
+            if ((ilen == jlen && strcasecmp(list[j], list[i]) == 0) ||
+                (sscope == 2 && is_subtree(list[j], jlen, list[i], ilen))) {
+                free(list[j]);
+                list[j--] = list[count - 1];
+                list[--count] = NULL;
+            } else if (sscope == 2 &&
+                       is_subtree(list[i], ilen, list[j], jlen)) {
+                free(list[i]);
+                list[i--] = list[count - 1];
+                list[--count] = NULL;
+                break;
             }
         }
     }
-    *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;
+    *subtcount = count;
 }
 
 /*
@@ -1639,306 +1254,257 @@ 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;
-    int             val;
-    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;
+    krb5_error_code ret;
+    unsigned int mask = 0;
+    int val, i, pcount, objtype;
+    krb5_boolean attr_present;
+    krb5_kvno mkvno = 0;
+    krb5_timestamp lastpwdchange, unlock_time;
+    char *policydn = NULL, *pwdpolicydn = NULL, *polname = NULL, *user = NULL;
+    char *tktpolname = NULL, *dn = NULL, **link_references = NULL;
+    char **pnvalues = NULL, **ocvalues = NULL, **a2d2 = NULL;
+    struct berval **ber_key_data = NULL, **ber_tl_data = NULL;
+    krb5_tl_data userinfo_tl_data = { NULL }, **endp, *tl;
+
+    ret = krb5_copy_principal(context, princ, &entry->princ);
+    if (ret)
         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)
+    /* get the associated directory user information */
+    pnvalues = ldap_get_values(ld, ent, "krbprincipalname");
+    if (pnvalues != NULL) {
+        ret = krb5_unparse_name(context, princ, &user);
+        if (ret)
             goto cleanup;
 
-        for (i=0; values[i] != NULL; ++i) {
-            if (strcasecmp(values[i], user) == 0) {
-                pcount = ldap_count_values(values);
+        pcount = 0;
+        for (i = 0; pnvalues[i] != NULL; i++) {
+            if (strcasecmp(pnvalues[i], user) == 0) {
+                pcount = ldap_count_values(pnvalues);
                 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);
+        dn = ldap_get_dn(ld, ent);
+        if (dn == NULL) {
+            ldap_get_option(ld, LDAP_OPT_RESULT_CODE, &ret);
+            ret = set_ldap_error(context, ret, 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)
+        ocvalues = ldap_get_values(ld, ent, "objectclass");
+        if (ocvalues != NULL) {
+            for (i = 0; ocvalues[i] != NULL; i++) {
+                if (strcasecmp(ocvalues[i], "krbprincipal") == 0) {
+                    objtype = KDB_STANDALONE_PRINCIPAL_OBJECT;
+                    ret = store_tl_data(&userinfo_tl_data, KDB_TL_PRINCTYPE,
+                                        &objtype);
+                    if (ret)
                         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))
+        /* Add principalcount, DN and principaltype user information to
+         * tl_data */
+        ret = store_tl_data(&userinfo_tl_data, KDB_TL_PRINCCOUNT, &pcount);
+        if (ret)
+            goto cleanup;
+        ret = store_tl_data(&userinfo_tl_data, KDB_TL_USERDN, dn);
+        if (ret)
             goto cleanup;
     }
 
-    /* read all the kerberos attributes */
-
-    /* KRBLASTSUCCESSFULAUTH */
-    if ((st=krb5_ldap_get_time(ld, ent, "krbLastSuccessfulAuth",
-                               &(entry->last_success), &attr_present)) != 0)
+    ret = get_time(ld, ent, "krbLastSuccessfulAuth", &entry->last_success,
+                   &attr_present);
+    if (ret)
         goto cleanup;
-    if (attr_present == TRUE)
+    if (attr_present)
         mask |= KDB_LAST_SUCCESS_ATTR;
 
-    /* KRBLASTFAILEDAUTH */
-    if ((st=krb5_ldap_get_time(ld, ent, "krbLastFailedAuth",
-                               &(entry->last_failed), &attr_present)) != 0)
+    ret = get_time(ld, ent, "krbLastFailedAuth", &entry->last_failed,
+                   &attr_present);
+    if (ret)
         goto cleanup;
-    if (attr_present == TRUE)
+    if (attr_present)
         mask |= KDB_LAST_FAILED_ATTR;
 
-    /* KRBLOGINFAILEDCOUNT */
     if (krb5_ldap_get_value(ld, ent, "krbLoginFailedCount", &val) == 0) {
         entry->fail_auth_count = val;
         mask |= KDB_FAIL_AUTH_COUNT_ATTR;
     }
 
-    /* KRBMAXTICKETLIFE */
-    if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", &(entry->max_life)) == 0)
+    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)
+                            &entry->max_renewable_life) == 0)
         mask |= KDB_MAX_RLIFE_ATTR;
 
-    /* KRBTICKETFLAGS */
-    if (krb5_ldap_get_value(ld, ent, "krbticketflags", &(entry->attributes)) == 0)
+    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)
+    ret = get_time(ld, ent, "krbprincipalexpiration", &entry->expiration,
+                   &attr_present);
+    if (ret)
         goto cleanup;
-    if (attr_present == TRUE)
+    if (attr_present)
         mask |= KDB_PRINC_EXPIRE_TIME_ATTR;
 
-    /* PASSWORD EXPIRATION TIME */
-    if ((st=krb5_ldap_get_time(ld, ent, "krbpasswordexpiration", &(entry->pw_expiration),
-                               &attr_present)) != 0)
+    ret = get_time(ld, ent, "krbpasswordexpiration", &entry->pw_expiration,
+                   &attr_present);
+    if (ret)
         goto cleanup;
-    if (attr_present == TRUE)
+    if (attr_present)
         mask |= KDB_PWD_EXPIRE_TIME_ATTR;
 
-    /* KRBPOLICYREFERENCE */
-
-    if ((st=krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn,
-                                 &attr_present)) != 0)
+    ret = krb5_ldap_get_string(ld, ent, "krbticketpolicyreference", &policydn,
+                               &attr_present);
+    if (ret)
         goto cleanup;
-    if (attr_present == TRUE) {
+    if (attr_present) {
         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)
+        /* Ensure that the policy is inside the realm container. */
+        ret = krb5_ldap_policydn_to_name(context, policydn, &tktpolname);
+        if (ret)
             goto cleanup;
     }
 
-    /* KRBPWDPOLICYREFERENCE */
-    if ((st=krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn,
-                                 &attr_present)) != 0)
+    ret = krb5_ldap_get_string(ld, ent, "krbpwdpolicyreference", &pwdpolicydn,
+                               &attr_present);
+    if (ret)
         goto cleanup;
-    if (attr_present == TRUE) {
+    if (attr_present) {
         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)
+        /* Ensure that the policy is inside the realm container. */
+        ret = krb5_ldap_policydn_to_name(context, pwdpolicydn, &polname);
+        if (ret)
             goto cleanup;
 
-        if ((st = krb5_update_tl_kadm_data(context, entry, polname)) != 0)
+        ret = krb5_update_tl_kadm_data(context, entry, polname);
+        if (ret)
             goto cleanup;
     }
 
-    /* KRBSECRETKEY */
-    if ((bvalues=ldap_get_values_len(ld, ent, "krbprincipalkey")) != NULL) {
-        krb5_kvno mkvno = 0;
-
+    ber_key_data = ldap_get_values_len(ld, ent, "krbprincipalkey");
+    if (ber_key_data != NULL) {
         mask |= KDB_SECRET_KEY_ATTR;
-        if ((st=krb5_decode_krbsecretkey(context, entry, bvalues, &userinfo_tl_data, &mkvno)) != 0)
+        ret = krb5_decode_krbsecretkey(context, entry, ber_key_data,
+                                       &userinfo_tl_data, &mkvno);
+        if (ret)
             goto cleanup;
         if (mkvno != 0) {
-            /* don't add the tl data if mkvno == 0 */
-            if ((st=krb5_dbe_update_mkvno(context, entry, mkvno)) != 0)
+            ret = krb5_dbe_update_mkvno(context, entry, mkvno);
+            if (ret)
                 goto cleanup;
         }
     }
 
-    /* LAST PASSWORD CHANGE */
-    {
-        krb5_timestamp lstpwdchng=0;
-        if ((st=krb5_ldap_get_time(ld, ent, "krbLastPwdChange",
-                                   &lstpwdchng, &attr_present)) != 0)
+    ret = get_time(ld, ent, "krbLastPwdChange", &lastpwdchange, &attr_present);
+    if (ret)
+        goto cleanup;
+    if (attr_present) {
+        ret = krb5_dbe_update_last_pwd_change(context, entry, lastpwdchange);
+        if (ret)
             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;
-        }
+        mask |= KDB_LAST_PWD_CHANGE_ATTR;
     }
 
-    /* LAST ADMIN UNLOCK */
-    {
-        krb5_timestamp unlock_time=0;
-        if ((st=krb5_ldap_get_time(ld, ent, "krbLastAdminUnlock",
-                                   &unlock_time, &attr_present)) != 0)
+    ret = get_time(ld, ent, "krbLastAdminUnlock", &unlock_time, &attr_present);
+    if (ret)
+        goto cleanup;
+    if (attr_present) {
+        ret = krb5_dbe_update_last_admin_unlock(context, entry, unlock_time);
+        if (ret)
             goto cleanup;
-        if (attr_present == TRUE) {
-            if ((st=krb5_dbe_update_last_admin_unlock(context, entry,
-                                                      unlock_time)))
-                goto cleanup;
-            mask |= KDB_LAST_ADMIN_UNLOCK_ATTR;
-        }
+        mask |= KDB_LAST_ADMIN_UNLOCK_ATTR;
     }
 
-    /* ALLOWED TO DELEGATE TO */
-    {
-        char **a2d2 = NULL;
-        int i;
-        krb5_tl_data **tlp;
-
-        st = krb5_ldap_get_strings(ld, ent, "krbAllowedToDelegateTo",
-                                   &a2d2, &attr_present);
-        if (st != 0)
-            goto cleanup;
-
-        if (attr_present == TRUE) {
-            for (tlp = &entry->tl_data; *tlp; tlp = &(*tlp)->tl_data_next)
-                ;
-            for (i = 0; a2d2[i] != NULL; i++) {
-                krb5_tl_data *tl = k5alloc(sizeof(*tl), &st);
-                if (st != 0) {
-                    ldap_value_free(a2d2);
-                    goto cleanup;
-                }
-                tl->tl_data_type = KRB5_TL_CONSTRAINED_DELEGATION_ACL;
-                tl->tl_data_length = strlen(a2d2[i]);
-                tl->tl_data_contents = (krb5_octet *)strdup(a2d2[i]);
-                if (tl->tl_data_contents == NULL) {
-                    st = ENOMEM;
-                    ldap_value_free(a2d2);
-                    free(tl);
-                    goto cleanup;
-                }
-                tl->tl_data_next = NULL;
-                *tlp = tl;
-                tlp = &tl->tl_data_next;
+    a2d2 = ldap_get_values(ld, ent, "krbAllowedToDelegateTo");
+    if (a2d2 != NULL) {
+        for (endp = &entry->tl_data; *endp; endp = &(*endp)->tl_data_next);
+        for (i = 0; a2d2[i] != NULL; i++) {
+            tl = k5alloc(sizeof(*tl), &ret);
+            if (tl == NULL)
+                goto cleanup;
+            tl->tl_data_type = KRB5_TL_CONSTRAINED_DELEGATION_ACL;
+            tl->tl_data_length = strlen(a2d2[i]);
+            tl->tl_data_contents = (unsigned char *)strdup(a2d2[i]);
+            if (tl->tl_data_contents == NULL) {
+                ret = ENOMEM;
+                free(tl);
+                goto cleanup;
             }
-            ldap_value_free(a2d2);
+            tl->tl_data_next = NULL;
+            *endp = tl;
+            endp = &tl->tl_data_next;
         }
     }
 
-    /* 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;
-            }
+    link_references = ldap_get_values(ld, ent, "krbobjectreferences");
+    if (link_references != NULL) {
+        for (i = 0; link_references[i] != NULL; i++) {
+            ret = store_tl_data(&userinfo_tl_data, KDB_TL_LINKDN,
+                                link_references[i]);
+            if (ret)
+                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;
-                st = krb5_dbe_update_tl_data(context, entry, ptr);
-                free(ptr->tl_data_contents);
-                free(ptr);
-                if (st != 0)
-                    break;
-            }
-            ldap_value_free_len (ber_tl_data);
-            if (st != 0)
+    ber_tl_data = ldap_get_values_len(ld, ent, "krbExtraData");
+    if (ber_tl_data != NULL) {
+        for (i = 0; ber_tl_data[i] != NULL; i++) {
+            ret = berval2tl_data(ber_tl_data[i], &tl);
+            if (ret)
+                goto cleanup;
+            ret = krb5_dbe_update_tl_data(context, entry, tl);
+            free(tl->tl_data_contents);
+            free(tl);
+            if (ret)
                 goto cleanup;
-            mask |= KDB_EXTRA_DATA_ATTR;
         }
+        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)
+    /* Update the mask of attributes present on the directory object to the
+     * tl_data. */
+    ret = store_tl_data(&userinfo_tl_data, KDB_TL_MASK, &mask);
+    if (ret)
         goto cleanup;
-    if ((st=krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data)) != 0)
+    ret = krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data);
+    if (ret)
         goto cleanup;
 
-    if ((st=krb5_read_tkt_policy (context, ldap_context, entry, tktpolname)) !=0)
+    ret = krb5_read_tkt_policy(context, ldap_context, entry, tktpolname);
+    if (ret)
         goto cleanup;
 
-    /* XXX so krb5_encode_princ_contents() will be happy */
+    /* For compatibility with DB2 principals. */
     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);
+    ldap_memfree(dn);
+    ldap_value_free_len(ber_key_data);
+    ldap_value_free_len(ber_tl_data);
+    ldap_value_free(pnvalues);
+    ldap_value_free(ocvalues);
+    ldap_value_free(link_references);
+    ldap_value_free(a2d2);
+    free(userinfo_tl_data.tl_data_contents);
+    free(pwdpolicydn);
+    free(polname);
+    free(tktpolname);
+    free(policydn);
+    krb5_free_unparsed_name(context, user);
+    return ret;
 }
 
-/*
- * Solaris libldap does not provide the following functions which are in
- * OpenLDAP.
- */
+/* Solaris libldap does not provide the following functions which are in
+ * OpenLDAP. */
 #ifndef HAVE_LDAP_INITIALIZE
 int
 ldap_initialize(LDAP **ldp, char *url)
@@ -1947,31 +1513,26 @@ ldap_initialize(LDAP **ldp, char *url)
     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 .  */
+    /*
+     * 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) {
+        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;
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h
index c3bb6c8..fb4f3ce 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.h
@@ -38,7 +38,7 @@
 
 /* misc functions */
 
-krb5_error_code
+krb5_boolean
 is_principal_in_realm(krb5_ldap_context *, krb5_const_principal);
 
 krb5_error_code
@@ -60,18 +60,9 @@ krb5_error_code
 krb5_get_userdn(krb5_context, krb5_db_entry *, char **);
 
 krb5_error_code
-krb5_get_containerdn(krb5_context, krb5_db_entry *, char **);
-
-krb5_error_code
 store_tl_data(krb5_tl_data *, int, void *);
 
 krb5_error_code
-decode_tl_data(krb5_tl_data *, int, void **);
-
-krb5_error_code
-is_principal_in_realm(krb5_ldap_context *, krb5_const_principal);
-
-krb5_error_code
 krb5_get_subtree_info(krb5_ldap_context *, char ***, unsigned int *);
 
 krb5_error_code
@@ -80,7 +71,7 @@ krb5_ldap_parse_db_params(krb5_context, char **);
 krb5_error_code
 krb5_ldap_read_server_params(krb5_context , char *, int);
 
-krb5_error_code
+void
 krb5_ldap_free_server_params(krb5_ldap_context *);
 
 krb5_error_code
@@ -93,15 +84,6 @@ krb5_error_code
 krb5_ldap_get_string(LDAP *, LDAPMessage *, char *, char **, krb5_boolean *);
 
 krb5_error_code
-krb5_ldap_get_strings(LDAP *, LDAPMessage *, char *, char ***, krb5_boolean *);
-
-krb5_error_code
-krb5_ldap_get_time(LDAP *, LDAPMessage *, char *, krb5_timestamp *, krb5_boolean *);
-
-krb5_error_code
-krb5_add_member(LDAPMod ***, int *);
-
-krb5_error_code
 krb5_add_str_mem_ldap_mod(LDAPMod  ***, char *, int, char **);
 
 krb5_error_code
@@ -117,7 +99,7 @@ krb5_error_code
 krb5_ldap_get_reference_count (krb5_context, char *, char *, int *, LDAP *);
 
 krb5_error_code
-krb5_ldap_policydn_to_name (krb5_context, char *, char **);
+krb5_ldap_policydn_to_name (krb5_context, const char *, char **);
 
 krb5_error_code
 krb5_ldap_name_to_policydn (krb5_context, char *, char **);
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
index 44bf339..3f3efdc 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
@@ -189,7 +189,7 @@ krb5_ldap_iterate(krb5_context context, char *match_expr,
                         continue;
                     if (krb5_parse_name(context, princ_name, &principal) != 0)
                         continue;
-                    if (is_principal_in_realm(ldap_context, principal) == 0) {
+                    if (is_principal_in_realm(ldap_context, principal)) {
                         if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent, principal,
                                                          &entry)) != 0)
                             goto cleanup;
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
index 06881f0..ce851ea 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
@@ -103,7 +103,7 @@ krb5_ldap_get_principal(krb5_context context, krb5_const_principal searchfor,
 
     CHECK_LDAP_HANDLE(ldap_context);
 
-    if (is_principal_in_realm(ldap_context, searchfor) != 0) {
+    if (!is_principal_in_realm(ldap_context, searchfor)) {
         st = KRB5_KDB_NOENTRY;
         k5_setmsg(context, st, _("Principal does not belong to realm"));
         goto cleanup;
@@ -536,7 +536,7 @@ krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
     /* get ldap handle */
     GET_HANDLE();
 
-    if (is_principal_in_realm(ldap_context, entry->princ) != 0) {
+    if (!is_principal_in_realm(ldap_context, entry->princ)) {
         st = EINVAL;
         k5_setmsg(context, st,
                   _("Principal does not belong to the default realm"));
@@ -1411,7 +1411,6 @@ krb5_decode_krbsecretkey(krb5_context context, krb5_db_entry *entries,
     entries->key_data = key_data;
 
 cleanup:
-    ldap_value_free_len(bvalues);
     free (user);
     return st;
 }
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c
index 94ad9c7..87a2118 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c
@@ -35,8 +35,7 @@
 
 /* Decode a password of the form {HEX}<hexstring>. */
 static krb5_error_code
-dec_password(krb5_context context, const char *str,
-             unsigned char **password_out)
+dec_password(krb5_context context, const char *str, char **password_out)
 {
     size_t len;
     const unsigned char *p;
@@ -72,85 +71,62 @@ dec_password(krb5_context context, const char *str,
     }
     *q = '\0';
 
-    *password_out = password;
+    *password_out = (char *)password;
     return 0;
 }
 
 krb5_error_code
-krb5_ldap_readpassword(krb5_context context, krb5_ldap_context *ldap_context,
-                       unsigned char **password)
+krb5_ldap_readpassword(krb5_context context, const char *filename,
+                       const char *name, char **password_out)
 {
-    int                         entryfound=0;
-    krb5_error_code             st=0;
-    char                        line[RECORDLEN]="0", *start=NULL, *file=NULL;
-    FILE                        *fptr=NULL;
-
-    *password = NULL;
-
-    if (ldap_context->service_password_file)
-        file = ldap_context->service_password_file;
-
-    fptr = fopen(file, "r");
-    if (fptr == NULL) {
-        st = errno;
-        k5_setmsg(context, st, _("Cannot open LDAP password file '%s': %s"),
-                  file, error_message(st));
-        goto rp_exit;
+    krb5_error_code ret;
+    char line[RECORDLEN], *end;
+    const char *start, *sep, *val = NULL;
+    int namelen = strlen(name);
+    FILE *fp;
+
+    *password_out = NULL;
+
+    fp = fopen(filename, "r");
+    if (fp == NULL) {
+        ret = errno;
+        k5_setmsg(context, ret, _("Cannot open LDAP password file '%s': %s"),
+                  filename, error_message(ret));
+        return ret;
     }
-    set_cloexec_file(fptr);
+    set_cloexec_file(fp);
 
-    /* get the record from the file */
-    while (fgets(line, RECORDLEN, fptr)!= NULL) {
-        char tmp[RECORDLEN];
+    while (fgets(line, RECORDLEN, fp) != NULL) {
+        /* Remove trailing newline. */
+        end = line + strlen(line);
+        if (end > line && end[-1] == '\n')
+            end[-1] = '\0';
 
-        tmp[0] = '\0';
-        /* Handle leading white-spaces */
+        /* Skip past leading whitespace. */
         for (start = line; isspace(*start); ++start);
 
-        /* Handle comment lines */
+        /* Ignore comment lines */
         if (*start == '!' || *start == '#')
             continue;
-        sscanf(line, "%*[ \t]%[^#]", tmp);
-        if (tmp[0] == '\0')
-            sscanf(line, "%[^#]", tmp);
-        if (strcasecmp(tmp, ldap_context->bind_dn) == 0) {
-            entryfound = 1; /* service_dn record found !!! */
+
+        sep = strchr(start, '#');
+        if (sep != NULL && sep - start == namelen &&
+            strncasecmp(start, name, namelen) == 0) {
+            val = sep + 1;
             break;
         }
     }
-    fclose (fptr);
+    fclose(fp);
 
-    if (entryfound == 0)  {
-        st = KRB5_KDB_SERVER_INTERNAL_ERR;
-        k5_setmsg(context, st,
+    if (val == NULL) {
+        k5_setmsg(context, KRB5_KDB_SERVER_INTERNAL_ERR,
                   _("Bind DN entry '%s' missing in LDAP password file '%s'"),
-                  ldap_context->bind_dn, file);
-        goto rp_exit;
+                  name, filename);
+        return KRB5_KDB_SERVER_INTERNAL_ERR;
     }
-    /* replace the \n with \0 */
-    start = strchr(line, '\n');
-    if (start)
-        *start = '\0';
-
-    start = strchr(line, '#');
-    if (start == NULL) {
-        /* password field missing */
-        st = KRB5_KDB_SERVER_INTERNAL_ERR;
-        k5_setmsg(context, st, _("Stash file entry corrupt"));
-        goto rp_exit;
-    }
-    ++ start;
 
     /* Extract the plain password information. */
-    st = dec_password(context, start, password);
-
-rp_exit:
-    if (st) {
-        if (*password)
-            free (*password);
-        *password = NULL;
-    }
-    return st;
+    return dec_password(context, val, password_out);
 }
 
 /* Encodes a sequence of bytes in hexadecimal */
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h
index 31511fc..dbf6244 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h
@@ -34,7 +34,8 @@
 #define RECORDLEN 1024
 
 krb5_error_code
-krb5_ldap_readpassword(krb5_context, krb5_ldap_context *, unsigned char **);
+krb5_ldap_readpassword(krb5_context context, const char *filename,
+                       const char *name, char **password_out);
 
 int
 tohex(krb5_data, krb5_data *);


More information about the cvs-krb5 mailing list