diff options
Diffstat (limited to 'src/sss_client/autofs')
-rw-r--r-- | src/sss_client/autofs/autofs_test_client.c | 148 | ||||
-rw-r--r-- | src/sss_client/autofs/sss_autofs.c | 505 | ||||
-rw-r--r-- | src/sss_client/autofs/sss_autofs.exports | 15 | ||||
-rw-r--r-- | src/sss_client/autofs/sss_autofs_private.h | 50 |
4 files changed, 718 insertions, 0 deletions
diff --git a/src/sss_client/autofs/autofs_test_client.c b/src/sss_client/autofs/autofs_test_client.c new file mode 100644 index 0000000..f5cbf36 --- /dev/null +++ b/src/sss_client/autofs/autofs_test_client.c @@ -0,0 +1,148 @@ +/* + Authors: + Jakub Hrozek <jhrozek@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> +#include <errno.h> +#include <popt.h> + +#include "util/util.h" +#include "sss_client/autofs/sss_autofs_private.h" + +struct automtent { + const char *mapname; + size_t cursor; +}; + +int main(int argc, const char *argv[]) +{ + void *ctx; + errno_t ret; + const char *mapname; + char *key = NULL; + char *value = NULL; + char *pc_key = NULL; + int pc_setent = 0; + int pc_protocol = 1; + unsigned int protocol; + unsigned int requested_protocol = 1; + struct poptOption long_options[] = { + POPT_AUTOHELP + { "by-name", 'n', POPT_ARG_STRING, &pc_key, 0, "Request map by name", NULL }, + { "only-setent", 's', POPT_ARG_VAL, &pc_setent, 1, "Run only setent, do not enumerate", NULL }, + { "protocol", 'p', POPT_ARG_INT, &pc_protocol, 0, "Protocol version", NULL }, + POPT_TABLEEND + }; + poptContext pc = NULL; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptSetOtherOptionHelp(pc, "MAPNAME"); + + while (poptGetNextOpt(pc) > 0) + ; + + mapname = poptGetArg(pc); + if (mapname == NULL) { + poptPrintUsage(pc, stderr, 0); + fprintf(stderr, "Please specify the automounter map name\n"); + poptFreeContext(pc); + exit(EXIT_FAILURE); + } + + poptFreeContext(pc); + + requested_protocol = pc_protocol; + protocol = _sss_auto_protocol_version(requested_protocol); + if (protocol != requested_protocol) { + fprintf(stderr, "Unsupported protocol version: %u -> %u\n", + requested_protocol, protocol); + exit(EXIT_FAILURE); + } + + ret = _sss_setautomntent(mapname, &ctx); + if (ret) { + fprintf(stderr, "setautomntent failed [%d]: %s\n", + ret, strerror(ret)); + exit(EXIT_FAILURE); + } + printf("setautomntent done for %s\n", mapname); + + if (pc_setent) { + goto end; + } + + if (!pc_key) { + do { + ret = _sss_getautomntent_r(&key, &value, ctx); + if (ret == 0) { + if (!key || !value) { + fprintf(stderr, + "getautomntent returned success but no data?\n"); + goto end; + } + + printf("key: %s\t\tvalue: %s\n", key, value); + free(key); + key = NULL; + free(value); + value = NULL; + } + } while(ret == 0); + + if (ret != 0 && ret != ENOENT) { + fprintf(stderr, "getautomntent_r failed [%d]: %s\n", + ret, strerror(ret)); + goto end; + } + } else { + ret = _sss_getautomntbyname_r(pc_key, &value, ctx); + if (ret == ENOENT) { + fprintf(stderr, "no such entry in map\n"); + } else if (ret != 0) { + fprintf(stderr, "getautomntbyname_r failed [%d]: %s\n", + ret, strerror(ret)); + goto end; + } else { + if (!value) { + fprintf(stderr, "_sss_getautomntbyname_r " + "returned success but no data?\n"); + goto end; + } + + printf("key: %s\t\tvalue: %s\n", pc_key, value); + free(value); + } + } + +end: + ret = _sss_endautomntent(&ctx); + if (ret) { + fprintf(stderr, "endautomntent failed [%d]: %s\n", + ret, strerror(ret)); + exit(EXIT_FAILURE); + } + printf("endautomntent done for %s\n", mapname); + return 0; +} diff --git a/src/sss_client/autofs/sss_autofs.c b/src/sss_client/autofs/sss_autofs.c new file mode 100644 index 0000000..ef27cf8 --- /dev/null +++ b/src/sss_client/autofs/sss_autofs.c @@ -0,0 +1,505 @@ +/* + Authors: + Jakub Hrozek <jhrozek@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include <stdlib.h> +#include <stdatomic.h> + +#include "sss_client/autofs/sss_autofs_private.h" +#include "sss_client/sss_cli.h" + +/* Historically, autofs map names were just file names. Direct key names + * may be full directory paths + */ +#define MAX_AUTOMNTMAPNAME_LEN NAME_MAX +#define MAX_AUTOMNTKEYNAME_LEN PATH_MAX + +/* How many entries shall _sss_getautomntent_r retrieve at once */ +#define GETAUTOMNTENT_MAX_ENTRIES 512 + +static atomic_uint _protocol = 0; + +unsigned int _sss_auto_protocol_version(unsigned int requested) +{ + switch (requested) { + case 0: + /* EHOSTDOWN will be translated to ENOENT */ + _protocol = 0; + return 0; + default: + /* There is no other protocol version at this point. */ + _protocol = 1; + return 1; + } +} + +/* Returns correct errno based on autofs version expectations. */ +static errno_t errnop_to_errno(int errnop) +{ + if (errnop == EHOSTDOWN && _protocol == 0) { + return ENOENT; + } + + return errnop; +} + +struct automtent { + char *mapname; + size_t cursor; +}; + +static struct sss_getautomntent_data { + char *mapname; + size_t len; + size_t ptr; + uint8_t *data; +} sss_getautomntent_data; + +static void +sss_getautomntent_data_clean(void) +{ + free(sss_getautomntent_data.data); + free(sss_getautomntent_data.mapname); + memset(&sss_getautomntent_data, 0, sizeof(struct sss_getautomntent_data)); +} + +errno_t +_sss_setautomntent(const char *mapname, void **context) +{ + errno_t ret; + int errnop; + struct automtent *ctx; + char *name; + size_t name_len; + struct sss_cli_req_data rd; + uint8_t *repbuf = NULL; + size_t replen; + uint32_t num_results = 0; + + if (!mapname) return EINVAL; + + sss_nss_lock(); + + /* Make sure there are no leftovers from previous runs */ + sss_getautomntent_data_clean(); + + ret = sss_strnlen(mapname, MAX_AUTOMNTMAPNAME_LEN, &name_len); + if (ret != 0) { + ret = EINVAL; + goto out; + } + + name = malloc(sizeof(char)*name_len + 1); + if (name == NULL) { + ret = ENOMEM; + goto out; + } + strncpy(name, mapname, name_len + 1); + + rd.data = name; + rd.len = name_len + 1; + + ret = sss_autofs_make_request(SSS_AUTOFS_SETAUTOMNTENT, &rd, + &repbuf, &replen, &errnop); + if (ret != SSS_STATUS_SUCCESS) { + free(name); + ret = errnop_to_errno(errnop); + goto out; + } + + /* Get number of results from repbuf. */ + SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL); + + /* no results if not found */ + if (num_results == 0) { + free(name); + free(repbuf); + ret = ENOENT; + goto out; + } + free(repbuf); + + ctx = malloc(sizeof(struct automtent)); + if (!ctx) { + free(name); + ret = ENOMEM; + goto out; + } + + ctx->mapname = strdup(name); + if (!ctx->mapname) { + free(name); + free(ctx); + ret = ENOMEM; + goto out; + } + ctx->cursor = 0; + free(name); + + *context = ctx; + ret = 0; +out: + sss_nss_unlock(); + return ret; +} + +static errno_t +sss_getautomntent_data_return(const char *mapname, char **_key, char **_value) +{ + size_t dp; + uint32_t len = 0; + char *key = NULL; + uint32_t keylen; + char *value = NULL; + uint32_t vallen; + errno_t ret; + + if (sss_getautomntent_data.mapname == NULL || + sss_getautomntent_data.data == NULL || + sss_getautomntent_data.ptr >= sss_getautomntent_data.len) { + /* We're done with this buffer */ + ret = ENOENT; + goto done; + } + + ret = strcmp(mapname, sss_getautomntent_data.mapname); + if (ret != EOK) { + /* The map we're looking for is not cached. Let responder + * do an implicit setautomntent */ + ret = ENOENT; + goto done; + } + + dp = sss_getautomntent_data.ptr; + + SAFEALIGN_COPY_UINT32(&len, sss_getautomntent_data.data+dp, &dp); + if (len + sss_getautomntent_data.ptr > sss_getautomntent_data.len) { + /* len is bigger than the buffer */ + ret = EIO; + goto done; + } + + if (len == 0) { + /* There are no more records. */ + *_key = NULL; + *_value = NULL; + ret = ENOENT; + goto done; + } + + SAFEALIGN_COPY_UINT32(&keylen, sss_getautomntent_data.data+dp, &dp); + if (keylen + dp > sss_getautomntent_data.len) { + ret = EIO; + goto done; + } + + key = malloc(keylen); + if (!key) { + ret = ENOMEM; + goto done; + } + + safealign_memcpy(key, sss_getautomntent_data.data+dp, keylen, &dp); + + SAFEALIGN_COPY_UINT32(&vallen, sss_getautomntent_data.data+dp, &dp); + if (vallen + dp > sss_getautomntent_data.len) { + ret = EIO; + goto done; + } + + value = malloc(vallen); + if (!value) { + ret = ENOMEM; + goto done; + } + + safealign_memcpy(value, sss_getautomntent_data.data+dp, vallen, &dp); + + sss_getautomntent_data.ptr = dp; + *_key = key; + *_value = value; + return EOK; + +done: + free(key); + free(value); + sss_getautomntent_data_clean(); + return ret; +} + +/* The repbuf is owned by the sss_getautomntent_data once this + * function is called */ +static errno_t +sss_getautomntent_data_save(const char *mapname, uint8_t **repbuf, size_t replen) +{ + size_t rp; + uint32_t num; + + rp = 0; + SAFEALIGN_COPY_UINT32(&num, *repbuf+rp, &rp); + if (num == 0) { + free(*repbuf); + return ENOENT; + } + + sss_getautomntent_data.mapname = strdup(mapname); + if (sss_getautomntent_data.mapname == NULL) { + free(*repbuf); + return ENOENT; + } + + sss_getautomntent_data.data = *repbuf; + sss_getautomntent_data.len = replen; + sss_getautomntent_data.ptr = rp; + *repbuf = NULL; + return EOK; +} + +errno_t +_sss_getautomntent_r(char **key, char **value, void *context) +{ + int errnop; + errno_t ret; + size_t name_len; + struct sss_cli_req_data rd; + uint8_t *repbuf = NULL; + size_t replen; + struct automtent *ctx; + size_t ctr = 0; + size_t data_len = 0; + uint8_t *data; + + sss_nss_lock(); + + ctx = (struct automtent *) context; + if (!ctx) { + ret = EINVAL; + goto out; + } + + /* Be paranoid in case someone tries to smuggle in a huge map name */ + ret = sss_strnlen(ctx->mapname, MAX_AUTOMNTMAPNAME_LEN, &name_len); + if (ret != 0) { + ret = EINVAL; + goto out; + } + + ret = sss_getautomntent_data_return(ctx->mapname, key, value); + if (ret == EOK) { + /* The results are available from cache. Just advance the + * cursor and return. */ + ctx->cursor++; + ret = 0; + goto out; + } + /* Don't try to handle any error codes, just go to the responder again */ + + data_len = sizeof(uint32_t) + /* mapname len */ + name_len + 1 + /* mapname\0 */ + sizeof(uint32_t) + /* index into the map */ + sizeof(uint32_t); /* num entries to retrieve */ + + data = malloc(data_len); + if (!data) { + ret = ENOMEM; + goto out; + } + + SAFEALIGN_SET_UINT32(data, name_len, &ctr); + + safealign_memcpy(data+ctr, ctx->mapname, name_len + 1, &ctr); + + SAFEALIGN_SET_UINT32(data+ctr, ctx->cursor, &ctr); + + SAFEALIGN_SET_UINT32(data+ctr, GETAUTOMNTENT_MAX_ENTRIES, &ctr); + + rd.data = data; + rd.len = data_len; + + ret = sss_autofs_make_request(SSS_AUTOFS_GETAUTOMNTENT, &rd, + &repbuf, &replen, &errnop); + free(data); + if (ret != SSS_STATUS_SUCCESS) { + ret = errnop_to_errno(errnop); + goto out; + } + + /* Got reply, let's save it and return from "cache" */ + ret = sss_getautomntent_data_save(ctx->mapname, &repbuf, replen); + if (ret == ENOENT) { + /* No results */ + *key = NULL; + *value = NULL; + goto out; + } else if (ret != EOK) { + /* Unexpected error */ + goto out; + } + + ret = sss_getautomntent_data_return(ctx->mapname, key, value); + if (ret != EOK) { + goto out; + } + + /* Advance the cursor so that we'll fetch the next map + * next time getautomntent is called */ + ctx->cursor++; + ret = 0; +out: + sss_nss_unlock(); + return ret; +} + +errno_t +_sss_getautomntbyname_r(const char *key, char **value, void *context) +{ + int errnop; + errno_t ret; + struct automtent *ctx; + size_t key_len; + size_t name_len; + size_t data_len = 0; + uint8_t *data; + size_t ctr = 0; + struct sss_cli_req_data rd; + uint8_t *repbuf = NULL; + size_t replen; + + char *buf; + uint32_t len; + uint32_t vallen; + size_t rp; + + sss_nss_lock(); + + ctx = (struct automtent *) context; + if (!ctx || !key) { + ret = EINVAL; + goto out; + } + + /* Be paranoid in case someone tries to smuggle in a huge map name */ + ret = sss_strnlen(ctx->mapname, MAX_AUTOMNTMAPNAME_LEN, &name_len); + if (ret != 0) { + ret = EINVAL; + goto out; + } + + ret = sss_strnlen(key, MAX_AUTOMNTKEYNAME_LEN, &key_len); + if (ret != 0) { + ret = EINVAL; + goto out; + } + + + data_len = sizeof(uint32_t) + /* mapname len */ + name_len + 1 + /* mapname\0 */ + sizeof(uint32_t) + /* keyname len */ + key_len + 1; /* keyname\0 */ + + data = malloc(data_len); + if (!data) { + ret = ENOMEM; + goto out; + } + + SAFEALIGN_SET_UINT32(data, name_len, &ctr); + + safealign_memcpy(data+ctr, ctx->mapname, name_len + 1, &ctr); + + SAFEALIGN_SET_UINT32(data+ctr, key_len, &ctr); + + safealign_memcpy(data+ctr, key, key_len + 1, &ctr); + + rd.data = data; + rd.len = data_len; + + ret = sss_autofs_make_request(SSS_AUTOFS_GETAUTOMNTBYNAME, &rd, + &repbuf, &replen, &errnop); + free(data); + if (ret != SSS_STATUS_SUCCESS) { + ret = errnop_to_errno(errnop); + goto out; + } + + /* Got reply, let's parse it */ + rp = 0; + SAFEALIGN_COPY_UINT32(&len, repbuf+rp, &rp); + if (len == 0) { + /* No data */ + *value = NULL; + ret = ENOENT; + goto out; + } + + SAFEALIGN_COPY_UINT32(&vallen, repbuf+rp, &rp); + if (vallen > len-rp) { + ret = EIO; + goto out; + } + + buf = malloc(vallen); + if (!buf) { + ret = ENOMEM; + goto out; + } + + safealign_memcpy(buf, repbuf+rp, vallen, &rp); + *value = buf; + + ret = 0; +out: + free(repbuf); + sss_nss_unlock(); + return ret; +} + +errno_t +_sss_endautomntent(void **context) +{ + struct automtent *fctx; + errno_t ret; + int errnop; + + if (!context) return 0; + + sss_nss_lock(); + + sss_getautomntent_data_clean(); + + fctx = (struct automtent *) *context; + + if (fctx != NULL) { + free(fctx->mapname); + free(fctx); + } + + ret = sss_autofs_make_request(SSS_AUTOFS_ENDAUTOMNTENT, + NULL, NULL, NULL, &errnop); + if (ret != SSS_STATUS_SUCCESS) { + ret = errnop_to_errno(errnop); + goto out; + } + + ret = 0; +out: + sss_nss_unlock(); + return ret; +} diff --git a/src/sss_client/autofs/sss_autofs.exports b/src/sss_client/autofs/sss_autofs.exports new file mode 100644 index 0000000..ec61f71 --- /dev/null +++ b/src/sss_client/autofs/sss_autofs.exports @@ -0,0 +1,15 @@ +EXPORTED { + + # public functions + global: + _sss_auto_protocol_version; + _sss_setautomntent; + _sss_getautomntent_r; + _sss_getautomntbyname_r; + _sss_endautomntent; + + # everything else is local + local: + *; +}; + diff --git a/src/sss_client/autofs/sss_autofs_private.h b/src/sss_client/autofs/sss_autofs_private.h new file mode 100644 index 0000000..7fd49db --- /dev/null +++ b/src/sss_client/autofs/sss_autofs_private.h @@ -0,0 +1,50 @@ +/* + Authors: + Jakub Hrozek <jhrozek@redhat.com> + + Copyright (C) 2012 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <errno.h> +#include "util/util.h" + +/** + * Choose an autofs protocol version to be used between autofs and sss_autofs. + */ +unsigned int _sss_auto_protocol_version(unsigned int requested); + +/** + * Selects a map for processing. + */ +errno_t _sss_setautomntent(const char *mapname, void **context); + +/** + * Iterates through key/value pairs in the selected map. The key is usually + * the mount point, the value is mount information (server:/export) + */ +errno_t _sss_getautomntent_r(char **key, char **value, void *context); + +/** + * Returns value for a specific key + */ +errno_t +_sss_getautomntbyname_r(const char *key, char **value, void *context); + +/** + * Deselect a map, end the processing + */ +errno_t _sss_endautomntent(void **context); + |