From 10eae23e2483733d4ca3c21f15b5bdb3f04c9839 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 3 Jan 2012 02:46:40 -0500 Subject: sss_client: shared memory cache group map support --- src/sss_client/nss_group.c | 43 +++++++++ src/sss_client/nss_mc.h | 9 ++ src/sss_client/nss_mc_group.c | 216 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 src/sss_client/nss_mc_group.c (limited to 'src/sss_client') diff --git a/src/sss_client/nss_group.c b/src/sss_client/nss_group.c index 085a53409..1b9f3a3aa 100644 --- a/src/sss_client/nss_group.c +++ b/src/sss_client/nss_group.c @@ -29,6 +29,7 @@ #include #include #include "sss_cli.h" +#include "nss_mc.h" static struct sss_nss_getgrent_data { size_t len; @@ -365,6 +366,27 @@ enum nss_status _nss_sss_getgrnam_r(const char *name, struct group *result, return NSS_STATUS_NOTFOUND; } + ret = sss_nss_mc_getgrnam(name, name_len, result, buffer, buflen); + 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; + case EINVAL: + /* if using the mmaped cache failed, + * fall back to socket based comms */ + break; + default: + *errnop = EBADMSG; + return NSS_STATUS_TRYAGAIN; + } + rd.len = name_len + 1; rd.data = name; @@ -433,6 +455,27 @@ enum nss_status _nss_sss_getgrgid_r(gid_t gid, struct group *result, /* Caught once glibc passing in buffer == 0x0 */ if (!buffer || !buflen) return ERANGE; + ret = sss_nss_mc_getgrgid(gid, result, buffer, buflen); + 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; + case EINVAL: + /* if using the mmaped cache failed, + * fall back to socket based comms */ + break; + default: + *errnop = EBADMSG; + return NSS_STATUS_TRYAGAIN; + } + group_gid = gid; rd.len = sizeof(uint32_t); rd.data = &group_gid; diff --git a/src/sss_client/nss_mc.h b/src/sss_client/nss_mc.h index b1b929eb9..d8155b0ad 100644 --- a/src/sss_client/nss_mc.h +++ b/src/sss_client/nss_mc.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "util/mmap_cache.h" #ifndef HAVE_ERRNO_T @@ -67,4 +68,12 @@ errno_t sss_nss_mc_getpwuid(uid_t uid, struct passwd *result, char *buffer, size_t buflen); +/* group db */ +errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len, + struct group *result, + char *buffer, size_t buflen); +errno_t sss_nss_mc_getgrgid(gid_t gid, + struct group *result, + char *buffer, size_t buflen); + #endif /* _NSS_MC_H_ */ diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c new file mode 100644 index 000000000..7beeb2823 --- /dev/null +++ b/src/sss_client/nss_mc_group.c @@ -0,0 +1,216 @@ +/* + * System Security Services Daemon. NSS client interface + * + * Copyright (C) Simo Sorce 2011 + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* GROUP database NSS interface using mmap cache */ + +#include +#include +#include +#include +#include +#include +#include "nss_mc.h" + +struct sss_cli_mc_ctx gr_mc_ctx = { false, -1, 0, NULL, 0, NULL, 0, NULL, 0 }; + +static errno_t sss_nss_mc_parse_result(struct sss_mc_rec *rec, + struct group *result, + char *buffer, size_t buflen) +{ + struct sss_mc_grp_data *data; + time_t expire; + void *cookie; + char *membuf; + size_t memsize; + int ret; + int i; + + /* additional checks before filling result*/ + expire = rec->expire; + if (expire < time(NULL)) { + /* entry is now invalid */ + return EINVAL; + } + + data = (struct sss_mc_grp_data *)rec->data; + + memsize = (data->members + 1) * sizeof(char *); + if (data->strs_len + memsize > buflen) { + return ERANGE; + } + + /* fill in glibc provided structs */ + + /* copy in buffer */ + membuf = buffer + memsize; + memcpy(membuf, data->strs, data->strs_len); + + /* fill in group */ + result->gr_gid = data->gid; + result->gr_mem = (char **)buffer; + result->gr_mem[data->members] = NULL; + + cookie = NULL; + ret = sss_nss_str_ptr_from_buffer(&result->gr_name, &cookie, + membuf, data->strs_len); + if (ret) { + return ret; + } + ret = sss_nss_str_ptr_from_buffer(&result->gr_passwd, &cookie, + membuf, data->strs_len); + if (ret) { + return ret; + } + + for (i = 0; i < data->members; i++) { + ret = sss_nss_str_ptr_from_buffer(&result->gr_mem[i], &cookie, + membuf, data->strs_len); + if (ret) { + return ret; + } + } + if (cookie != NULL) { + return EINVAL; + } + + return 0; +} + +errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len, + struct group *result, + char *buffer, size_t buflen) +{ + struct sss_mc_rec *rec = NULL; + struct sss_mc_grp_data *data; + char *rec_name; + uint32_t hash; + uint32_t slot; + int ret; + + ret = sss_nss_mc_get_ctx("group", &gr_mc_ctx); + if (ret) { + return ret; + } + + /* hashes are calculated including the NULL terminator */ + hash = sss_nss_mc_hash(&gr_mc_ctx, name, name_len + 1); + slot = gr_mc_ctx.hash_table[hash]; + if (slot > MC_SIZE_TO_SLOTS(gr_mc_ctx.dt_size)) { + return ENOENT; + } + + while (slot != MC_INVALID_VAL) { + + ret = sss_nss_mc_get_record(&gr_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 = rec->next; + continue; + } + + data = (struct sss_mc_grp_data *)rec->data; + rec_name = (char *)data + data->name; + if (strcmp(name, rec_name) == 0) { + break; + } + + slot = rec->next; + } + + if (slot == MC_INVALID_VAL) { + ret = ENOENT; + goto done; + } + + ret = sss_nss_mc_parse_result(rec, result, buffer, buflen); + +done: + free(rec); + return ret; +} + +errno_t sss_nss_mc_getgrgid(gid_t gid, + struct group *result, + char *buffer, size_t buflen) +{ + struct sss_mc_rec *rec = NULL; + struct sss_mc_grp_data *data; + char gidstr[11]; + uint32_t hash; + uint32_t slot; + int len; + int ret; + + ret = sss_nss_mc_get_ctx("group", &gr_mc_ctx); + if (ret) { + return ret; + } + + len = snprintf(gidstr, 11, "%ld", (long)gid); + if (len > 10) { + return EINVAL; + } + + /* hashes are calculated including the NULL terminator */ + hash = sss_nss_mc_hash(&gr_mc_ctx, gidstr, len+1); + slot = gr_mc_ctx.hash_table[hash]; + if (slot > MC_SIZE_TO_SLOTS(gr_mc_ctx.dt_size)) { + return ENOENT; + } + + while (slot != MC_INVALID_VAL) { + + ret = sss_nss_mc_get_record(&gr_mc_ctx, slot, &rec); + if (ret) { + goto done; + } + + /* check record matches what we are searching for */ + if (hash != rec->hash2) { + /* if uid hash does not match we can skip this immediately */ + slot = rec->next; + continue; + } + + data = (struct sss_mc_grp_data *)rec->data; + if (gid == data->gid) { + break; + } + + slot = rec->next; + } + + if (slot == MC_INVALID_VAL) { + ret = ENOENT; + goto done; + } + + ret = sss_nss_mc_parse_result(rec, result, buffer, buflen); + +done: + free(rec); + return ret; +} + -- cgit