Blob Blame History Raw
From b0043a95f86b240d0beb551ef4e9ff9a4be99995 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 7 Aug 2019 13:59:04 +0200
Subject: [PATCH 78/90] autofs: convert code to cache_req
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This will simplify the code a lot so it can be further extended.
At this point the conversion is done 1:1, we will do additional
changes in next patches.

Resolves:
https://pagure.io/SSSD/sssd/issue/2607

Reviewed-by: Tomáš Halman <thalman@redhat.com>
---
 src/responder/autofs/autofs_private.h |   72 +-
 src/responder/autofs/autofssrv.c      |    7 +-
 src/responder/autofs/autofssrv_cmd.c  | 1651 ++++++++-----------------
 3 files changed, 549 insertions(+), 1181 deletions(-)

diff --git a/src/responder/autofs/autofs_private.h b/src/responder/autofs/autofs_private.h
index 6a39b17ad..3be25d4d9 100644
--- a/src/responder/autofs/autofs_private.h
+++ b/src/responder/autofs/autofs_private.h
@@ -21,7 +21,9 @@
 #ifndef _AUTOFSSRV_PRIVATE_H_
 #define _AUTOFSSRV_PRIVATE_H_
 
+#include "responder/common/responder.h"
 #include "responder/common/responder_sbus.h"
+#include "responder/common/cache_req/cache_req.h"
 
 #define SSS_AUTOFS_PROTO_VERSION        0x001
 
@@ -33,75 +35,33 @@ struct autofs_ctx {
     hash_table_t *maps;
 };
 
-struct autofs_state_ctx {
-    char *automntmap_name;
-};
-
 struct autofs_cmd_ctx {
-    struct cli_ctx *cctx;
-    char *mapname;
-    char *key;
-    uint32_t cursor;
+    struct autofs_ctx *autofs_ctx;
+    struct cli_ctx *cli_ctx;
+
+    const char *mapname;
+    const char *keyname;
     uint32_t max_entries;
-    bool check_next;
+    uint32_t cursor;
 };
 
-struct autofs_dom_ctx {
-    struct autofs_cmd_ctx  *cmd_ctx;
-    struct sss_domain_info *domain;
-    bool check_provider;
-
-    /* cache results */
-    struct ldb_message *map;
-
-    size_t entry_count;
-    struct ldb_message **entries;
-
-    struct autofs_map_ctx *map_ctx;
-};
+struct autofs_enum_ctx {
+    /* Results. First result is the map objects, next results are map entries. */
+    struct cache_req_result *result;
 
-struct autofs_map_ctx {
-    /* state of the map entry */
-    bool ready;
+    /* True if the map was found. */
     bool found;
 
-    /* requests */
-    struct setent_req_list *reqs;
-
-    hash_table_t *map_table;
-    char *mapname;
+    /* False if the result is being created. */
+    bool ready;
 
-    /* map entry */
-    struct ldb_message *map;
-    size_t entry_count;
-    struct ldb_message **entries;
+    /* Requests that awaits the data. */
+    struct setent_req_list *notify_list;
 };
 
 struct sss_cmd_table *get_autofs_cmds(void);
 int autofs_connection_setup(struct cli_ctx *cctx);
 
-void autofs_map_hash_delete_cb(hash_entry_t *item,
-                               hash_destroy_enum deltype, void *pvt);
-
 errno_t autofs_orphan_maps(struct autofs_ctx *actx);
 
-enum sss_dp_autofs_type {
-    SSS_DP_AUTOFS
-};
-
-struct tevent_req *
-sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx,
-                       struct resp_ctx *rctx,
-                       struct sss_domain_info *dom,
-                       bool fast_reply,
-                       enum sss_dp_autofs_type type,
-                       const char *name);
-
-errno_t
-sss_dp_get_autofs_recv(TALLOC_CTX *mem_ctx,
-                       struct tevent_req *req,
-                       dbus_uint16_t *dp_err,
-                       dbus_uint32_t *dp_ret,
-                       char **err_msg);
-
 #endif /* _AUTOFSSRV_PRIVATE_H_ */
diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
index 7d236f4d9..309ed76b1 100644
--- a/src/responder/autofs/autofssrv.c
+++ b/src/responder/autofs/autofssrv.c
@@ -28,6 +28,7 @@
 #include "responder/common/responder.h"
 #include "providers/data_provider.h"
 #include "responder/autofs/autofs_private.h"
+#include "util/sss_ptr_hash.h"
 
 static int autofs_clean_hash_table(struct sbus_request *dbus_req, void *data);
 
@@ -105,7 +106,6 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
     struct autofs_ctx *autofs_ctx;
     struct be_conn *iter;
     int ret;
-    int hret;
     int max_retries;
 
     autofs_cmds = get_autofs_cmds();
@@ -158,9 +158,8 @@ autofs_process_init(TALLOC_CTX *mem_ctx,
     }
 
     /* Create the lookup table for setautomntent results */
-    hret = sss_hash_create_ex(autofs_ctx, 10, &autofs_ctx->maps, 0, 0, 0, 0,
-                              autofs_map_hash_delete_cb, NULL);
-    if (hret != HASH_SUCCESS) {
+    autofs_ctx->maps = sss_ptr_hash_create(autofs_ctx, NULL, NULL);
+    if (autofs_ctx->maps == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Unable to initialize automount maps hash table\n");
         ret = EIO;
diff --git a/src/responder/autofs/autofssrv_cmd.c b/src/responder/autofs/autofssrv_cmd.c
index 9ea2ab71b..670b6d50d 100644
--- a/src/responder/autofs/autofssrv_cmd.c
+++ b/src/responder/autofs/autofssrv_cmd.c
@@ -25,20 +25,22 @@
 #include "util/util.h"
 #include "responder/common/responder.h"
 #include "responder/common/responder_packet.h"
+#include "responder/common/cache_req/cache_req.h"
 #include "responder/autofs/autofs_private.h"
 #include "db/sysdb.h"
 #include "db/sysdb_autofs.h"
 #include "confdb/confdb.h"
+#include "util/sss_ptr_hash.h"
 
 static int autofs_cmd_send_error(struct autofs_cmd_ctx *cmdctx, int err)
 {
-    return sss_cmd_send_error(cmdctx->cctx, err);
+    return sss_cmd_send_error(cmdctx->cli_ctx, err);
 }
 
 static int
 autofs_cmd_send_empty(struct autofs_cmd_ctx *cmdctx)
 {
-    return sss_cmd_send_empty(cmdctx->cctx);
+    return sss_cmd_send_empty(cmdctx->cli_ctx);
 }
 
 static int
@@ -54,7 +56,7 @@ autofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
         if (ret) {
             return EFAULT;
         }
-        sss_cmd_done(cmdctx->cctx, cmdctx);
+        sss_cmd_done(cmdctx->cli_ctx, cmdctx);
         break;
 
     case EAGAIN:
@@ -70,7 +72,7 @@ autofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
         if (ret) {
             return EFAULT;
         }
-        sss_cmd_done(cmdctx->cctx, cmdctx);
+        sss_cmd_done(cmdctx->cli_ctx, cmdctx);
         break;
     }
 
@@ -78,1058 +80,524 @@ autofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
 }
 
 static errno_t
-autofs_setent_add_ref(TALLOC_CTX *memctx,
-                      struct autofs_map_ctx *map_ctx,
-                      struct tevent_req *req)
+autofs_fill_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp)
 {
-    return setent_add_ref(memctx, &map_ctx->reqs, req);
-}
-
-static void
-autofs_setent_notify(struct autofs_map_ctx *map_ctx, errno_t ret)
-{
-    setent_notify(&map_ctx->reqs, ret);
-}
-
-errno_t
-autofs_orphan_maps(struct autofs_ctx *actx)
-{
-    int hret;
-    unsigned long mcount;
-    unsigned long i;
-    hash_key_t *maps;
+    errno_t ret;
+    const char *key;
+    size_t keylen;
+    const char *value;
+    size_t valuelen;
+    uint8_t *body;
+    size_t blen;
+    size_t len;
 
-    if (!actx || !actx->maps) {
+    key = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_KEY, NULL);
+    value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
+    if (!key || !value) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Incomplete entry\n");
         return EINVAL;
     }
 
-    hret = hash_keys(actx->maps, &mcount, &maps);
-    if (hret != HASH_SUCCESS) {
-        return EIO;
-    }
-
-    for (i = 0; i < mcount; i++) {
-        hret = hash_delete(actx->maps, &maps[i]);
-        if (hret != HASH_SUCCESS) {
-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete key from hash\n");
-            continue;
-        }
-    }
-
-    return EOK;
-}
+    keylen = 1 + strlen(key);
+    valuelen = 1 + strlen(value);
+    len = sizeof(uint32_t) + sizeof(uint32_t) + keylen + sizeof(uint32_t) + valuelen;
 
-static errno_t
-get_autofs_map(struct autofs_ctx *actx,
-               char *mapname,
-               struct autofs_map_ctx **map)
-{
-    hash_key_t key;
-    hash_value_t value;
-    int hret;
-
-    key.type = HASH_KEY_STRING;
-    key.str = mapname;
-
-    hret = hash_lookup(actx->maps, &key, &value);
-    if (hret == HASH_SUCCESS) {
-        *map = talloc_get_type(value.ptr, struct autofs_map_ctx);
-        return EOK;
-    } else if (hret == HASH_ERROR_KEY_NOT_FOUND) {
-        return ENOENT;
+    ret = sss_packet_grow(packet, len);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
+        return ret;
     }
 
-    DEBUG(SSSDBG_CRIT_FAILURE,
-          "Unexpected error reading from autofs map hash [%d][%s]\n",
-          hret, hash_error_string(hret));
-    return EIO;
-}
-
-static int autofs_map_hash_remove (TALLOC_CTX *ctx);
+    sss_packet_get_body(packet, &body, &blen);
 
-void
-autofs_map_hash_delete_cb(hash_entry_t *item,
-                          hash_destroy_enum deltype, void *pvt)
-{
-    struct autofs_map_ctx *map;
+    SAFEALIGN_SET_UINT32(&body[*rp], len, rp);
+    SAFEALIGN_SET_UINT32(&body[*rp], keylen, rp);
 
-    if (deltype != HASH_ENTRY_DESTROY) {
-        return;
+    if (keylen == 1) {
+        body[*rp] = '\0';
+    } else {
+        memcpy(&body[*rp], key, keylen);
     }
+    *rp += keylen;
 
-    map = talloc_get_type(item->value.ptr, struct autofs_map_ctx);
-    if (!map) {
-        DEBUG(SSSDBG_OP_FAILURE, "Invalid autofs map\n");
-        return;
+    SAFEALIGN_SET_UINT32(&body[*rp], valuelen, rp);
+    if (valuelen == 1) {
+        body[*rp] = '\0';
+    } else {
+        memcpy(&body[*rp], value, valuelen);
     }
+    *rp += valuelen;
 
-    /* So that the destructor wouldn't attempt to remove the map from hash
-     * table */
-    map->map_table = NULL;
+    return EOK;
 }
 
-static errno_t
-set_autofs_map(struct autofs_ctx *actx,
-               struct autofs_map_ctx *map)
+errno_t
+autofs_orphan_maps(struct autofs_ctx *autofs_ctx)
 {
-    hash_key_t key;
-    hash_value_t value;
-    int hret;
-
-    if (map->mapname == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs map name.\n");
-        return EINVAL;
-    }
-
-    /* Add this entry to the hash table */
-    key.type = HASH_KEY_STRING;
-    key.str = map->mapname;
-    value.type = HASH_VALUE_PTR;
-    value.ptr = map;
-    hret = hash_enter(actx->maps, &key, &value);
-    if (hret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Unable to add hash table entry for [%s]\n", key.str);
-        DEBUG(SSSDBG_MINOR_FAILURE,
-              "Hash error [%d][%s]\n", hret, hash_error_string(hret));
-        return EIO;
-    }
-    talloc_steal(actx->maps, map);
-    talloc_set_destructor((TALLOC_CTX *) map, autofs_map_hash_remove);
+    sss_ptr_hash_delete_all(autofs_ctx->maps, true);
 
     return EOK;
 }
 
-static int
-autofs_map_hash_remove(TALLOC_CTX *ctx)
+static void
+autofs_enumctx_lifetime_timeout(struct tevent_context *ev,
+                                struct tevent_timer *te,
+                                struct timeval current_time,
+                                void *pvt)
 {
-    int hret;
-    hash_key_t key;
-    struct autofs_map_ctx *map =
-            talloc_get_type(ctx, struct autofs_map_ctx);
-
-    if (map->map_table == NULL) {
-        DEBUG(SSSDBG_TRACE_LIBS, "autofs map [%s] was already removed\n",
-              map->mapname);
-        return 0;
-    }
+    struct autofs_enum_ctx *enum_ctx;
 
-    key.type = HASH_KEY_STRING;
-    key.str = map->mapname;
+    enum_ctx = talloc_get_type(pvt, struct autofs_enum_ctx);
 
-    /* Remove the autofs map result object from the lookup table */
-    hret = hash_delete(map->map_table, &key);
-    if (hret != HASH_SUCCESS) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not remove key from table! [%d][%s]\n",
-              hret, hash_error_string(hret));
-        return -1;
-    }
-    return 0;
+    /* Free the context. It will be automatically removed from the hash table. */
+    talloc_free(enum_ctx);
 }
 
-static struct tevent_req *
-setautomntent_send(TALLOC_CTX *mem_ctx,
-                   const char *rawname,
-                   struct autofs_cmd_ctx *cmdctx);
-static errno_t setautomntent_recv(struct tevent_req *req);
-static void sss_autofs_cmd_setautomntent_done(struct tevent_req *req);
-
-/* FIXME - file a ticket to have per-responder private
- * data instead of growing the cli_ctx structure */
-static int
-sss_autofs_cmd_setautomntent(struct cli_ctx *client)
+static void
+autofs_set_enumctx_lifetime(struct autofs_ctx *autofs_ctx,
+                            struct autofs_enum_ctx *enum_ctx,
+                            uint32_t lifetime)
 {
-    struct autofs_cmd_ctx *cmdctx;
-    struct cli_protocol *pctx;
-    uint8_t *body;
-    size_t blen;
-    errno_t ret = EOK;
-    const char *rawname;
-    struct tevent_req *req;
-
-    DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_setautomntent\n");
-
-    cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
-    if (!cmdctx) {
-        return ENOMEM;
-    }
-    cmdctx->cctx = client;
-
-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
-
-    sss_packet_get_body(pctx->creq->in, &body, &blen);
-
-    /* if not terminated fail */
-    if (body[blen -1] != '\0') {
-        ret = EINVAL;
-        goto done;
-    }
-
-    /* If the body isn't valid UTF-8, fail */
-    if (!sss_utf8_check(body, blen -1)) {
-        ret = EINVAL;
-        goto done;
-    }
-
-    rawname = (const char *)body;
-    DEBUG(SSSDBG_TRACE_FUNC,
-          "Got request for automount map named %s\n", rawname);
+    struct timeval tv;
+    struct tevent_timer *te;
 
-    req = setautomntent_send(cmdctx, rawname, cmdctx);
-    if (!req) {
+    tv = tevent_timeval_current_ofs(lifetime, 0);
+    te = tevent_add_timer(autofs_ctx->rctx->ev, enum_ctx, tv,
+                          autofs_enumctx_lifetime_timeout, enum_ctx);
+    if (te == NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "Fatal error calling setautomntent_send\n");
-        ret = EIO;
-        goto done;
+              "Could not set up life timer for autofs maps. "
+              "Entries may become stale.\n");
     }
-    tevent_req_set_callback(req, sss_autofs_cmd_setautomntent_done, cmdctx);
-
-    ret = EOK;
-done:
-    return autofs_cmd_done(cmdctx, ret);
 }
 
-static void sss_autofs_cmd_setautomntent_done(struct tevent_req *req)
+static struct autofs_enum_ctx *
+autofs_create_enumeration_context(TALLOC_CTX *mem_ctx,
+                                  struct autofs_ctx *autofs_ctx,
+                                  const char *mapname)
 {
-    struct autofs_cmd_ctx *cmdctx =
-        tevent_req_callback_data(req, struct autofs_cmd_ctx);
-    struct cli_protocol *pctx;
+    struct autofs_enum_ctx *enum_ctx;
     errno_t ret;
-    errno_t reqret;
-    uint8_t *body;
-    size_t blen;
 
-    DEBUG(SSSDBG_TRACE_INTERNAL, "setautomntent done\n");
-
-    reqret = setautomntent_recv(req);
-    talloc_zfree(req);
-    if (reqret != EOK && reqret != ENOENT) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
-        autofs_cmd_done(cmdctx, reqret);
-        return;
+    enum_ctx = talloc_zero(mem_ctx, struct autofs_enum_ctx);
+    if (enum_ctx == NULL) {
+        return NULL;
     }
 
-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
+    enum_ctx->ready = false;
 
-    /* Either we succeeded or no domains were eligible */
-    ret = sss_packet_new(pctx->creq, 0,
-                         sss_packet_get_cmd(pctx->creq->in),
-                         &pctx->creq->out);
-    if (ret == EOK) {
-        if (reqret == ENOENT) {
-            DEBUG(SSSDBG_TRACE_FUNC, "setautomntent did not find requested map\n");
-            /* Notify the caller that this entry wasn't found */
-            ret = sss_cmd_empty_packet(pctx->creq->out);
-            if (ret != EOK) {
-                DEBUG(SSSDBG_TRACE_INTERNAL,
-                      "sss_cmd_empty_packet() failed: %s [%d]\n",
-                      sss_strerror(ret), ret);
-            }
-        } else {
-            DEBUG(SSSDBG_TRACE_FUNC, "setautomntent found data\n");
-            ret = sss_packet_grow(pctx->creq->out, 2*sizeof(uint32_t));
-            if (ret != EOK) {
-                DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't grow the packet\n");
-                talloc_free(cmdctx);
-                return;
-            }
-
-            sss_packet_get_body(pctx->creq->out, &body, &blen);
-
-            /* Got some results */
-            SAFEALIGN_SETMEM_UINT32(body, 1, NULL);
-
-            /* Reserved padding */
-            SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
-        }
-
-        sss_cmd_done(cmdctx->cctx, NULL);
-        return;
+    ret = sss_ptr_hash_add(autofs_ctx->maps, mapname,
+                           enum_ctx, struct autofs_enum_ctx);
+    if (ret != EOK) {
+        talloc_free(enum_ctx);
+        return NULL;
     }
 
-    DEBUG(SSSDBG_CRIT_FAILURE, "Error creating packet\n");
-    return;
+    return enum_ctx;
 }
 
-struct setautomntent_state {
-    struct autofs_cmd_ctx *cmdctx;
-    struct autofs_dom_ctx *dctx;
-
-    char *mapname;
-    struct autofs_map_ctx *map;
+struct autofs_setent_state {
+    struct autofs_ctx *autofs_ctx;
+    struct autofs_enum_ctx *enum_ctx;
 };
 
-struct setautomntent_lookup_ctx {
-    struct autofs_ctx *actx;
-    struct autofs_dom_ctx *dctx;
-    struct resp_ctx *rctx;
-    struct cli_ctx *cctx;
-
-    bool returned_to_mainloop;
-
-    char *mapname;
-    struct autofs_map_ctx *map;
-};
-
-static errno_t
-lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx);
-
-static void
-autofs_map_result_timeout(struct tevent_context *ev,
-                          struct tevent_timer *te,
-                          struct timeval current_time,
-                          void *pvt)
-{
-    struct autofs_map_ctx *map =
-            talloc_get_type(pvt, struct autofs_map_ctx);
-
-    /* Free the autofs map result context
-     * The destructor for the autofs map will remove itself
-     * from the hash table
-     */
-    talloc_free(map);
-}
-
-static void
-set_autofs_map_lifetime(uint32_t lifetime,
-                        struct setautomntent_lookup_ctx *lookup_ctx,
-                        struct autofs_map_ctx *map)
-{
-    struct timeval tv;
-    struct tevent_timer *te;
-
-    tv = tevent_timeval_current_ofs(lifetime, 0);
-    te = tevent_add_timer(lookup_ctx->rctx->ev,
-                          map, tv,
-                          autofs_map_result_timeout,
-                          map);
-    if (!te) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Could not set up life timer for autofs maps. "
-               "Entries may become stale.\n");
-    }
-}
-
-static errno_t
-setautomntent_get_autofs_map(struct autofs_ctx *actx,
-                             char *mapname,
-                             struct autofs_map_ctx **map);
+static void autofs_setent_done(struct tevent_req *subreq);
 
 static struct tevent_req *
-setautomntent_send(TALLOC_CTX *mem_ctx,
-                   const char *rawname,
-                   struct autofs_cmd_ctx *cmdctx)
+autofs_setent_send(TALLOC_CTX *mem_ctx,
+                   struct tevent_context *ev,
+                   struct autofs_ctx *autofs_ctx,
+                   const char *mapname)
 {
-    char *domname;
-    errno_t ret;
+    struct autofs_setent_state *state;
+    struct tevent_req *subreq;
     struct tevent_req *req;
-    struct setautomntent_state *state;
-    struct cli_ctx *client = cmdctx->cctx;
-    struct autofs_dom_ctx *dctx;
-    struct autofs_ctx *actx;
-    struct autofs_state_ctx *state_ctx;
-    struct setautomntent_lookup_ctx *lookup_ctx;
-
-    actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
-    state_ctx = talloc_get_type(client->state_ctx, struct autofs_state_ctx);
-
-    req = tevent_req_create(mem_ctx, &state, struct setautomntent_state);
-    if (!req) {
-        DEBUG(SSSDBG_FATAL_FAILURE,
-              "Could not create tevent request for setautomntent\n");
-        return NULL;
-    }
-    state->cmdctx = cmdctx;
-
-    dctx = talloc_zero(state, struct autofs_dom_ctx);
-    if (!dctx) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory\n");
-        ret = ENOMEM;
-        goto fail;
-    }
-    dctx->cmd_ctx = state->cmdctx;
-    state->dctx = dctx;
+    errno_t ret;
 
-    ret = sss_parse_name_for_domains(state, client->rctx->domains,
-                                     NULL, rawname,
-                                     &domname, &state->mapname);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_FATAL_FAILURE,
-              "Invalid name received [%s]\n", rawname);
-        goto fail;
+    req = tevent_req_create(mem_ctx, &state, struct autofs_setent_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
+        return NULL;
     }
 
-    DEBUG(SSSDBG_TRACE_FUNC,
-         "Requesting info for automount map [%s] from [%s]\n",
-         state->mapname, domname?domname:"<ALL>");
-
-    if (domname) {
-        dctx->domain = responder_get_domain(client->rctx, domname);
-        if (!dctx->domain) {
-            ret = EINVAL;
-            goto fail;
-        }
+    state->autofs_ctx = autofs_ctx;
 
-        state_ctx->automntmap_name = talloc_strdup(client, rawname);
-        if (!state_ctx->automntmap_name) {
-            ret = ENOMEM;
-            goto fail;
-        }
-    } else {
-        /* this is a multidomain search */
-        dctx->domain = client->rctx->domains;
-        cmdctx->check_next = true;
-
-        state_ctx->automntmap_name = talloc_strdup(client, state->mapname);
-        if (!state_ctx->automntmap_name) {
-            ret = ENOMEM;
-            goto fail;
-        }
-    }
-
-    dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
-    /* Is the result context already available?
-     * Check for existing lookups for this map
-     */
-    ret = setautomntent_get_autofs_map(actx, state->mapname, &state->map);
-    if (ret == EOK) {
-        /* Another process already requested this map
-         * Check whether it's ready for processing.
-         */
-        if (state->map->ready) {
-            if (state->map->found) {
-                DEBUG(SSSDBG_TRACE_LIBS,
-                      "Map %s is ready to be processed\n", state->mapname);
-                tevent_req_done(req);
-                tevent_req_post(req, actx->rctx->ev);
-                return req;
-            } else {
-                DEBUG(SSSDBG_TRACE_LIBS,
-                      "Map %s was marked as nonexistent\n", state->mapname);
-                tevent_req_error(req, ENOENT);
-                tevent_req_post(req, actx->rctx->ev);
-                return req;
-            }
+    /* Lookup current results if available. */
+    state->enum_ctx = sss_ptr_hash_lookup(autofs_ctx->maps, mapname,
+                                          struct autofs_enum_ctx);
+    if (state->enum_ctx != NULL) {
+        if (state->enum_ctx->ready) {
+            ret = EOK;
+            goto done;
         }
 
-        /* Result object is still being constructed
-         * Register for notification when it's ready
-         */
-        DEBUG(SSSDBG_TRACE_LIBS,
-              "Map %s is being looked up, registering for notification\n",
-               state->mapname);
-        ret = autofs_setent_add_ref(state, state->map, req);
+        /* Map is still being created. We will watch the request. */
+        ret = setent_add_ref(state, &state->enum_ctx->notify_list, req);
         if (ret != EOK) {
-            goto fail;
-        }
-        /* Will return control below */
-    } else if (ret == ENOENT) {
-        DEBUG(SSSDBG_TRACE_LIBS,
-              "Map %s needs to be looked up\n", state->mapname);
-
-        state->map = talloc_zero(actx, struct autofs_map_ctx);
-        if (!state->map) {
-            ret = ENOMEM;
-            goto fail;
-        }
-        dctx->map_ctx = state->map;
-
-        state->map->mapname = talloc_strdup(state->map, state->mapname);
-        if (!state->map->mapname) {
-            talloc_free(state->map);
-            ret = ENOMEM;
-            goto fail;
+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to watch enumeration request "
+                  "[%d]: %s\n", ret, sss_strerror(ret));
+            goto done;
         }
-        state->map->map_table = actx->maps;
 
-        ret = autofs_setent_add_ref(state, state->map, req);
-        if (ret != EOK) {
-            talloc_free(state->map);
-            goto fail;
-        }
+        ret = EAGAIN;
+        goto done;
+    }
 
-        ret = set_autofs_map(actx, state->map);
-        if (ret != EOK) {
-            talloc_free(state->map);
-            goto fail;
-        }
+    /* Map does not yet exist. Create the enumeration object and fetch data. */
+    state->enum_ctx = autofs_create_enumeration_context(state, autofs_ctx, mapname);
+    if (state->enum_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create enumeration context!\n");
+        ret = ENOMEM;
+        goto done;
+    }
 
-        /* Perform lookup */
-        lookup_ctx = talloc_zero(state->map, struct setautomntent_lookup_ctx);
-        if (!lookup_ctx) {
-            talloc_free(state->map);
-            ret = ENOMEM;
-            goto fail;
-        }
+    subreq = cache_req_autofs_map_entries_send(mem_ctx, ev, autofs_ctx->rctx,
+                                               autofs_ctx->rctx->ncache,
+                                               0, NULL, mapname);
+    if (subreq == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create subrequest!\n");
+        ret = ENOMEM;
+        goto done;
+    }
 
-        /* Steal the dom_ctx onto the lookup_ctx so it doesn't go out of scope if
-        * this request is canceled while other requests are in-progress.
-        */
-        lookup_ctx->dctx = talloc_steal(lookup_ctx, state->dctx);
-        lookup_ctx->actx = actx;
-        lookup_ctx->map = state->map;
-        lookup_ctx->rctx = client->rctx;
-        lookup_ctx->mapname =
-                    talloc_strdup(lookup_ctx, state->mapname);
-        if (!lookup_ctx->mapname) {
-            talloc_free(state->map);
-            ret = ENOMEM;
-            goto fail;
-        }
+    tevent_req_set_callback(subreq, autofs_setent_done, req);
 
-        ret = lookup_automntmap_step(lookup_ctx);
-        if (ret == EAGAIN) {
-            DEBUG(SSSDBG_TRACE_INTERNAL, "lookup_automntmap_step "
-                  "is refreshing the cache, re-entering the mainloop\n");
-            return req;
-        } else if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Could not get data from cache\n");
-            talloc_free(state->map);
-            ret = ENOMEM;
-            goto fail;
-        }
+    ret = EAGAIN;
 
+done:
+    if (ret == EOK) {
         tevent_req_done(req);
-        tevent_req_post(req, cmdctx->cctx->ev);
-        return req;
-    } else {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Unexpected error from get_autofs_map [%d]: %s\n",
-               ret, strerror(ret));
-        goto fail;
+        tevent_req_post(req, ev);
+    } else if (ret != EAGAIN) {
+        tevent_req_error(req, ret);
+        tevent_req_post(req, ev);
     }
 
     return req;
-
-fail:
-    tevent_req_error(req, ret);
-    tevent_req_post(req, actx->rctx->ev);
-    return req;
 }
 
-static errno_t
-setautomntent_get_autofs_map(struct autofs_ctx *actx,
-                             char *mapname,
-                             struct autofs_map_ctx **map)
+static void autofs_setent_done(struct tevent_req *subreq)
 {
+    struct autofs_setent_state *state;
+    struct cache_req_result *result;
+    struct tevent_req *req;
     errno_t ret;
 
-    if (strcmp(mapname, "auto.master") == 0) {
-        /* Iterate over the hash and remove all maps */
-        ret = autofs_orphan_maps(actx);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_MINOR_FAILURE, "Could not remove existing maps from hash\n");
-        }
-        return ENOENT;
-    }
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct autofs_setent_state);
 
-    return get_autofs_map(actx, mapname, map);
-}
+    ret = cache_req_autofs_map_entries_recv(state, subreq, &result);
+    talloc_zfree(subreq);
 
-static errno_t
-lookup_automntmap_update_cache(struct setautomntent_lookup_ctx *lookup_ctx);
-
-static errno_t
-lookup_automntmap_step(struct setautomntent_lookup_ctx *lookup_ctx)
-{
-    errno_t ret;
-    struct sss_domain_info *dom = lookup_ctx->dctx->domain;
-    struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
-    struct sysdb_ctx *sysdb;
-    struct autofs_map_ctx *map;
-
-    /* Check each domain for this map name */
-    while (dom) {
-        if (dom != dctx->domain) {
-            /* make sure we reset the check_provider flag when we check
-             * a new domain */
-            dctx->check_provider =
-                    NEED_CHECK_PROVIDER(dom->provider);
-        }
+    switch (ret) {
+    case EOK:
+        state->enum_ctx->found = true;
+        state->enum_ctx->result = talloc_steal(state->enum_ctx, result);
+        autofs_set_enumctx_lifetime(state->autofs_ctx, state->enum_ctx,
+                        state->enum_ctx->result->domain->autofsmap_timeout);
+        break;
+    case ENOENT:
+        state->enum_ctx->found = false;
+        state->enum_ctx->result = NULL;
+        autofs_set_enumctx_lifetime(state->autofs_ctx, state->enum_ctx,
+                                    state->autofs_ctx->neg_timeout);
+        break;
+    default:
+        DEBUG(SSSDBG_OP_FAILURE, "Unable to get map data [%d]: %s\n",
+              ret, sss_strerror(ret));
 
-        /* make sure to update the dctx if we changed domain */
-        dctx->domain = dom;
+        setent_notify(&state->enum_ctx->notify_list, ret);
+        talloc_zfree(state->enum_ctx);
+        tevent_req_error(req, ret);
+        return;
+    }
 
-        DEBUG(SSSDBG_TRACE_FUNC, "Requesting info for [%s@%s]\n",
-              lookup_ctx->mapname, dom->name);
-        sysdb = dom->sysdb;
-        if (sysdb == NULL) {
-            DEBUG(SSSDBG_FATAL_FAILURE,
-                  "Fatal: Sysdb CTX not found for this domain!\n");
-            return EIO;
-        }
+    state->enum_ctx->ready = true;
 
-        /* Look into the cache */
-        talloc_free(dctx->map);
-        ret = sysdb_get_map_byname(dctx, dom, lookup_ctx->mapname,
-                                   &dctx->map);
-        if (ret != EOK && ret != ENOENT) {
-            DEBUG(SSSDBG_OP_FAILURE, "Could not check cache\n");
-            return ret;
-        } else if (ret == ENOENT) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  "No automount map [%s] in cache for domain [%s]\n",
-                   lookup_ctx->mapname, dom->name);
-            if (!dctx->check_provider) {
-                if (dctx->cmd_ctx->check_next) {
-                    DEBUG(SSSDBG_TRACE_INTERNAL, "Moving on to next domain\n");
-                    dom = get_next_domain(dom, 0);
-                    continue;
-                }
-                else break;
-            }
-        }
+    /* Make the enumeration context disappear with maps table. */
+    talloc_steal(state->autofs_ctx->maps, state->enum_ctx);
 
-        ret = get_autofs_map(lookup_ctx->actx, lookup_ctx->mapname, &map);
-        if (ret != EOK) {
-            /* Something really bad happened! */
-            DEBUG(SSSDBG_CRIT_FAILURE, "Autofs map entry was lost!\n");
-            return ret;
-        }
+    setent_notify_done(&state->enum_ctx->notify_list);
+    tevent_req_done(req);
+    return;
+}
 
-        if (dctx->map == NULL && !dctx->check_provider) {
-            DEBUG(SSSDBG_MINOR_FAILURE,
-                  "Autofs map not found, setting negative cache\n");
-            map->ready = true;
-            map->found = false;
-            set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
-            return ENOENT;
-        }
+static errno_t
+autofs_setent_recv(struct tevent_req *req,
+                   struct autofs_enum_ctx **_enum_ctx)
+{
+    struct autofs_setent_state *state;
+    state = tevent_req_data(req, struct autofs_setent_state);
 
-        if (dctx->check_provider) {
-            ret = lookup_automntmap_update_cache(lookup_ctx);
-            if (ret == EAGAIN) {
-                DEBUG(SSSDBG_TRACE_INTERNAL,
-                      "Looking up automount maps from the DP\n");
-                return EAGAIN;
-            } else if (ret != EOK) {
-                DEBUG(SSSDBG_OP_FAILURE,
-                      "Error looking up automount maps [%d]: %s\n",
-                       ret, strerror(ret));
-                return ret;
-            }
-        }
+    TEVENT_REQ_RETURN_ON_ERROR(req);
 
-        /* OK, the map is in cache and valid.
-         * Let's get all members and return it
-         */
-        ret = sysdb_autofs_entries_by_map(map, dom, map->mapname,
-                                          &map->entry_count,
-                                          &map->entries);
-        if (ret != EOK && ret != ENOENT) {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  "Error looking automount map entries [%d]: %s\n",
-                  ret, strerror(ret));
-            map->ready = true;
-            map->found = false;
-            set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
-            return EIO;
-        }
+    *_enum_ctx = state->enum_ctx;
 
-        map->map = talloc_steal(map, dctx->map);
+    return EOK;
+}
 
-        DEBUG(SSSDBG_TRACE_FUNC,
-              "setautomntent done for map %s\n", lookup_ctx->mapname);
-        map->ready = true;
-        map->found = true;
-        set_autofs_map_lifetime(dom->autofsmap_timeout, lookup_ctx, map);
-        return EOK;
-    }
+static errno_t
+autofs_read_setautomntent_input(struct cli_ctx *cli_ctx,
+                                const char **_mapname)
+{
+    struct cli_protocol *pctx;
+    uint8_t *body;
+    size_t blen;
 
-    map = talloc_zero(lookup_ctx->actx, struct autofs_map_ctx);
-    if (!map) {
-        return ENOMEM;
-    }
+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
 
-    map->ready = true;
-    map->found = false;
-    map->map_table = lookup_ctx->actx->maps;
+    sss_packet_get_body(pctx->creq->in, &body, &blen);
 
-    map->mapname = talloc_strdup(map, lookup_ctx->mapname);
-    if (!map->mapname) {
-        talloc_free(map);
-        return ENOMEM;
+    /* if not terminated fail */
+    if (body[blen - 1] != '\0') {
+        return EINVAL;
     }
 
-    ret = set_autofs_map(lookup_ctx->actx, map);
-    if (ret != EOK) {
-        talloc_free(map);
-        return ENOMEM;
+    /* If the body isn't valid UTF-8, fail */
+    if (!sss_utf8_check(body, blen - 1)) {
+        return EINVAL;
     }
 
-    set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
+    *_mapname = (const char *)body;
 
-    /* If we've gotten here, then no domain contained this map */
-    return ENOENT;
+    return EOK;
 }
 
-static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min,
-                                            const char *err_msg, void *ptr);
-static void autofs_dp_send_map_req_done(struct tevent_req *req);
-
 static errno_t
-lookup_automntmap_update_cache(struct setautomntent_lookup_ctx *lookup_ctx)
+autofs_write_setautomntent_output(struct cli_ctx *cli_ctx,
+                                  struct autofs_enum_ctx *enum_ctx)
 {
+    struct cli_protocol *pctx;
+    uint8_t *body;
+    size_t blen;
     errno_t ret;
-    uint64_t cache_expire = 0;
-    struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
-    struct tevent_req *req = NULL;
-    struct dp_callback_ctx *cb_ctx = NULL;
-
-    if (dctx->map != NULL) {
-        if (strcmp(lookup_ctx->mapname, "auto.master") != 0) {
-            cache_expire = ldb_msg_find_attr_as_uint64(dctx->map,
-                                                       SYSDB_CACHE_EXPIRE, 0);
-        }
 
-        /* if we have any reply let's check cache validity */
-        ret = sss_cmd_check_cache(dctx->map, 0, cache_expire);
-        if (ret == EOK) {
-            DEBUG(SSSDBG_TRACE_FUNC, "Cached entry is valid, returning..\n");
-            return EOK;
-        } else if (ret != EAGAIN && ret != ENOENT) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache: %d\n", ret);
-            goto error;
-        }
-    }
+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
 
-    /* dont loop forever :-) */
-    dctx->check_provider = false;
-
-    /* keep around current data in case backend is offline */
-    /* FIXME - do this by default */
-#if 0
-    if (dctx->res->count) {
-        dctx->res = talloc_steal(dctx, dctx->res);
-    }
-#endif
-
-    req = sss_dp_get_autofs_send(lookup_ctx->cctx, lookup_ctx->rctx,
-                                 lookup_ctx->dctx->domain, true,
-                                 SSS_DP_AUTOFS, lookup_ctx->mapname);
-    if (!req) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Out of memory sending data provider request\n");
-        ret = ENOMEM;
-        goto error;
+    ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in),
+                         &pctx->creq->out);
+    if (ret != EOK) {
+        return ret;
     }
 
-    cb_ctx = talloc_zero(lookup_ctx->dctx, struct dp_callback_ctx);
-    if(!cb_ctx) {
-        talloc_zfree(req);
-        ret = ENOMEM;
-        goto error;
+    if (!enum_ctx->found) {
+        DEBUG(SSSDBG_TRACE_FUNC, "Map was not found\n");
+        return sss_cmd_empty_packet(pctx->creq->out);
     }
-    cb_ctx->callback = lookup_automntmap_cache_updated;
-    cb_ctx->ptr = lookup_ctx;
-    cb_ctx->cctx = lookup_ctx->dctx->cmd_ctx->cctx;
-    cb_ctx->mem_ctx = lookup_ctx->dctx;
-
-    tevent_req_set_callback(req, autofs_dp_send_map_req_done, cb_ctx);
 
-    return EAGAIN;
+    DEBUG(SSSDBG_TRACE_FUNC, "Map found\n");
 
-error:
-    ret = autofs_cmd_send_error(lookup_ctx->dctx->cmd_ctx, ret);
+    ret = sss_packet_grow(pctx->creq->out, 2 * sizeof(uint32_t));
     if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
-        talloc_free(lookup_ctx->cctx);
         return ret;
     }
-    autofs_cmd_done(lookup_ctx->dctx->cmd_ctx, ret);
-    return EOK;
-}
-
-static void autofs_dp_send_map_req_done(struct tevent_req *req)
-{
-    struct dp_callback_ctx *cb_ctx =
-            tevent_req_callback_data(req, struct dp_callback_ctx);
-    struct setautomntent_lookup_ctx *lookup_ctx =
-            talloc_get_type(cb_ctx->ptr, struct setautomntent_lookup_ctx);
-
-    errno_t ret;
-    dbus_uint16_t err_maj;
-    dbus_uint32_t err_min;
-    char *err_msg;
-
-    ret = sss_dp_get_autofs_recv(cb_ctx->mem_ctx, req,
-                                 &err_maj, &err_min,
-                                 &err_msg);
-    talloc_free(req);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
-        talloc_free(lookup_ctx->cctx);
-        return;
-    }
-
-    cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
-}
-
-static void lookup_automntmap_cache_updated(uint16_t err_maj, uint32_t err_min,
-                                            const char *err_msg, void *ptr)
-{
-    struct setautomntent_lookup_ctx *lookup_ctx =
-            talloc_get_type(ptr, struct setautomntent_lookup_ctx);
-    struct autofs_dom_ctx *dctx = lookup_ctx->dctx;
-    errno_t ret;
-
-    if (err_maj) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Unable to get information from Data Provider\n"
-              "Error: %u, %u, %s\n"
-              "Will try to return what we have in cache\n",
-               (unsigned int)err_maj, (unsigned int)err_min, err_msg);
-
-        /* Try to fall back to cache */
-        ret = lookup_automntmap_step(lookup_ctx);
-        if (ret == EOK) {
-            /* We have cached results to return */
-            autofs_setent_notify(lookup_ctx->map, ret);
-            return;
-        }
 
-        /* Otherwise try the next domain */
-        if (dctx->cmd_ctx->check_next
-                && (dctx->domain = get_next_domain(dctx->domain, 0))) {
-            dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
-        }
-    }
+    sss_packet_get_body(pctx->creq->out, &body, &blen);
 
-    ret = lookup_automntmap_step(lookup_ctx);
-    if (ret != EOK) {
-        if (ret == EAGAIN) {
-            return;
-        }
-    }
+    /* Got some results */
+    SAFEALIGN_SETMEM_UINT32(body, 1, NULL);
 
-    /* We have results to return */
-    autofs_setent_notify(lookup_ctx->map, ret);
-}
+    /* Reserved padding */
+    SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), 0, NULL);
 
-static errno_t
-setautomntent_recv(struct tevent_req *req)
-{
-    TEVENT_REQ_RETURN_ON_ERROR(req);
     return EOK;
 }
 
-static errno_t
-getautomntent_process(struct autofs_cmd_ctx *cmdctx,
-                      struct autofs_map_ctx *map,
-                      uint32_t cursor, uint32_t max_entries);
 static void
-getautomntent_implicit_done(struct tevent_req *req);
-static errno_t
-fill_autofs_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp);
-
+sss_autofs_cmd_setautomntent_done(struct tevent_req *req);
 
 static int
-sss_autofs_cmd_getautomntent(struct cli_ctx *client)
+sss_autofs_cmd_setautomntent(struct cli_ctx *cli_ctx)
 {
-    struct autofs_cmd_ctx *cmdctx;
-    struct autofs_map_ctx *map;
-    struct autofs_ctx *actx;
-    struct cli_protocol *pctx;
-    uint8_t *body;
-    size_t blen;
-    errno_t ret;
-    uint32_t namelen;
-    size_t c = 0;
+    struct autofs_cmd_ctx *cmd_ctx;
+    struct autofs_ctx *autofs_ctx;
     struct tevent_req *req;
+    errno_t ret;
 
-    DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_getautomntent\n");
+    autofs_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct autofs_ctx);
 
-    cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
-    if (!cmdctx) {
+    cmd_ctx = talloc_zero(cli_ctx, struct autofs_cmd_ctx);
+    if (cmd_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create command context.\n");
         return ENOMEM;
     }
-    cmdctx->cctx = client;
 
-    actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
-    if (!actx) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs context\n");
-        return EIO;
-    }
+    cmd_ctx->cli_ctx = cli_ctx;
+    cmd_ctx->autofs_ctx = autofs_ctx;
 
-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
-
-    /* get autofs map name and index to query */
-    sss_packet_get_body(pctx->creq->in, &body, &blen);
-
-    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
-
-    if (namelen == 0 || namelen > blen - c) {
-        ret = EINVAL;
+    ret = autofs_read_setautomntent_input(cli_ctx, &cmd_ctx->mapname);
+    if (ret != EOK) {
         goto done;
     }
 
-    cmdctx->mapname = (char *) body+c;
+    DEBUG(SSSDBG_TRACE_FUNC, "Creating enumeration context for %s\n",
+          cmd_ctx->mapname);
 
-    /* if not null-terminated fail */
-    if (cmdctx->mapname[namelen] != '\0') {
-        ret = EINVAL;
+    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx,
+                             cmd_ctx->mapname);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
+        ret = ENOMEM;
         goto done;
     }
 
-    /* If the name isn't valid UTF-8, fail */
-    if (!sss_utf8_check((const uint8_t *) cmdctx->mapname, namelen -1)) {
-        ret = EINVAL;
-        goto done;
-    }
+    tevent_req_set_callback(req, sss_autofs_cmd_setautomntent_done, cmd_ctx);
 
-    SAFEALIGN_COPY_UINT32_CHECK(&cmdctx->cursor, body+c+namelen+1, blen, &c);
-    SAFEALIGN_COPY_UINT32_CHECK(&cmdctx->max_entries, body+c+namelen+1, blen, &c);
+    ret = EOK;
 
-    DEBUG(SSSDBG_TRACE_FUNC,
-          "Requested data of map %s cursor %d max entries %d\n",
-           cmdctx->mapname, cmdctx->cursor, cmdctx->max_entries);
+done:
+    return autofs_cmd_done(cmd_ctx, ret);
+}
 
-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
-    if (ret == ENOENT) {
-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
-        if (req == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
-            ret = EIO;
-            goto done;
-        }
+static void
+sss_autofs_cmd_setautomntent_done(struct tevent_req *req)
+{
+    struct autofs_enum_ctx *enum_ctx;
+    struct autofs_cmd_ctx *cmd_ctx;
+    errno_t ret;
 
-        tevent_req_set_callback(req, getautomntent_implicit_done, cmdctx);
-        ret = EOK;
-        goto done;
-    } else if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "An unexpected error occurred: [%d][%s]\n",
-              ret, strerror(ret));
-        goto done;
-    }
+    cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
 
-    if (map->ready == false) {
-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
-        if (req == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
-            ret = EIO;
-            goto done;
-        }
+    ret = autofs_setent_recv(req, &enum_ctx);
+    talloc_zfree(req);
+    if (ret != EOK) {
+        autofs_cmd_done(cmd_ctx, ret);
+        return;
+    }
 
-        tevent_req_set_callback(req, getautomntent_implicit_done, cmdctx);
-        ret = EOK;
-        goto done;
-    } else if (map->found == false) {
-        DEBUG(SSSDBG_TRACE_FUNC, "negative cache hit\n");
-        ret = ENOENT;
-        goto done;
+    ret = autofs_write_setautomntent_output(cmd_ctx->cli_ctx, enum_ctx);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
+              "[%d]: %s\n", ret, sss_strerror(ret));
+        autofs_cmd_done(cmd_ctx, ret);
+        return;
     }
 
-    DEBUG(SSSDBG_TRACE_INTERNAL,
-          "returning entries for [%s]\n", map->mapname);
+    sss_cmd_done(cmd_ctx->cli_ctx, NULL);
+}
 
-    ret = getautomntent_process(cmdctx, map, cmdctx->cursor, cmdctx->max_entries);
+static int
+sss_autofs_cmd_endautomntent(struct cli_ctx *client)
+{
+    struct cli_protocol *pctx;
+    errno_t ret;
 
-done:
-    return autofs_cmd_done(cmdctx, ret);
+    DEBUG(SSSDBG_TRACE_FUNC, "endautomntent called\n");
+
+    pctx = talloc_get_type(client->protocol_ctx, struct cli_protocol);
+
+    /* create response packet */
+    ret = sss_packet_new(pctx->creq, 0,
+                         sss_packet_get_cmd(pctx->creq->in),
+                         &pctx->creq->out);
+
+    if (ret != EOK) {
+        return ret;
+    }
+
+    sss_cmd_done(client, NULL);
+    return EOK;
 }
 
-static void
-getautomntent_implicit_done(struct tevent_req *req)
+static errno_t
+autofs_read_getautomntent_input(struct cli_ctx *cli_ctx,
+                                const char **_mapname,
+                                uint32_t *_cursor,
+                                uint32_t *_max_entries)
 {
-    errno_t ret;
-    struct autofs_map_ctx *map;
-    struct autofs_cmd_ctx *cmdctx =
-        tevent_req_callback_data(req, struct autofs_cmd_ctx);
-    struct autofs_ctx *actx =
-        talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct autofs_ctx);
+    struct cli_protocol *pctx;
+    const char *mapname;
+    uint32_t namelen;
+    uint8_t *body;
+    size_t blen;
+    size_t c = 0;
 
-    ret = setautomntent_recv(req);
-    talloc_zfree(req);
-    if (ret != EOK) {
-        if (ret != ENOENT) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
-        } else {
-            DEBUG(SSSDBG_MINOR_FAILURE, "No such map\n");
-        }
-        goto done;
+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
+
+    sss_packet_get_body(pctx->creq->in, &body, &blen);
+
+    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
+    if (namelen == 0 || namelen > blen - c) {
+        return EINVAL;
     }
 
-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Cannot get map after setautomntent succeeded?\n");
-        goto done;
+    mapname = (const char *)body + c;
+
+    /* if not null-terminated fail */
+    if (mapname[namelen] != '\0') {
+        return EINVAL;
     }
 
-    if (map->ready == false) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Map not ready after setautomntent succeeded\n");
-        goto done;
+    /* If the name isn't valid UTF-8, fail */
+    if (!sss_utf8_check((const uint8_t *)mapname, namelen - 1)) {
+        return EINVAL;
     }
 
-    ret = getautomntent_process(cmdctx, map,
-                                cmdctx->cursor, cmdctx->max_entries);
-done:
-    autofs_cmd_done(cmdctx, ret);
-    return;
+    SAFEALIGN_COPY_UINT32_CHECK(_cursor, body + c + namelen + 1, blen, &c);
+    SAFEALIGN_COPY_UINT32_CHECK(_max_entries, body + c + namelen + 1, blen, &c);
+    *_mapname = mapname;
+
+    return EOK;
 }
 
 static errno_t
-getautomntent_process(struct autofs_cmd_ctx *cmdctx,
-                      struct autofs_map_ctx *map,
-                      uint32_t cursor, uint32_t max_entries)
+autofs_write_getautomntent_output(struct cli_ctx *cli_ctx,
+                                  struct autofs_enum_ctx *enum_ctx,
+                                  uint32_t cursor,
+                                  uint32_t max_entries)
 {
     struct cli_protocol *pctx;
-    errno_t ret;
+    struct ldb_message **entries;
     struct ldb_message *entry;
-    size_t rp;
-    uint32_t i, stop, left, nentries;
+    size_t count;
+    size_t num_entries;
     uint8_t *body;
     size_t blen;
+    size_t rp;
+    uint32_t i;
+    uint32_t stop;
+    uint32_t left;
+    errno_t ret;
 
-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
 
-    /* create response packet */
-    ret = sss_packet_new(pctx->creq, 0,
-                         sss_packet_get_cmd(pctx->creq->in),
+    count = enum_ctx->found ? enum_ctx->result->count - 1 : 0;
+    entries = count > 0 ? enum_ctx->result->msgs + 1 : NULL;
+
+    ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in),
                          &pctx->creq->out);
     if (ret != EOK) {
         return ret;
     }
 
-    if (!map->map || !map->entries || !map->entries[0] ||
-        cursor >= map->entry_count) {
-        DEBUG(SSSDBG_MINOR_FAILURE, "No entries found\n");
-        ret = sss_cmd_empty_packet(pctx->creq->out);
-        if (ret != EOK) {
-            return autofs_cmd_done(cmdctx, ret);
-        }
-        goto done;
+    if (!enum_ctx->found || count == 0 || cursor >= count) {
+        DEBUG(SSSDBG_TRACE_FUNC, "No entries was not found\n");
+        return sss_cmd_empty_packet(pctx->creq->out);
     }
 
     /* allocate memory for number of entries in the packet */
     ret = sss_packet_grow(pctx->creq->out, sizeof(uint32_t));
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
-        goto done;
+        return ret;
     }
 
-    rp = sizeof(uint32_t);  /* We'll write the number of entries here */
-
-    left = map->entry_count - cursor;
+    rp = sizeof(uint32_t);  /* We will first write the elements. */
+    left = count - cursor;
     stop = max_entries < left ? max_entries : left;
 
-    nentries = 0;
-    for (i=0; i < stop; i++) {
-        entry = map->entries[cursor];
+    num_entries = 0;
+    for (i = 0; i < stop; i++) {
+        entry = entries[cursor];
         cursor++;
 
-        ret = fill_autofs_entry(entry, pctx->creq->out, &rp);
+        ret = autofs_fill_entry(entry, pctx->creq->out, &rp);
         if (ret != EOK) {
             DEBUG(SSSDBG_MINOR_FAILURE,
                   "Cannot fill entry %d/%d, skipping\n", i, stop);
             continue;
         }
-        nentries++;
+        num_entries++;
     }
 
     /* packet grows in fill_autofs_entry, body pointer may change,
@@ -1137,311 +605,212 @@ getautomntent_process(struct autofs_cmd_ctx *cmdctx,
     sss_packet_get_body(pctx->creq->out, &body, &blen);
 
     rp = 0;
-    SAFEALIGN_SET_UINT32(&body[rp], nentries, &rp);
-
-    ret = EOK;
-done:
-    sss_packet_set_error(pctx->creq->out, ret);
-    sss_cmd_done(cmdctx->cctx, cmdctx);
+    SAFEALIGN_SET_UINT32(&body[rp], num_entries, &rp);
 
     return EOK;
 }
 
-static errno_t
-fill_autofs_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp)
+static void
+sss_autofs_cmd_getautomntent_done(struct tevent_req *req);
+
+static int
+sss_autofs_cmd_getautomntent(struct cli_ctx *cli_ctx)
 {
+    struct autofs_cmd_ctx *cmd_ctx;
+    struct autofs_ctx *autofs_ctx;
+    struct tevent_req *req;
     errno_t ret;
-    const char *key;
-    size_t keylen;
-    const char *value;
-    size_t valuelen;
-    uint8_t *body;
-    size_t blen;
-    size_t len;
 
-    key = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_KEY, NULL);
-    value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
-    if (!key || !value) {
-        DEBUG(SSSDBG_MINOR_FAILURE, "Incomplete entry\n");
-        return EINVAL;
+    autofs_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct autofs_ctx);
+
+    cmd_ctx = talloc_zero(cli_ctx, struct autofs_cmd_ctx);
+    if (cmd_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create command context.\n");
+        return ENOMEM;
     }
 
-    keylen = 1 + strlen(key);
-    valuelen = 1 + strlen(value);
-    len = sizeof(uint32_t) + sizeof(uint32_t) + keylen + sizeof(uint32_t) + valuelen;
+    cmd_ctx->cli_ctx = cli_ctx;
+    cmd_ctx->autofs_ctx = autofs_ctx;
 
-    ret = sss_packet_grow(packet, len);
+    ret = autofs_read_getautomntent_input(cli_ctx, &cmd_ctx->mapname,
+                                          &cmd_ctx->cursor,
+                                          &cmd_ctx->max_entries);
     if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
-        return ret;
+        goto done;
     }
 
-    sss_packet_get_body(packet, &body, &blen);
-
-    SAFEALIGN_SET_UINT32(&body[*rp], len, rp);
-    SAFEALIGN_SET_UINT32(&body[*rp], keylen, rp);
+    DEBUG(SSSDBG_TRACE_FUNC, "Obtaining enumeration context for %s\n",
+          cmd_ctx->mapname);
 
-    if (keylen == 1) {
-        body[*rp] = '\0';
-    } else {
-        memcpy(&body[*rp], key, keylen);
+    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx, cmd_ctx->mapname);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
+        ret = ENOMEM;
+        goto done;
     }
-    *rp += keylen;
 
-    SAFEALIGN_SET_UINT32(&body[*rp], valuelen, rp);
-    if (valuelen == 1) {
-        body[*rp] = '\0';
-    } else {
-        memcpy(&body[*rp], value, valuelen);
-    }
-    *rp += valuelen;
+    tevent_req_set_callback(req, sss_autofs_cmd_getautomntent_done, cmd_ctx);
 
-    return EOK;
+    ret = EOK;
+
+done:
+    return autofs_cmd_done(cmd_ctx, ret);
 }
 
-static errno_t
-getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
-                         struct autofs_map_ctx *map,
-                         const char *key);
 static void
-getautomntbyname_implicit_done(struct tevent_req *req);
-
-static int
-sss_autofs_cmd_getautomntbyname(struct cli_ctx *client)
+sss_autofs_cmd_getautomntent_done(struct tevent_req *req)
 {
+    struct autofs_enum_ctx *enum_ctx;
+    struct autofs_cmd_ctx *cmd_ctx;
     errno_t ret;
-    struct autofs_cmd_ctx *cmdctx;
-    struct autofs_map_ctx *map;
-    struct autofs_ctx *actx;
-    struct cli_protocol *pctx;
-    uint8_t *body;
-    size_t blen;
-    uint32_t namelen;
-    uint32_t keylen;
-    size_t c = 0;
-    struct tevent_req *req;
 
-    DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_getautomntbyname\n");
+    cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
 
-    cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
-    if (!cmdctx) {
-        return ENOMEM;
+    ret = autofs_setent_recv(req, &enum_ctx);
+    talloc_zfree(req);
+    if (ret != EOK) {
+        autofs_cmd_done(cmd_ctx, ret);
+        return;
     }
-    cmdctx->cctx = client;
 
-    actx = talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
-    if (!actx) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs context\n");
-        return EIO;
+    ret = autofs_write_getautomntent_output(cmd_ctx->cli_ctx, enum_ctx,
+                                            cmd_ctx->cursor,
+                                            cmd_ctx->max_entries);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
+              "[%d]: %s\n", ret, sss_strerror(ret));
+        autofs_cmd_done(cmd_ctx, ret);
+        return;
     }
 
-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
+    sss_cmd_done(cmd_ctx->cli_ctx, NULL);
+}
 
-    /* get autofs map name and index to query */
-    sss_packet_get_body(pctx->creq->in, &body, &blen);
+static errno_t
+autofs_read_getautomntbyname_input(struct cli_ctx *cli_ctx,
+                                   const char **_mapname,
+                                   const char **_keyname)
+{
+    struct cli_protocol *pctx;
+    const char *mapname;
+    const char *keyname;
+    uint32_t namelen;
+    uint32_t keylen;
+    uint8_t *body;
+    size_t blen;
+    size_t c = 0;
 
-    /* FIXME - split out a function to get string from <len><str>\0 */
-    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
+
+    sss_packet_get_body(pctx->creq->in, &body, &blen);
 
+    /* Get map name. */
+    SAFEALIGN_COPY_UINT32_CHECK(&namelen, body + c, blen, &c);
     if (namelen == 0 || namelen > blen - c) {
-        ret = EINVAL;
-        goto done;
+        return EINVAL;
     }
 
-    cmdctx->mapname = (char *) body+c;
+    mapname = (const  char *) body + c;
 
     /* if not null-terminated fail */
-    if (cmdctx->mapname[namelen] != '\0') {
-        ret = EINVAL;
-        goto done;
+    if (mapname[namelen] != '\0') {
+        return EINVAL;
     }
 
     /* If the name isn't valid UTF-8, fail */
-    if (!sss_utf8_check((const uint8_t *) cmdctx->mapname, namelen -1)) {
-        ret = EINVAL;
-        goto done;
+    if (!sss_utf8_check((const uint8_t *)mapname, namelen - 1)) {
+        return EINVAL;
     }
 
     c += namelen + 1;
 
-    /* FIXME - split out a function to get string from <len><str>\0 */
-    SAFEALIGN_COPY_UINT32_CHECK(&keylen, body+c, blen, &c);
-
+    /* Get key name. */
+    SAFEALIGN_COPY_UINT32_CHECK(&keylen, body + c, blen, &c);
     if (keylen == 0 || keylen > blen - c) {
-        ret = EINVAL;
-        goto done;
+        return EINVAL;
     }
 
-    cmdctx->key = (char *) body+c;
+    keyname = (const char *) body + c;
 
     /* if not null-terminated fail */
-    if (cmdctx->key[keylen] != '\0') {
-        ret = EINVAL;
-        goto done;
+    if (keyname[keylen] != '\0') {
+        return EINVAL;
     }
 
     /* If the key isn't valid UTF-8, fail */
-    if (!sss_utf8_check((const uint8_t *) cmdctx->key, keylen -1)) {
-        ret = EINVAL;
-        goto done;
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC,
-          "Requested data of map %s key %s\n", cmdctx->mapname, cmdctx->key);
-
-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
-    if (ret == ENOENT) {
-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
-        if (req == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
-            ret = EIO;
-            goto done;
-        }
-
-        tevent_req_set_callback(req, getautomntbyname_implicit_done, cmdctx);
-        ret = EOK;
-        goto done;
-    } else if (ret != EOK) {
-        DEBUG(SSSDBG_OP_FAILURE,
-              "An unexpected error occurred: [%d][%s]\n",
-              ret, strerror(ret));
-        goto done;
-    }
-
-    if (map->ready == false) {
-        DEBUG(SSSDBG_TRACE_FUNC, "Performing implicit setautomntent\n");
-        req = setautomntent_send(cmdctx, cmdctx->mapname, cmdctx);
-        if (req == NULL) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_send failed\n");
-            ret = EIO;
-            goto done;
-        }
-
-        tevent_req_set_callback(req, getautomntbyname_implicit_done, cmdctx);
-        ret = EOK;
-        goto done;
-    } else if (map->found == false) {
-        DEBUG(SSSDBG_TRACE_FUNC, "negative cache hit\n");
-        ret = ENOENT;
-        goto done;
-    }
-
-    DEBUG(SSSDBG_TRACE_INTERNAL,
-          "Looking up value for [%s] in [%s]\n", cmdctx->key, map->mapname);
-
-    ret = getautomntbyname_process(cmdctx, map, cmdctx->key);
-
-done:
-    return autofs_cmd_done(cmdctx, ret);
-}
-
-static void
-getautomntbyname_implicit_done(struct tevent_req *req)
-{
-    errno_t ret;
-    struct autofs_map_ctx *map;
-    struct autofs_cmd_ctx *cmdctx =
-        tevent_req_callback_data(req, struct autofs_cmd_ctx);
-    struct autofs_ctx *actx =
-        talloc_get_type(cmdctx->cctx->rctx->pvt_ctx, struct autofs_ctx);
-
-    ret = setautomntent_recv(req);
-    talloc_zfree(req);
-    if (ret != EOK) {
-        if (ret != ENOENT) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "setautomntent_recv failed\n");
-        } else {
-            DEBUG(SSSDBG_MINOR_FAILURE, "No such map\n");
-        }
-        goto done;
-    }
-
-    ret = get_autofs_map(actx, cmdctx->mapname, &map);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Cannot get map after setautomntent succeeded?\n");
-        goto done;
+    if (!sss_utf8_check((const uint8_t *)keyname, keylen - 1)) {
+        return EINVAL;
     }
 
-    if (map->ready == false) {
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "Map not ready after setautomntent succeeded\n");
-        goto done;
-    }
+    *_mapname = mapname;
+    *_keyname = keyname;
 
-    ret = getautomntbyname_process(cmdctx, map, cmdctx->key);
-done:
-    autofs_cmd_done(cmdctx, ret);
-    return;
+    return EOK;
 }
 
 static errno_t
-getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
-                         struct autofs_map_ctx *map,
-                         const char *key)
+autofs_write_getautomntbyname_output(struct cli_ctx *cli_ctx,
+                                     struct autofs_enum_ctx *enum_ctx,
+                                     const char *keyname)
 {
     struct cli_protocol *pctx;
-    errno_t ret;
-    size_t i;
-    const char *k;
+    struct ldb_message **entries;
+    struct ldb_message *entry = NULL;
+    const char *entry_key;
     const char *value;
-    size_t valuelen;
+    size_t value_len;
     size_t len;
+    size_t count;
     uint8_t *body;
-    size_t blen, rp;
+    size_t blen;
+    size_t rp;
+    size_t i;
+    errno_t ret;
 
-    pctx = talloc_get_type(cmdctx->cctx->protocol_ctx, struct cli_protocol);
+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
 
-    /* create response packet */
-    ret = sss_packet_new(pctx->creq, 0,
-                         sss_packet_get_cmd(pctx->creq->in),
+    count = enum_ctx->found ? enum_ctx->result->count - 1 : 0;
+    entries = count > 0 ? enum_ctx->result->msgs + 1 : NULL;
+
+    ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in),
                          &pctx->creq->out);
     if (ret != EOK) {
         return ret;
     }
 
-    if (!map->map || !map->entries || !map->entries[0]) {
-        DEBUG(SSSDBG_MINOR_FAILURE, "No entries found\n");
-        ret = sss_cmd_empty_packet(pctx->creq->out);
-        if (ret != EOK) {
-            return autofs_cmd_done(cmdctx, ret);
-        }
-        goto done;
-    }
-
-    for (i=0; i < map->entry_count; i++) {
-        k = ldb_msg_find_attr_as_string(map->entries[i],
-                                        SYSDB_AUTOFS_ENTRY_KEY, NULL);
-        if (!k) {
+    for (i = 0; i < count; i++) {
+        entry_key = ldb_msg_find_attr_as_string(entries[i],
+                                                SYSDB_AUTOFS_ENTRY_KEY,
+                                                NULL);
+        if (entry_key == NULL) {
             DEBUG(SSSDBG_MINOR_FAILURE, "Skipping incomplete entry\n");
             continue;
         }
 
-        if (strcmp(k, key) == 0) {
-            DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", key);
+        if (strcmp(entry_key, keyname) == 0) {
+            DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", keyname);
+            entry = entries[i];
             break;
         }
     }
 
-    if (i >= map->entry_count) {
-        DEBUG(SSSDBG_MINOR_FAILURE, "No key named [%s] found\n", key);
-        ret = sss_cmd_empty_packet(pctx->creq->out);
-        if (ret != EOK) {
-            return autofs_cmd_done(cmdctx, ret);
-        }
-        goto done;
+    if (!enum_ctx->found || count == 0 || entry == NULL) {
+        DEBUG(SSSDBG_TRACE_FUNC, "Key [%s] was not found\n", keyname);
+        return sss_cmd_empty_packet(pctx->creq->out);
     }
 
-    value = ldb_msg_find_attr_as_string(map->entries[i],
-                                        SYSDB_AUTOFS_ENTRY_VALUE, NULL);
+    value = ldb_msg_find_attr_as_string(entry, SYSDB_AUTOFS_ENTRY_VALUE, NULL);
+    if (value == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "No entry value found in [%s]\n", keyname);
+        return EINVAL;
+    }
 
-    valuelen = 1 + strlen(value);
-    len = sizeof(uint32_t) + sizeof(uint32_t) + valuelen;
+    value_len = 1 + strlen(value);
+    len = sizeof(uint32_t) + sizeof(uint32_t) + value_len;
 
     ret = sss_packet_grow(pctx->creq->out, len);
     if (ret != EOK) {
-        goto done;
+        return ret;
     }
 
     sss_packet_get_body(pctx->creq->out, &body, &blen);
@@ -1449,43 +818,88 @@ getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
     rp = 0;
     SAFEALIGN_SET_UINT32(&body[rp], len, &rp);
 
-    SAFEALIGN_SET_UINT32(&body[rp], valuelen, &rp);
-    if (valuelen == 1) {
+    SAFEALIGN_SET_UINT32(&body[rp], value_len, &rp);
+    if (value_len == 1) {
         body[rp] = '\0';
     } else {
-        memcpy(&body[rp], value, valuelen);
+        memcpy(&body[rp], value, value_len);
     }
-    rp += valuelen;
-
-    ret = EOK;
-done:
-    sss_packet_set_error(pctx->creq->out, ret);
-    sss_cmd_done(cmdctx->cctx, cmdctx);
 
     return EOK;
 }
 
+static void
+sss_autofs_cmd_getautomntbyname_done(struct tevent_req *req);
+
 static int
-sss_autofs_cmd_endautomntent(struct cli_ctx *client)
+sss_autofs_cmd_getautomntbyname(struct cli_ctx *cli_ctx)
 {
-    struct cli_protocol *pctx;
+    struct autofs_cmd_ctx *cmd_ctx;
+    struct autofs_ctx *autofs_ctx;
+    struct tevent_req *req;
     errno_t ret;
 
-    DEBUG(SSSDBG_TRACE_FUNC, "endautomntent called\n");
+    autofs_ctx = talloc_get_type(cli_ctx->rctx->pvt_ctx, struct autofs_ctx);
 
-    pctx = talloc_get_type(client->protocol_ctx, struct cli_protocol);
+    cmd_ctx = talloc_zero(cli_ctx, struct autofs_cmd_ctx);
+    if (cmd_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create command context.\n");
+        return ENOMEM;
+    }
 
-    /* create response packet */
-    ret = sss_packet_new(pctx->creq, 0,
-                         sss_packet_get_cmd(pctx->creq->in),
-                         &pctx->creq->out);
+    cmd_ctx->cli_ctx = cli_ctx;
+    cmd_ctx->autofs_ctx = autofs_ctx;
 
+    ret = autofs_read_getautomntbyname_input(cli_ctx, &cmd_ctx->mapname,
+                                             &cmd_ctx->keyname);
     if (ret != EOK) {
-        return ret;
+        goto done;
     }
 
-    sss_cmd_done(client, NULL);
-    return EOK;
+    DEBUG(SSSDBG_TRACE_FUNC, "Obtaining enumeration context for %s\n",
+          cmd_ctx->mapname);
+
+    req = autofs_setent_send(cli_ctx, cli_ctx->ev, autofs_ctx, cmd_ctx->mapname);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    tevent_req_set_callback(req, sss_autofs_cmd_getautomntbyname_done, cmd_ctx);
+
+    ret = EOK;
+
+done:
+    return autofs_cmd_done(cmd_ctx, ret);
+}
+
+static void
+sss_autofs_cmd_getautomntbyname_done(struct tevent_req *req)
+{
+    struct autofs_enum_ctx *enum_ctx;
+    struct autofs_cmd_ctx *cmd_ctx;
+    errno_t ret;
+
+    cmd_ctx = tevent_req_callback_data(req, struct autofs_cmd_ctx);
+
+    ret = autofs_setent_recv(req, &enum_ctx);
+    talloc_zfree(req);
+    if (ret != EOK) {
+        autofs_cmd_done(cmd_ctx, ret);
+        return;
+    }
+
+    ret = autofs_write_getautomntbyname_output(cmd_ctx->cli_ctx, enum_ctx,
+                                               cmd_ctx->keyname);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create reply packet "
+              "[%d]: %s\n", ret, sss_strerror(ret));
+        autofs_cmd_done(cmd_ctx, ret);
+        return;
+    }
+
+    sss_cmd_done(cmd_ctx->cli_ctx, NULL);
 }
 
 struct cli_protocol_version *register_cli_protocol_version(void)
@@ -1518,10 +932,5 @@ int autofs_connection_setup(struct cli_ctx *cctx)
     ret = sss_connection_setup(cctx);
     if (ret != EOK) return ret;
 
-    cctx->state_ctx = talloc_zero(cctx, struct autofs_state_ctx);
-    if (!cctx->state_ctx) {
-        return ENOMEM;
-    }
-
     return EOK;
 }
-- 
2.20.1