>From 5d7bddd6188efd071eaa85c0d056861cb59a81e4 Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik Date: Tue, 30 Jun 2015 16:36:03 +0200 Subject: [PATCH 5/8] sss_client: Use initgr mmap cache in client code Resolves: https://fedorahosted.org/sssd/ticket/2485 --- Makefile.am | 1 + src/sss_client/nss_group.c | 29 +++++++- src/sss_client/nss_mc.h | 5 ++ src/sss_client/nss_mc_initgr.c | 159 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/sss_client/nss_mc_initgr.c diff --git a/Makefile.am b/Makefile.am index 93a32dbdb932fe18c6d8f9361d7f97b0e05d0c17..6294a74f93a2d08f9374720a1ce9bc5f6a84f4c7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2597,6 +2597,7 @@ libnss_sss_la_SOURCES = \ src/util/murmurhash3.c \ src/sss_client/nss_mc_passwd.c \ src/sss_client/nss_mc_group.c \ + src/sss_client/nss_mc_initgr.c \ src/sss_client/nss_mc.h libnss_sss_la_LIBADD = \ $(CLIENT_LIBS) diff --git a/src/sss_client/nss_group.c b/src/sss_client/nss_group.c index 1614c33b5388326d82f1c9c1baaeee472a676cb9..b614fcf7f493345f793d3d4a28df998534ca546b 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; - rd.len = strlen(user) +1; + 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 = 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 050bd4100dec091cb096a7d97bfe6615b12654da..a39d45f143d2f2a6eb006ffc4b45fda097dad4f2 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 0000000000000000000000000000000000000000..bfb09d6550c310fbab254dc9b3ab7b306b7d3f06 --- /dev/null +++ b/src/sss_client/nss_mc_initgr.c @@ -0,0 +1,159 @@ +/* + * System Security Services Daemon. NSS client interface + * + * Authors: + * Lukas Slebodnik + * + * 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 . + */ + +/* INITGROUPs database NSS interface using mmap cache */ + +#include +#include +#include +#include +#include +#include +#include +#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; +} -- 2.4.3