autofssrv_cmd.c revision 877b92e80bde510d5cd9f03dbf01e2bcf73ab072
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen/*
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Authors:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Jakub Hrozek <jhrozek@redhat.com>
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Copyright (C) 2012 Red Hat
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen Autofs responder: commands
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen This program is free software; you can redistribute it and/or modify
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen it under the terms of the GNU General Public License as published by
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen the Free Software Foundation; either version 3 of the License, or
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen (at your option) any later version.
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen This program is distributed in the hope that it will be useful,
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen GNU General Public License for more details.
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen You should have received a copy of the GNU General Public License
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen*/
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen#include <talloc.h>
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen#include "util/util.h"
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen#include "responder/common/responder.h"
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen#include "responder/common/responder_packet.h"
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen#include "responder/autofs/autofs_private.h"
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen#include "db/sysdb.h"
05b7b8f14426b5fe5d016940eb5916033f0bc841Timo Sirainen#include "db/sysdb_autofs.h"
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen#include "confdb/confdb.h"
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainenstatic int autofs_cmd_send_error(struct autofs_cmd_ctx *cmdctx, int err)
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen{
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen return sss_cmd_send_error(cmdctx->cctx, err);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomiautofs_cmd_send_empty(struct autofs_cmd_ctx *cmdctx)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen return sss_cmd_send_empty(cmdctx->cctx, cmdctx);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen}
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenstatic int
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenautofs_cmd_done(struct autofs_cmd_ctx *cmdctx, int ret)
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen{
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen switch (ret) {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen case EOK:
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* all fine, just return here */
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen break;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen case ENOENT:
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen ret = autofs_cmd_send_empty(cmdctx);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen if (ret) {
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen return EFAULT;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen }
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen break;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen case EAGAIN:
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* async processing, just return here */
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen break;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen case EFAULT:
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen /* very bad error */
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen return EFAULT;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen default:
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi ret = autofs_cmd_send_error(cmdctx, ret);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen return EFAULT;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen sss_cmd_done(cmdctx->cctx, cmdctx);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen break;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen return EOK;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen}
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomistatic errno_t
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenautofs_setent_add_ref(TALLOC_CTX *memctx,
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen struct autofs_map_ctx *map_ctx,
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen struct tevent_req *req)
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen return setent_add_ref(memctx, map_ctx, &map_ctx->reqs, req);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen}
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenstatic void
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenautofs_setent_notify(struct autofs_map_ctx *map_ctx, errno_t ret)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen setent_notify(&map_ctx->reqs, ret);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen}
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenerrno_t
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenautofs_orphan_maps(struct autofs_ctx *actx)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen int hret;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen unsigned long mcount;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen unsigned long i;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hash_key_t *maps;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (!actx || !actx->maps) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return EINVAL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
009217abb57a24a4076092e8e4e165545747839eStephan Bosch
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hret = hash_keys(actx->maps, &mcount, &maps);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (hret != HASH_SUCCESS) {
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen return EIO;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen for (i = 0; i < mcount; i++) {
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen hret = hash_delete(actx->maps, &maps[i]);
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (hret != HASH_SUCCESS) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete key from hash\n");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen continue;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen return EOK;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainenstatic errno_t
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainenget_autofs_map(struct autofs_ctx *actx,
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen char *mapname,
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen struct autofs_map_ctx **map)
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen{
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen hash_key_t key;
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen hash_value_t value;
5754fa860405e9af20c38981942f6aa97ce3158dTimo Sirainen int hret;
4dc8d682c855ca78db8874e04302e885465c1d65Timo Sirainen
4dc8d682c855ca78db8874e04302e885465c1d65Timo Sirainen key.type = HASH_KEY_STRING;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen key.str = mapname;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen hret = hash_lookup(actx->maps, &key, &value);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (hret == HASH_SUCCESS) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen *map = talloc_get_type(value.ptr, struct autofs_map_ctx);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return EOK;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (hret == HASH_ERROR_KEY_NOT_FOUND) {
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi return ENOENT;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen "Unexpected error reading from autofs map hash [%d][%s]\n",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hret, hash_error_string(hret));
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen return EIO;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainenstatic int autofs_map_hash_remove (TALLOC_CTX *ctx);
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainenvoid
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainenautofs_map_hash_delete_cb(hash_entry_t *item,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen hash_destroy_enum deltype, void *pvt)
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen{
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen struct autofs_map_ctx *map;
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen if (deltype != HASH_ENTRY_DESTROY) {
3dc72a40e457658caa3c033fb6b3418d16e9fd21Timo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen map = talloc_get_type(item->value.ptr, struct autofs_map_ctx);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen if (!map) {
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen DEBUG(SSSDBG_OP_FAILURE, "Invalid autofs map\n");
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen return;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* So that the destructor wouldn't attempt to remove the map from hash
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen * table */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen map->map_table = NULL;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen}
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic errno_t
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenset_autofs_map(struct autofs_ctx *actx,
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen struct autofs_map_ctx *map)
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hash_key_t key;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hash_value_t value;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int hret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (map->mapname == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Missing autofs map name.\n");
009217abb57a24a4076092e8e4e165545747839eStephan Bosch return EINVAL;
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi }
3e0c0a269390de8495e8f6ecaed59a823221480eAki Tuomi
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* Add this entry to the hash table */
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainen key.type = HASH_KEY_STRING;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen key.str = map->mapname;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen value.type = HASH_VALUE_PTR;
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen value.ptr = map;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hret = hash_enter(actx->maps, &key, &value);
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen if (hret != EOK) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen "Unable to add hash table entry for [%s]\n", key.str);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DEBUG(SSSDBG_MINOR_FAILURE,
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen "Hash error [%d][%s]\n", hret, hash_error_string(hret));
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen return EIO;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen }
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen talloc_steal(actx->maps, map);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen talloc_set_destructor((TALLOC_CTX *) map, autofs_map_hash_remove);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen return EOK;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenstatic int
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenautofs_map_hash_remove(TALLOC_CTX *ctx)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen int hret;
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen hash_key_t key;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct autofs_map_ctx *map =
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen talloc_get_type(ctx, struct autofs_map_ctx);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (map->map_table == NULL) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen DEBUG(SSSDBG_TRACE_LIBS, "autofs map [%s] was already removed\n",
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen map->mapname);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen key.type = HASH_KEY_STRING;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen key.str = map->mapname;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
f5d82a4b87a9b17894e1869cfe8b1a90afbced59Timo Sirainen /* Remove the autofs map result object from the lookup table */
f5d82a4b87a9b17894e1869cfe8b1a90afbced59Timo Sirainen hret = hash_delete(map->map_table, &key);
ce8d63810932f48176304ed08cd8b7652c4a8addTimo Sirainen if (hret != HASH_SUCCESS) {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen "Could not remove key from table! [%d][%s]\n",
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen hret, hash_error_string(hret));
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen return -1;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen }
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen return 0;
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen}
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainenstatic struct tevent_req *
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainensetautomntent_send(TALLOC_CTX *mem_ctx,
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen const char *rawname,
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen struct autofs_cmd_ctx *cmdctx);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainenstatic errno_t setautomntent_recv(struct tevent_req *req);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainenstatic void sss_autofs_cmd_setautomntent_done(struct tevent_req *req);
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen/* FIXME - file a ticket to have per-responder private
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen * data instead of growing the cli_ctx structure */
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainenstatic int
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainensss_autofs_cmd_setautomntent(struct cli_ctx *client)
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct autofs_cmd_ctx *cmdctx;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen uint8_t *body;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen size_t blen;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen errno_t ret = EOK;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen const char *rawname;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct tevent_req *req;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_setautomntent\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (!cmdctx) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return ENOMEM;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen cmdctx->cctx = client;
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen
e2fdcdb4ee53ab769123e27997713aaea34910e1Timo Sirainen sss_packet_get_body(client->creq->in, &body, &blen);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen /* if not terminated fail */
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen if (body[blen -1] != '\0') {
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen ret = EINVAL;
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainen goto done;
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen }
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen
c3a2a487e23a282e59254b82deb9344ed0306bb2Timo Sirainen /* If the body isn't valid UTF-8, fail */
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (!sss_utf8_check(body, blen -1)) {
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen ret = EINVAL;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen goto done;
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen }
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen
1f7f4294207557edf83171642ef62ce4922ffc9dTimo Sirainen rawname = (const char *)body;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DEBUG(SSSDBG_TRACE_FUNC,
"Got request for automount map named %s\n", rawname);
req = setautomntent_send(cmdctx, rawname, cmdctx);
if (!req) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Fatal error calling setautomntent_send\n");
ret = EIO;
goto done;
}
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)
{
struct autofs_cmd_ctx *cmdctx =
tevent_req_callback_data(req, struct autofs_cmd_ctx);
errno_t ret;
errno_t reqret;
struct sss_packet *packet;
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;
}
/* Either we succeeded or no domains were eligible */
ret = sss_packet_new(cmdctx->cctx->creq, 0,
sss_packet_get_cmd(cmdctx->cctx->creq->in),
&cmdctx->cctx->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 */
sss_cmd_empty_packet(cmdctx->cctx->creq->out);
} else {
DEBUG(SSSDBG_TRACE_FUNC, "setautomntent found data\n");
packet = cmdctx->cctx->creq->out;
ret = sss_packet_grow(packet, 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(packet, &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;
}
DEBUG(SSSDBG_CRIT_FAILURE, "Error creating packet\n");
return;
}
struct setautomntent_state {
struct autofs_cmd_ctx *cmdctx;
struct autofs_dom_ctx *dctx;
char *mapname;
struct autofs_map_ctx *map;
};
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,
lookup_ctx->rctx, 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 struct tevent_req *
setautomntent_send(TALLOC_CTX *mem_ctx,
const char *rawname,
struct autofs_cmd_ctx *cmdctx)
{
char *domname;
errno_t ret;
struct tevent_req *req;
struct setautomntent_state *state;
struct cli_ctx *client = cmdctx->cctx;
struct autofs_dom_ctx *dctx;
struct autofs_ctx *actx =
talloc_get_type(client->rctx->pvt_ctx, struct autofs_ctx);
struct setautomntent_lookup_ctx *lookup_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;
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;
}
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;
}
client->automntmap_name = talloc_strdup(client, rawname);
if (!client->automntmap_name) {
ret = ENOMEM;
goto fail;
}
} else {
/* this is a multidomain search */
dctx->domain = client->rctx->domains;
cmdctx->check_next = true;
client->automntmap_name = talloc_strdup(client, state->mapname);
if (!client->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;
}
}
/* 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);
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;
}
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 = set_autofs_map(actx, state->map);
if (ret != EOK) {
talloc_free(state->map);
goto fail;
}
/* Perform lookup */
lookup_ctx = talloc_zero(state->map, struct setautomntent_lookup_ctx);
if (!lookup_ctx) {
talloc_free(state->map);
ret = ENOMEM;
goto fail;
}
/* 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;
}
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;
}
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;
}
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)
{
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;
}
return get_autofs_map(actx, mapname, map);
}
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);
}
/* make sure to update the dctx if we changed domain */
dctx->domain = dom;
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;
}
/* 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;
}
}
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;
}
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;
}
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;
}
}
/* 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;
}
map->map = talloc_steal(map, dctx->map);
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;
}
map = talloc_zero(lookup_ctx->actx, struct autofs_map_ctx);
if (!map) {
return ENOMEM;
}
map->ready = true;
map->found = false;
map->map_table = lookup_ctx->actx->maps;
map->mapname = talloc_strdup(map, lookup_ctx->mapname);
if (!map->mapname) {
talloc_free(map);
return ENOMEM;
}
ret = set_autofs_map(lookup_ctx->actx, map);
if (ret != EOK) {
talloc_free(map);
return ENOMEM;
}
set_autofs_map_lifetime(lookup_ctx->actx->neg_timeout, lookup_ctx, map);
/* If we've gotten here, then no domain contained this map */
return ENOENT;
}
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)
{
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;
}
}
/* 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;
}
cb_ctx = talloc_zero(lookup_ctx->dctx, struct dp_callback_ctx);
if(!cb_ctx) {
talloc_zfree(req);
ret = ENOMEM;
goto error;
}
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;
error:
ret = autofs_cmd_send_error(lookup_ctx->dctx->cmd_ctx, ret);
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);
/* Loop to the next domain if possible */
if (dctx->cmd_ctx->check_next && get_next_domain(dctx->domain, 0)) {
dctx->domain = get_next_domain(dctx->domain, 0);
dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
}
}
/* ok the backend returned, search to see if we have updated results */
ret = lookup_automntmap_step(lookup_ctx);
if (ret != EOK) {
if (ret == EAGAIN) {
return;
}
}
/* We have results to return */
autofs_setent_notify(lookup_ctx->map, ret);
}
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);
static int
sss_autofs_cmd_getautomntent(struct cli_ctx *client)
{
struct autofs_cmd_ctx *cmdctx;
struct autofs_map_ctx *map;
struct autofs_ctx *actx;
uint8_t *body;
size_t blen;
errno_t ret;
uint32_t namelen;
size_t c = 0;
struct tevent_req *req;
DEBUG(SSSDBG_TRACE_INTERNAL, "sss_autofs_cmd_getautomntent\n");
cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
if (!cmdctx) {
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;
}
/* get autofs map name and index to query */
sss_packet_get_body(client->creq->in, &body, &blen);
SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
if (namelen == 0 || namelen > blen - c) {
ret = EINVAL;
goto done;
}
cmdctx->mapname = (char *) body+c;
/* if not null-terminated fail */
if (cmdctx->mapname[namelen] != '\0') {
ret = EINVAL;
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;
}
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);
DEBUG(SSSDBG_TRACE_FUNC,
"Requested data of map %s cursor %d max entries %d\n",
cmdctx->mapname, cmdctx->cursor, cmdctx->max_entries);
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, 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;
}
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, 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;
}
DEBUG(SSSDBG_TRACE_INTERNAL,
"returning entries for [%s]\n", map->mapname);
ret = getautomntent_process(cmdctx, map, cmdctx->cursor, cmdctx->max_entries);
done:
return autofs_cmd_done(cmdctx, ret);
}
static void
getautomntent_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 (map->ready == false) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Map not ready after setautomntent succeeded\n");
goto done;
}
ret = getautomntent_process(cmdctx, map,
cmdctx->cursor, cmdctx->max_entries);
done:
autofs_cmd_done(cmdctx, ret);
return;
}
static errno_t
getautomntent_process(struct autofs_cmd_ctx *cmdctx,
struct autofs_map_ctx *map,
uint32_t cursor, uint32_t max_entries)
{
struct cli_ctx *client = cmdctx->cctx;
errno_t ret;
struct ldb_message *entry;
size_t rp;
uint32_t i, stop, left, nentries;
uint8_t *body;
size_t blen;
/* create response packet */
ret = sss_packet_new(client->creq, 0,
sss_packet_get_cmd(client->creq->in),
&client->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(client->creq->out);
if (ret != EOK) {
return autofs_cmd_done(cmdctx, ret);
}
goto done;
}
/* allocate memory for number of entries in the packet */
ret = sss_packet_grow(client->creq->out, sizeof(uint32_t));
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
goto done;
}
rp = sizeof(uint32_t); /* We'll write the number of entries here */
left = map->entry_count - cursor;
stop = max_entries < left ? max_entries : left;
nentries = 0;
for (i=0; i < stop; i++) {
entry = map->entries[cursor];
cursor++;
ret = fill_autofs_entry(entry, client->creq->out, &rp);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Cannot fill entry %d/%d, skipping\n", i, stop);
continue;
}
nentries++;
}
/* packet grows in fill_autofs_entry, body pointer may change,
* thus we have to obtain it here */
sss_packet_get_body(client->creq->out, &body, &blen);
rp = 0;
SAFEALIGN_SET_UINT32(&body[rp], nentries, &rp);
ret = EOK;
done:
sss_packet_set_error(client->creq->out, ret);
sss_cmd_done(client, cmdctx);
return EOK;
}
static errno_t
fill_autofs_entry(struct ldb_message *entry, struct sss_packet *packet, size_t *rp)
{
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;
}
keylen = 1 + strlen(key);
valuelen = 1 + strlen(value);
len = sizeof(uint32_t) + sizeof(uint32_t) + keylen + sizeof(uint32_t) + valuelen;
ret = sss_packet_grow(packet, len);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Cannot grow packet\n");
return ret;
}
sss_packet_get_body(packet, &body, &blen);
SAFEALIGN_SET_UINT32(&body[*rp], len, rp);
SAFEALIGN_SET_UINT32(&body[*rp], keylen, rp);
if (keylen == 1) {
body[*rp] = '\0';
} else {
memcpy(&body[*rp], key, keylen);
}
*rp += keylen;
SAFEALIGN_SET_UINT32(&body[*rp], valuelen, rp);
if (valuelen == 1) {
body[*rp] = '\0';
} else {
memcpy(&body[*rp], value, valuelen);
}
*rp += valuelen;
return EOK;
}
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)
{
errno_t ret;
struct autofs_cmd_ctx *cmdctx;
struct autofs_map_ctx *map;
struct autofs_ctx *actx;
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");
cmdctx = talloc_zero(client, struct autofs_cmd_ctx);
if (!cmdctx) {
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;
}
/* get autofs map name and index to query */
sss_packet_get_body(client->creq->in, &body, &blen);
/* FIXME - split out a function to get string from <len><str>\0 */
SAFEALIGN_COPY_UINT32_CHECK(&namelen, body+c, blen, &c);
if (namelen == 0 || namelen > blen - c) {
ret = EINVAL;
goto done;
}
cmdctx->mapname = (char *) body+c;
/* if not null-terminated fail */
if (cmdctx->mapname[namelen] != '\0') {
ret = EINVAL;
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;
}
c += namelen + 1;
/* FIXME - split out a function to get string from <len><str>\0 */
SAFEALIGN_COPY_UINT32_CHECK(&keylen, body+c, blen, &c);
if (keylen == 0 || keylen > blen - c) {
ret = EINVAL;
goto done;
}
cmdctx->key = (char *) body+c;
/* if not null-terminated fail */
if (cmdctx->key[keylen] != '\0') {
ret = EINVAL;
goto done;
}
/* 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 (map->ready == false) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Map not ready after setautomntent succeeded\n");
goto done;
}
ret = getautomntbyname_process(cmdctx, map, cmdctx->key);
done:
autofs_cmd_done(cmdctx, ret);
return;
}
static errno_t
getautomntbyname_process(struct autofs_cmd_ctx *cmdctx,
struct autofs_map_ctx *map,
const char *key)
{
struct cli_ctx *client = cmdctx->cctx;
errno_t ret;
size_t i;
const char *k;
const char *value;
size_t valuelen;
size_t len;
uint8_t *body;
size_t blen, rp;
/* create response packet */
ret = sss_packet_new(client->creq, 0,
sss_packet_get_cmd(client->creq->in),
&client->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(client->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) {
DEBUG(SSSDBG_MINOR_FAILURE, "Skipping incomplete entry\n");
continue;
}
if (strcmp(k, key) == 0) {
DEBUG(SSSDBG_TRACE_INTERNAL, "Found key [%s]\n", key);
break;
}
}
if (i >= map->entry_count) {
DEBUG(SSSDBG_MINOR_FAILURE, "No key named [%s] found\n", key);
ret = sss_cmd_empty_packet(client->creq->out);
if (ret != EOK) {
return autofs_cmd_done(cmdctx, ret);
}
goto done;
}
value = ldb_msg_find_attr_as_string(map->entries[i],
SYSDB_AUTOFS_ENTRY_VALUE, NULL);
valuelen = 1 + strlen(value);
len = sizeof(uint32_t) + sizeof(uint32_t) + valuelen;
ret = sss_packet_grow(client->creq->out, len);
if (ret != EOK) {
goto done;
}
sss_packet_get_body(client->creq->out, &body, &blen);
rp = 0;
SAFEALIGN_SET_UINT32(&body[rp], len, &rp);
SAFEALIGN_SET_UINT32(&body[rp], valuelen, &rp);
if (valuelen == 1) {
body[rp] = '\0';
} else {
memcpy(&body[rp], value, valuelen);
}
rp += valuelen;
ret = EOK;
done:
sss_packet_set_error(client->creq->out, ret);
sss_cmd_done(client, cmdctx);
return EOK;
}
static int
sss_autofs_cmd_endautomntent(struct cli_ctx *client)
{
errno_t ret;
DEBUG(SSSDBG_TRACE_FUNC, "endautomntent called\n");
/* create response packet */
ret = sss_packet_new(client->creq, 0,
sss_packet_get_cmd(client->creq->in),
&client->creq->out);
if (ret != EOK) {
return ret;
}
sss_cmd_done(client, NULL);
return EOK;
}
struct cli_protocol_version *register_cli_protocol_version(void)
{
static struct cli_protocol_version autofs_cli_protocol_version[] = {
{ SSS_AUTOFS_PROTO_VERSION, NULL, NULL }
};
return autofs_cli_protocol_version;
}
struct sss_cmd_table *get_autofs_cmds(void)
{
static struct sss_cmd_table autofs_cmds[] = {
{ SSS_GET_VERSION, sss_cmd_get_version },
{ SSS_AUTOFS_SETAUTOMNTENT, sss_autofs_cmd_setautomntent },
{ SSS_AUTOFS_GETAUTOMNTENT, sss_autofs_cmd_getautomntent },
{ SSS_AUTOFS_GETAUTOMNTBYNAME, sss_autofs_cmd_getautomntbyname },
{ SSS_AUTOFS_ENDAUTOMNTENT, sss_autofs_cmd_endautomntent },
{ SSS_CLI_NULL, NULL}
};
return autofs_cmds;
}