Fix plugin to build with Kerberos master tree.
authorSimo Sorce <idra@samba.org>
Wed, 2 Feb 2011 17:16:52 +0000 (12:16 -0500)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 24 Apr 2014 11:27:55 +0000 (13:27 +0200)
src/plugins/kdb/samba/kdb_samba.c
src/plugins/kdb/samba/kdb_samba.h
src/plugins/kdb/samba/kdb_samba_policies.c
src/plugins/kdb/samba/kdb_samba_util.c

index 30579e11461d43e4ce812731ed1370c8167d5da8..78e81b40f8cae043f301e85556ad7361fafe05c2 100644 (file)
@@ -212,15 +212,6 @@ ks_db_get_age(krb5_context context,
     return KRB5_KDB_DBTYPE_NOSUP;
 }
 
-static krb5_error_code
-ks_db_set_option(krb5_context context,
-                 int option,
-                 void *value)
-{
-    /* NOTE: looks like nothing uses this */
-    return KRB5_KDB_DBTYPE_NOSUP;
-}
-
 static krb5_error_code
 ks_db_lock(krb5_context context, int kmode)
 {
@@ -247,7 +238,7 @@ static krb5_error_code
 ks_get_principal(krb5_context context,
                  krb5_const_principal principal,
                  unsigned int flags,
-                 krb5_db_entry *kentry)
+                 krb5_db_entry **kentry)
 {
     struct ks_context *ks = GET_KS_CONTEXT(context);
     char *principal_string = NULL;
@@ -305,26 +296,33 @@ ks_is_tgs_principal(krb5_context context,
 static krb5_error_code
 ks_get_master_key_principal(krb5_context context,
                             krb5_const_principal princ,
-                            krb5_db_entry *kentry,
-                            int *nentries)
+                            krb5_db_entry **kentry_ptr)
 {
     krb5_error_code code;
     krb5_key_data *key_data;
     krb5_timestamp now;
+    krb5_db_entry *kentry;
 
-    memset(kentry, 0, sizeof(*kentry));
-    *nentries = 0;
+    *kentry_ptr = NULL;
+
+    kentry = k5alloc(sizeof(*kentry), &code);
+    if (kentry == NULL) {
+        return code;
+    }
 
     kentry->magic = KRB5_KDB_MAGIC_NUMBER;
     kentry->len = KRB5_KDB_V1_BASE_LENGTH;
     kentry->attributes = KRB5_KDB_DISALLOW_ALL_TIX;
 
-    if (princ == NULL)
+    if (princ == NULL) {
         code = krb5_parse_name(context, KRB5_KDB_M_NAME, &kentry->princ);
-    else
+    } else {
         code = krb5_copy_principal(context, princ, &kentry->princ);
-    if (code != 0)
+    }
+    if (code != 0) {
+        ks_free_krb5_db_entry(context, kentry);
         return code;
+    }
 
     now = time(NULL);
 
@@ -348,10 +346,11 @@ ks_get_master_key_principal(krb5_context context,
     key_data->key_data_kvno         = 1;
     key_data->key_data_type[0]      = ENCTYPE_UNKNOWN;
     if (code != 0) {
+        ks_free_krb5_db_entry(context, kentry);
         return code;
     }
 
-    *nentries = 1;
+    *kentry_ptr = kentry;
 
     return 0;
 }
@@ -368,12 +367,12 @@ ks_is_kadmin_history(krb5_context context,
 static krb5_error_code
 ks_get_dummy_principal(krb5_context context,
                        krb5_const_principal princ,
-                       krb5_db_entry *kentry,
-                       int *nentries)
+                       krb5_db_entry **kentry_ptr)
 {
     krb5_error_code code;
     krb5_key_data *key_data;
     krb5_timestamp now;
+    krb5_db_entry *kentry;
     krb5_keyblock key;
     krb5_data salt;
     krb5_data pwd;
@@ -384,14 +383,19 @@ ks_get_dummy_principal(krb5_context context,
         return KRB5_KDB_NOENTRY;
     }
 
-    memset(kentry, 0, sizeof(*kentry));
-    *nentries = 0;
+    *kentry_ptr = NULL;
+
+    kentry = k5alloc(sizeof(*kentry), &code);
+    if (kentry == NULL) {
+        return code;
+    }
 
     kentry->magic = KRB5_KDB_MAGIC_NUMBER;
     kentry->len = KRB5_KDB_V1_BASE_LENGTH;
 
     code = krb5_copy_principal(context, princ, &kentry->princ);
     if (code != 0) {
+        ks_free_krb5_db_entry(context, kentry);
         return code;
     }
 
@@ -434,7 +438,7 @@ ks_get_dummy_principal(krb5_context context,
     key_data->key_data_length[1]    = salt.length;
     key_data->key_data_contents[1]  = (krb5_octet *)strdup("salt");
 
-    *nentries = 1;
+    *kentry_ptr = kentry;
 
     return 0;
 }
@@ -443,34 +447,29 @@ static krb5_error_code
 ks_db_get_principal(krb5_context context,
                     krb5_const_principal princ,
                     unsigned int kflags,
-                    krb5_db_entry *kentry,
-                    int *nentries,
-                    krb5_boolean *more)
+                    krb5_db_entry **kentry)
 {
     struct ks_context *ks = GET_KS_CONTEXT(context);
     krb5_error_code code;
     unsigned int hflags;
 
-    *nentries = 0;
-    *more = FALSE;
-    memset(kentry, 0, sizeof(*kentry));
-
     if (ks == NULL) {
         return KRB5_KDB_DBNOTINITED;
     }
 
     if (ks_is_master_key_principal(context, princ)) {
-        return ks_get_master_key_principal(context, princ, kentry, nentries);
+        return ks_get_master_key_principal(context, princ, kentry);
     }
 
     /* FIXME: temporarily fake up kadmin history to let kadmin.local work */
     if (ks_is_kadmin_history(context, princ)) {
-        return ks_get_dummy_principal(context, princ, kentry, nentries);
+        return ks_get_dummy_principal(context, princ, kentry);
     }
 
     code = k5_mutex_lock(ks->lock);
-    if (code != 0)
+    if (code != 0) {
         return code;
+    }
 
     hflags = 0;
     if (kflags & KRB5_KDB_FLAG_CANONICALIZE)
@@ -484,53 +483,36 @@ ks_db_get_principal(krb5_context context,
         hflags |= HDB_F_GET_ANY;
 
     code = ks_get_principal(context, princ, hflags, kentry);
-    switch (code) {
-    case 0:
-        *nentries = 1;
-        break;
-    case KRB5_KDB_NOENTRY:
-        code = 0;
-        break;
-    default:
-        break;
-    }
 
     k5_mutex_unlock(ks->lock);
 
     return code;
 }
 
-static krb5_error_code
+static void
 ks_db_free_principal(krb5_context context,
-                     krb5_db_entry *entry,
-                     int count)
+                     krb5_db_entry *entry)
 {
     struct ks_context *ks = GET_KS_CONTEXT(context);
     krb5_error_code code;
-    int i;
 
     if (!ks) {
-        return KRB5_KDB_DBNOTINITED;
+        return;
     }
 
     code = k5_mutex_lock(ks->lock);
     if (code != 0) {
-        return code;
+        return;
     }
 
-    for (i = 0; i < count; i++) {
-        ks_free_krb5_db_entry(context, &entry[i]);
-    }
+    ks_free_krb5_db_entry(context, entry);
 
     k5_mutex_unlock(ks->lock);
-
-    return 0;
 }
 
 static krb5_error_code
 ks_db_put_principal(krb5_context context,
-                    krb5_db_entry *entries,
-                    int *nentries,
+                    krb5_db_entry *entry,
                     char **db_args)
 {
 
@@ -541,8 +523,7 @@ ks_db_put_principal(krb5_context context,
 
 static krb5_error_code
 ks_db_delete_principal(krb5_context context,
-                       krb5_const_principal princ,
-                       int *nentries)
+                       krb5_const_principal princ)
 {
 
     /* NOTE: deferred, samba does not allow the KDC to delete
@@ -574,12 +555,12 @@ ks_db_iterate(krb5_context context,
     code = ks_map_error(error);
 
     while (code == 0) {
-        krb5_db_entry kentry;
+        krb5_db_entry *kentry;
 
         code = ks_unmarshal_hdb_entry(context, hentry, &kentry);
         if (code == 0) {
-            code = (*func)(func_arg, &kentry);
-            ks_free_krb5_db_entry(context, &kentry);
+            code = (*func)(func_arg, kentry);
+            ks_free_krb5_db_entry(context, kentry);
         }
 
         if (code != 0) {
@@ -610,25 +591,6 @@ ks_db_free(krb5_context context, void *ptr)
     free(ptr);
 }
 
-static krb5_error_code
-ks_set_master_key(krb5_context context,
-                  char *pwd,
-                  krb5_keyblock *kkey)
-{
-
-    /* NOTE: samba does not support master keys
-     *       so just ignore the request */
-    return 0;
-}
-
-static krb5_error_code
-ks_get_master_key(krb5_context context,
-                  krb5_keyblock **pkey)
-{
-    /* NOTE: looks like nothing uses this */
-    return KRB5_KDB_DBTYPE_NOSUP;
-}
-
 static krb5_error_code
 ks_fetch_master_key(krb5_context context,
                     krb5_principal name,
@@ -762,57 +724,8 @@ ks_dbekd_encrypt_key_data(krb5_context context,
     return 0;
 }
 
-/*
- * db_invoke() related methods
- */
-
-static struct ks_invoke_table {
-    unsigned int method;
-    krb5_error_code (*function)(krb5_context, unsigned int,
-                                const krb5_data *, krb5_data *);
-} ks_invoke_vtable[] = {
-    { KRB5_KDB_METHOD_CHECK_POLICY_AS,           ks_db_check_policy_as },
-    { KRB5_KDB_METHOD_SIGN_AUTH_DATA,            ks_db_sign_auth_data },
-    { KRB5_KDB_METHOD_CHECK_ALLOWED_TO_DELEGATE, ks_db_check_allowed_to_delegate },
-    { 0, NULL }
-};
-
-static krb5_error_code
-ks_db_invoke(krb5_context context,
-             unsigned int method,
-             const krb5_data *req,
-             krb5_data *rep)
-{
-    struct ks_context *ks = GET_KS_CONTEXT(context);
-    krb5_error_code code;
-    int i;
-
-    if (!ks) {
-        return KRB5_KDB_DBNOTINITED;
-    }
-
-    code = k5_mutex_lock(ks->lock);
-    if (code != 0) {
-        return code;
-    }
-
-    code = KRB5_KDB_DBTYPE_NOSUP;
-
-    for (i = 0; ks_invoke_vtable[i].method; i++) {
-
-        if (ks_invoke_vtable[i].method == method) {
-            code = (ks_invoke_vtable[i].function)(context, method, req, rep);
-            break;
-        }
-    }
-
-    k5_mutex_unlock(ks->lock);
-
-    return code;
-}
-
 kdb_vftabl kdb_function_table = {
-    1,
+    KRB5_KDB_DAL_MAJOR_VERSION,
     0,
     ks_init,
     ks_fini,
@@ -821,7 +734,6 @@ kdb_vftabl kdb_function_table = {
     ks_db_create,
     ks_db_destroy,
     ks_db_get_age,
-    ks_db_set_option,
     ks_db_lock,
     ks_db_unlock,
     ks_db_get_principal,
@@ -829,32 +741,27 @@ kdb_vftabl kdb_function_table = {
     ks_db_put_principal,
     ks_db_delete_principal,
     ks_db_iterate,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
+    NULL, /* create_policy */
+    NULL, /* get_policy */
+    NULL, /* put_policy */
+    NULL, /* iter_policy */
+    NULL, /* delete_policy */
+    NULL, /* free_policy */
     ks_db_alloc,
     ks_db_free,
-    ks_set_master_key,
-    ks_get_master_key,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
     ks_fetch_master_key,
-    NULL,
     ks_fetch_master_key_list,
-    NULL,
-    NULL,
-    NULL,
+    NULL, /* store_master_key_list */
+    NULL, /* dbe_search_enctype */
+    NULL, /* change_pwd */
     ks_promote_db,
     ks_dbekd_decrypt_key_data,
     ks_dbekd_encrypt_key_data,
-    ks_db_invoke,
+    ks_db_sign_auth_data,
+    NULL, /* check_transited_realms */
+    ks_db_check_policy_as,
+    NULL, /* check_policy_tgs */
+    NULL, /* audit_as_req */
+    NULL, /* refresh_config */
+    ks_db_check_allowed_to_delegate
 };
index 533158a9f784e6e62dbe2a476b35120a663b690a..167d39ed97daeda920af776d75713537008b7449 100644 (file)
@@ -118,26 +118,38 @@ ks_unmarshal_Principal(krb5_context context,
 krb5_error_code
 ks_unmarshal_hdb_entry(krb5_context context,
                        struct hdb_entry_ex *hentry,
-                       krb5_db_entry *kentry);
+                       krb5_db_entry **kentry_ptr);
 
 /* from kdb_samba_policies.c */
 
 krb5_error_code
 ks_db_check_allowed_to_delegate(krb5_context context,
-                                unsigned int method,
-                                const krb5_data *req_data,
-                                krb5_data *rep_data);
+                                krb5_const_principal client,
+                                const krb5_db_entry *server,
+                                krb5_const_principal proxy);
 
 krb5_error_code
 ks_db_check_policy_as(krb5_context context,
-                      unsigned int method,
-                      const krb5_data *req_data,
-                      krb5_data *rep_data);
+                      krb5_kdc_req *kdcreq,
+                      krb5_db_entry *client_dbe,
+                      krb5_db_entry *server_dbe,
+                      krb5_timestamp kdc_time,
+                      const char **status,
+                      krb5_data *e_data);
 
 krb5_error_code
 ks_db_sign_auth_data(krb5_context context,
-                     unsigned int method,
-                     const krb5_data *req_data,
-                     krb5_data *rep_data);
+                     unsigned int flags,
+                     krb5_const_principal client_princ,
+                     krb5_db_entry *client,
+                     krb5_db_entry *server,
+                     krb5_db_entry *krbtgt,
+                     krb5_keyblock *client_key,
+                     krb5_keyblock *server_key,
+                     krb5_keyblock *krbtgt_key,
+                     krb5_keyblock *session_key,
+                     krb5_timestamp authtime,
+                     krb5_authdata **tgt_auth_data,
+                     krb5_authdata ***signed_auth_data);
 
 #endif /* _KDB_SAMBA_H_ */
index be0a2f56fe9ebbb48f82b0377e508ca3c8dda363..88c6354883d4b06dc472ac23cd5233790a64481b 100644 (file)
 
 krb5_error_code
 ks_db_check_allowed_to_delegate(krb5_context context,
-                                unsigned int method,
-                                const krb5_data *req_data,
-                                krb5_data *rep_data)
+                                krb5_const_principal client,
+                                const krb5_db_entry *server,
+                                krb5_const_principal proxy)
 {
     struct ks_context *ks = GET_KS_CONTEXT(context);
-    kdb_check_allowed_to_delegate_req *req;
     hdb_entry_ex *delegating_service;
     char *target_name = NULL;
     bool is_enterprise;
     krb5_error_code code;
     int error;
 
-    req = (kdb_check_allowed_to_delegate_req *)req_data->data;
-
 /*
  *  Names are quite odd and confusing in the current implementation.
  *  The following mappings should help understanding what is what.
- *  req->client ->  client to impersonate
- *  req->server; -> delegating service
- *  req->proxy; -> target principal
+ *  client ->  client to impersonate
+ *  server; -> delegating service
+ *  proxy; -> target principal
 */
 
-    delegating_service = (hdb_entry_ex *)req->server->e_data;
+    delegating_service = (hdb_entry_ex *)server->e_data;
 
-    code = krb5_unparse_name(context, req->proxy, &target_name);
+    code = krb5_unparse_name(context, proxy, &target_name);
     if (code) {
         goto done;
     }
 
-    is_enterprise = (req->proxy->type == KRB5_NT_ENTERPRISE_PRINCIPAL);
+    is_enterprise = (proxy->type == KRB5_NT_ENTERPRISE_PRINCIPAL);
 
     error = KS_CHECK_S4U2PROXY(ks, delegating_service,
                                target_name, is_enterprise);
@@ -113,14 +110,14 @@ get_netbios_name(krb5_address **addrs, char **name)
 
 krb5_error_code
 ks_db_check_policy_as(krb5_context context,
-                      unsigned int method,
-                      const krb5_data *req_data,
-                      krb5_data *rep_data)
+                      krb5_kdc_req *kdcreq,
+                      krb5_db_entry *client_dbe,
+                      krb5_db_entry *server_dbe,
+                      krb5_timestamp kdc_time,
+                      const char **status,
+                      krb5_data *e_data)
 {
     struct ks_context *ks = GET_KS_CONTEXT(context);
-    kdb_check_policy_as_req *req;
-    kdb_check_policy_as_rep *rep;
-    krb5_kdc_req *kdcreq;
     krb5_error_code code;
     hdb_entry_ex *client;
     hdb_entry_ex *server;
@@ -129,15 +126,11 @@ ks_db_check_policy_as(krb5_context context,
     char *netbios_name = NULL;
     char *realm = NULL;
     bool password_change = false;
-    DATA_BLOB e_data;
+    DATA_BLOB int_data = { NULL, 0 };
     int error;
 
-    req = (kdb_check_policy_as_req *)req_data->data;
-    rep = (kdb_check_policy_as_rep *)rep_data->data;
-    kdcreq = req->request;
-
-    server = (hdb_entry_ex *)req->server->e_data;
-    client = (hdb_entry_ex *)req->client->e_data;
+    server = (hdb_entry_ex *)server_dbe->e_data;
+    client = (hdb_entry_ex *)client_dbe->e_data;
 
     if (krb5_princ_size(context, kdcreq->server) == 2 &&
         data_eq_string(kdcreq->server->data[0], "kadmin") &&
@@ -175,13 +168,13 @@ ks_db_check_policy_as(krb5_context context,
                              server, server_name,
                              netbios_name,
                              password_change,
-                             &e_data);
+                             &int_data);
     code = ks_map_error(error);
     if (code) {
         goto done;
     }
 
-    rep->e_data = make_data(e_data.data, e_data.length);
+    *e_data = make_data(int_data.data, int_data.length);
 
 done:
     free(realm);
@@ -229,8 +222,13 @@ done:
 
 static krb5_error_code
 ks_verify_pac(krb5_context context,
+              unsigned int flags,
               krb5_const_principal client_princ,
-              kdb_sign_auth_data_req *req,
+              krb5_db_entry *client,
+              krb5_keyblock *server_key,
+              krb5_keyblock *krbtgt_key,
+              krb5_timestamp authtime,
+              krb5_authdata **tgt_auth_data,
               krb5_pac *pac)
 {
     struct ks_context *ks = GET_KS_CONTEXT(context);
@@ -245,7 +243,7 @@ ks_verify_pac(krb5_context context,
 
     /* find the existing PAC, if present */
     code = krb5int_find_authdata(context,
-                                 req->auth_data, NULL,
+                                 tgt_auth_data, NULL,
                                  KRB5_AUTHDATA_WIN2K_PAC,
                                  &authdata);
     if (code != 0) {
@@ -278,22 +276,22 @@ ks_verify_pac(krb5_context context,
      * ticket rather than a TGT; we must verify the server and KDC
      * signatures to assert that the server did not forge the PAC.
      */
-    if (req->flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
-        code = krb5_pac_verify(context, ipac, req->authtime,
+    if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
+        code = krb5_pac_verify(context, ipac, authtime,
                                client_princ,
-                               req->server_key, req->krbtgt_key);
+                               server_key, krbtgt_key);
     } else {
-        code = krb5_pac_verify(context, ipac, req->authtime,
+        code = krb5_pac_verify(context, ipac, authtime,
                                client_princ,
-                               req->krbtgt_key, NULL);
+                               krbtgt_key, NULL);
     }
     if (code != 0) {
         goto done;
     }
 
     /* check and update PAC */
-    if (req->client) {
-        hentry = (hdb_entry_ex *)req->client->e_data;
+    if (client) {
+        hentry = (hdb_entry_ex *)client->e_data;
     }
 
     pac_data.data = authdata[0]->contents;
@@ -326,48 +324,55 @@ done:
 
 krb5_error_code
 ks_db_sign_auth_data(krb5_context context,
-                     unsigned int method,
-                     const krb5_data *req_data,
-                     krb5_data *rep_data)
+                     unsigned int flags,
+                     krb5_const_principal client_princ,
+                     krb5_db_entry *client,
+                     krb5_db_entry *server,
+                     krb5_db_entry *krbtgt,
+                     krb5_keyblock *client_key,
+                     krb5_keyblock *server_key,
+                     krb5_keyblock *krbtgt_key,
+                     krb5_keyblock *session_key,
+                     krb5_timestamp authtime,
+                     krb5_authdata **tgt_auth_data,
+                     krb5_authdata ***signed_auth_data)
 {
-    kdb_sign_auth_data_req *req = (kdb_sign_auth_data_req *)req_data->data;
-    kdb_sign_auth_data_rep *rep = (kdb_sign_auth_data_rep *)rep_data->data;
-    krb5_const_principal client_princ;
+    krb5_const_principal ks_client_princ;
     krb5_authdata **authdata = NULL;
     krb5_boolean is_as_req;
     krb5_error_code code;
     krb5_pac pac = NULL;
     krb5_data pac_data;
 
-    memset(rep, 0, sizeof(*rep));
-
     /* Prefer canonicalised name from client entry */
-    if (req->client != NULL) {
-        client_princ = req->client->princ;
+    if (client != NULL) {
+        ks_client_princ = client->princ;
     } else {
-        client_princ = req->client_princ;
+        ks_client_princ = client_princ;
     }
 
-    is_as_req = ((req->flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
+    is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
 
-    if (is_as_req && (req->flags & KRB5_KDB_FLAG_INCLUDE_PAC)) {
+    if (is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) {
 
-        code = ks_get_pac(context, req->client, &pac);
+        code = ks_get_pac(context, client, &pac);
         if (code != 0) {
             goto done;
         }
     }
 
     if (!is_as_req) {
-        code = ks_verify_pac(context, client_princ, req, &pac);
+        code = ks_verify_pac(context, flags, ks_client_princ, client,
+                             server_key, krbtgt_key, authtime,
+                             tgt_auth_data, &pac);
         if (code != 0) {
             goto done;
         }
     }
 
-    if (pac == NULL && req->client != NULL) {
+    if (pac == NULL && client != NULL) {
 
-        code = ks_get_pac(context, req->client, &pac);
+        code = ks_get_pac(context, client, &pac);
         if (code != 0) {
             goto done;
         }
@@ -378,8 +383,8 @@ ks_db_sign_auth_data(krb5_context context,
         goto done;
     }
 
-    code = krb5int_pac_sign(context, pac, req->authtime, client_princ,
-                            req->server_key, req->krbtgt_key, &pac_data);
+    code = krb5int_pac_sign(context, pac, authtime, ks_client_princ,
+                            server_key, krbtgt_key, &pac_data);
     if (code != 0) {
         goto done;
     }
@@ -401,7 +406,7 @@ ks_db_sign_auth_data(krb5_context context,
     code = krb5_encode_authdata_container(context,
                                           KRB5_AUTHDATA_IF_RELEVANT,
                                           authdata,
-                                          &rep->auth_data);
+                                          signed_auth_data);
     if (code != 0) {
         goto done;
     }
index 4c35c0911be84331f66a02f8e56fc7f29d11a150..82e61b1f6e8e1791264cfda6c132cc6371c512be 100644 (file)
@@ -98,6 +98,10 @@ ks_free_krb5_db_entry(krb5_context context,
     krb5_tl_data *tl_data = NULL;
     int i, j;
 
+    if (entry == NULL) {
+        return;
+    }
+
     if (entry->e_data) {
         KS_FREE_DB_ENTRY(ks, (struct hdb_entry_ex *)(entry->e_data));
     }
@@ -130,7 +134,7 @@ ks_free_krb5_db_entry(krb5_context context,
         free(entry->key_data);
     }
 
-    memset(entry, 0, sizeof(*entry));
+    free(entry);
 }
 
 #if 0
@@ -441,13 +445,19 @@ ks_unmarshal_HDB_extensions(krb5_context context,
 krb5_error_code
 ks_unmarshal_hdb_entry(krb5_context context,
                        struct hdb_entry_ex *hentry_ex,
-                       krb5_db_entry *kentry)
+                       krb5_db_entry **kentry_ptr)
 {
     const hdb_entry *hentry = &hentry_ex->entry;
+    krb5_db_entry *kentry;
     krb5_error_code code;
     unsigned int i;
 
-    memset(kentry, 0, sizeof(*kentry));
+    *kentry_ptr = NULL;
+
+    kentry = k5alloc(sizeof(*kentry), &code);
+    if (kentry == NULL) {
+        return code;
+    }
 
     kentry->magic = KRB5_KDB_MAGIC_NUMBER;
     kentry->len = KRB5_KDB_V1_BASE_LENGTH;
@@ -509,6 +519,8 @@ ks_unmarshal_hdb_entry(krb5_context context,
 
     kentry->e_data = (void *)hentry_ex;
 
+    *kentry_ptr = kentry;
+
 cleanup:
     if (code != 0) {
         ks_free_krb5_db_entry(context, kentry);