From b0043a95f86b240d0beb551ef4e9ff9a4be99995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= 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 --- 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:""); - - 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 \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 \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