diff options
author | Lukas Slebodnik <lslebodn@redhat.com> | 2015-06-30 16:36:03 +0200 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2015-07-03 15:17:02 +0200 |
commit | 88e68607e474ab2ce46c562753ef2e988516d1e9 (patch) | |
tree | d7e0297a1ee53900eff0671d7b2e0d973c05dc02 /src | |
parent | 7c83c23177cdb43e23fe19935356e1319e2b6f39 (diff) | |
download | sssd-88e68607e474ab2ce46c562753ef2e988516d1e9.tar.gz sssd-88e68607e474ab2ce46c562753ef2e988516d1e9.tar.xz sssd-88e68607e474ab2ce46c562753ef2e988516d1e9.zip |
sss_client: Use initgr mmap cache in client code
Resolves:
https://fedorahosted.org/sssd/ticket/2485
Reviewed-by: Michal Židek <mzidek@redhat.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/sss_client/nss_group.c | 29 | ||||
-rw-r--r-- | src/sss_client/nss_mc.h | 5 | ||||
-rw-r--r-- | src/sss_client/nss_mc_initgr.c | 159 |
3 files changed, 192 insertions, 1 deletions
diff --git a/src/sss_client/nss_group.c b/src/sss_client/nss_group.c index 1614c33b5..b614fcf7f 100644 --- a/src/sss_client/nss_group.c +++ b/src/sss_client/nss_group.c @@ -281,10 +281,37 @@ enum nss_status _nss_sss_initgroups_dyn(const char *user, gid_t group, size_t replen; enum nss_status nret; size_t buf_index = 0; + size_t user_len; uint32_t num_ret; long int l, max_ret; + int ret; + + ret = sss_strnlen(user, SSS_NAME_MAX, &user_len); + if (ret != 0) { + *errnop = EINVAL; + return NSS_STATUS_NOTFOUND; + } + + ret = sss_nss_mc_initgroups_dyn(user, user_len, group, start, size, + groups, limit); + switch (ret) { + case 0: + *errnop = 0; + return NSS_STATUS_SUCCESS; + case ERANGE: + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + case ENOENT: + /* fall through, we need to actively ask the parent + * if no entry is found */ + break; + default: + /* if using the mmaped cache failed, + * fall back to socket based comms */ + break; + } - rd.len = strlen(user) +1; + rd.len = user_len + 1; rd.data = user; sss_nss_lock(); diff --git a/src/sss_client/nss_mc.h b/src/sss_client/nss_mc.h index 050bd4100..a39d45f14 100644 --- a/src/sss_client/nss_mc.h +++ b/src/sss_client/nss_mc.h @@ -85,4 +85,9 @@ errno_t sss_nss_mc_getgrgid(gid_t gid, struct group *result, char *buffer, size_t buflen); +/* initgroups db */ +errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len, + gid_t group, long int *start, long int *size, + gid_t **groups, long int limit); + #endif /* _NSS_MC_H_ */ diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c new file mode 100644 index 000000000..bfb09d655 --- /dev/null +++ b/src/sss_client/nss_mc_initgr.c @@ -0,0 +1,159 @@ +/* + * System Security Services Daemon. NSS client interface + * + * Authors: + * Lukas Slebodnik <lslebodn@redhat.com> + * + * Copyright (C) 2015 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 2.1 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/>. + */ + +/* INITGROUPs database NSS interface using mmap cache */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <sys/mman.h> +#include <time.h> +#include "nss_mc.h" +#include "util/util_safealign.h" + +struct sss_cli_mc_ctx initgr_mc_ctx = { UNINITIALIZED, -1, 0, NULL, 0, NULL, 0, + NULL, 0, 0 }; + +static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec, + long int *start, long int *size, + gid_t **groups, long int limit) +{ + struct sss_mc_initgr_data *data; + time_t expire; + long int i; + uint32_t gid_count; + long int max_ret; + + /* additional checks before filling result*/ + expire = rec->expire; + if (expire < time(NULL)) { + /* entry is now invalid */ + return EINVAL; + } + + data = (struct sss_mc_initgr_data *)rec->data; + gid_count = data->members; + max_ret = gid_count; + + /* check we have enough space in the buffer */ + if ((*size - *start) < gid_count) { + long int newsize; + gid_t *newgroups; + + newsize = *size + gid_count; + if ((limit > 0) && (newsize > limit)) { + newsize = limit; + max_ret = newsize - *start; + } + + newgroups = (gid_t *)realloc((*groups), newsize * sizeof(**groups)); + if (!newgroups) { + return ENOMEM; + } + *groups = newgroups; + *size = newsize; + } + + for (i = 0; i < max_ret; i++) { + SAFEALIGN_COPY_UINT32(&(*groups)[*start], data->gids + i, NULL); + *start += 1; + } + + return 0; +} + +errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len, + gid_t group, long int *start, long int *size, + gid_t **groups, long int limit) +{ + struct sss_mc_rec *rec = NULL; + struct sss_mc_initgr_data *data; + char *rec_name; + uint32_t hash; + uint32_t slot; + int ret; + uint8_t *max_addr; + + ret = sss_nss_mc_get_ctx("initgroups", &initgr_mc_ctx); + if (ret) { + return ret; + } + + /* Get max address of data table. */ + max_addr = initgr_mc_ctx.data_table + initgr_mc_ctx.dt_size; + + /* hashes are calculated including the NULL terminator */ + hash = sss_nss_mc_hash(&initgr_mc_ctx, name, name_len + 1); + slot = initgr_mc_ctx.hash_table[hash]; + + /* If slot is not within the bounds of mmaped region and + * it's value is not MC_INVALID_VAL, then the cache is + * probbably corrupted. */ + while (MC_SLOT_WITHIN_BOUNDS(slot, initgr_mc_ctx.dt_size)) { + /* free record from previous iteration */ + free(rec); + rec = NULL; + + ret = sss_nss_mc_get_record(&initgr_mc_ctx, slot, &rec); + if (ret) { + goto done; + } + + /* check record matches what we are searching for */ + if (hash != rec->hash1) { + /* if name hash does not match we can skip this immediately */ + slot = sss_nss_mc_next_slot_with_hash(rec, hash); + continue; + } + + data = (struct sss_mc_initgr_data *)rec->data; + /* Integrity check + * - array with gids must be within data_table + * - string must be within data_table */ + if ((uint8_t *)data->gids > max_addr + || (uint8_t *)data + data->name + name_len > max_addr) { + ret = ENOENT; + goto done; + } + + rec_name = (char *)data + data->name; + if (strcmp(name, rec_name) == 0) { + break; + } + + slot = sss_nss_mc_next_slot_with_hash(rec, hash); + } + + if (!MC_SLOT_WITHIN_BOUNDS(slot, initgr_mc_ctx.dt_size)) { + ret = ENOENT; + goto done; + } + + ret = sss_nss_mc_parse_result(rec, start, size, groups, limit); + +done: + free(rec); + __sync_sub_and_fetch(&initgr_mc_ctx.active_threads, 1); + return ret; +} |