From 9f2da732e7b03825027462dd1c46f8b4d18fc1f5 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Wed, 15 Jun 2011 21:00:21 -0400 Subject: Add initgroups lookups to nss_db --- nss/Makefile | 3 +- nss/Versions | 2 + nss/db-Makefile | 14 ++++- nss/makedb.c | 63 +++++++++++++++++---- nss/nss_db/db-initgroups.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+), 14 deletions(-) create mode 100644 nss/nss_db/db-initgroups.c (limited to 'nss') diff --git a/nss/Makefile b/nss/Makefile index a925cb5bf7..f6065cc2b8 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -71,7 +71,8 @@ distribute += files-XXX.c files-parse.c libnss_db-dbs := $(addprefix db-,\ $(filter-out hosts network key alias,\ - $(databases))) + $(databases))) \ + db-initgroups libnss_db-routines := $(libnss_db-dbs) db-open hash-string generated += $(filter-out db-alias.c db-netgrp.c, \ $(addsuffix .c,$(libnss_db-dbs))) diff --git a/nss/Versions b/nss/Versions index 2f3a671af6..913751217f 100644 --- a/nss/Versions +++ b/nss/Versions @@ -151,5 +151,7 @@ libnss_db { _nss_db_endspent; _nss_db_getspent_r; _nss_db_getspnam_r; + + _nss_db_initgroups_dyn; } } diff --git a/nss/db-Makefile b/nss/db-Makefile index 649e09ced6..13259c188c 100644 --- a/nss/db-Makefile +++ b/nss/db-Makefile @@ -47,7 +47,19 @@ $(VAR_DB)/group.db: /etc/group /^[ \t]*$$/ { next } \ /^[ \t]*#/ { next } \ /^[^#]/ { printf ".%s ", $$1; print; \ - printf "=%s ", $$3; print }' $^ | \ + printf "=%s ", $$3; print; \ + if ($$4 != "") { \ + split($$4, grmems, ","); \ + for (memidx in grmems) { \ + mem=grmems[memidx]; \ + if (members[mem] == "") \ + members[mem]=$$3; \ + else \ + members[mem]=members[mem] "," $$3; \ + } \ + delete grmems; } } \ + END { for (mem in members) \ + printf ":%s $s %s\n", mem, mem, members[mem]; }' $^ | \ $(MAKEDB) -o $@ - @echo "done." diff --git a/nss/makedb.c b/nss/makedb.c index ebb6215355..8bbebc5469 100644 --- a/nss/makedb.c +++ b/nss/makedb.c @@ -53,6 +53,7 @@ struct database { char dbid; + bool extra_string; struct database *next; void *entries; size_t nentries; @@ -67,6 +68,7 @@ static size_t nhashentries_total; static size_t valstrlen; static void *valstrtree; static char *valstrtab; +static size_t extrastrlen; /* Database entry. */ struct dbentry @@ -80,6 +82,7 @@ struct dbentry struct valstrentry { stridx_t idx; + bool extra_string; char str[0]; }; @@ -112,7 +115,8 @@ static const struct argp_option options[] = N_("Do not print messages while building database") }, { "undo", 'u', NULL, 0, N_("Print content of database file, one entry a line") }, - { NULL, 0, NULL, 0, N_("Select index type") }, + { "generated", 'g', N_("CHAR"), 0, + N_("Generated line not part of iteration") }, { NULL, 0, NULL, 0, NULL } }; @@ -136,6 +140,14 @@ static struct argp argp = }; +/* List of databases which are not part of the iteration table. */ +static struct db_option +{ + char dbid; + struct db_option *next; +} *db_options; + + /* Prototypes for local functions. */ static int process_input (FILE *input, const char *inname, int to_lowercase, int be_quiet); @@ -311,6 +323,8 @@ main (int argc, char *argv[]) static error_t parse_opt (int key, char *arg, struct argp_state *state) { + struct db_option *newp; + switch (key) { case 'f': @@ -325,6 +339,12 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'u': do_undo = 1; break; + case 'g': + newp = xmalloc (sizeof (*newp)); + newp->dbid = arg[0]; + newp->next = db_options; + db_options = newp; + break; default: return ARGP_ERR_UNKNOWN; } @@ -463,11 +483,22 @@ process_input (input, inname, to_lowercase, be_quiet) { last_database = xmalloc (sizeof (*last_database)); last_database->dbid = key[0]; + last_database->extra_string = false; last_database->next = databases; last_database->entries = NULL; last_database->nentries = 0; last_database->keystrlen = 0; databases = last_database; + + struct db_option *runp = db_options; + while (runp != NULL) + if (runp->dbid == key[0]) + { + last_database->extra_string = true; + break; + } + else + runp = runp->next; } } @@ -478,7 +509,11 @@ process_input (input, inname, to_lowercase, be_quiet) /* Store the data. */ struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry) + datalen); - nentry->idx = valstrlen; + if (last_database->extra_string) + nentry->idx = extrastrlen; + else + nentry->idx = valstrlen; + nentry->extra_string = last_database->extra_string; memcpy (nentry->str, data, datalen); struct valstrentry **fdata = tsearch (nentry, &valstrtree, @@ -493,7 +528,10 @@ process_input (input, inname, to_lowercase, be_quiet) nentry = *fdata; } else - valstrlen += datalen; + if (last_database->extra_string) + extrastrlen += datalen; + else + valstrlen += datalen; /* Store the key. */ struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen); @@ -538,7 +576,7 @@ copy_valstr (const void *nodep, const VISIT which, const int depth) const struct valstrentry *p = *(const struct valstrentry **) nodep; - strcpy (valstrtab + p->idx, p->str); + strcpy (valstrtab + (p->extra_string ? valstrlen : 0) + p->idx, p->str); } @@ -576,8 +614,8 @@ next_prime (size_t seed) static void compute_tables (void) { - valstrtab = xmalloc (roundup (valstrlen, sizeof (stridx_t))); - while (valstrlen % sizeof (stridx_t) != 0) + valstrtab = xmalloc (roundup (valstrlen + extrastrlen, sizeof (stridx_t))); + while ((valstrlen + extrastrlen) % sizeof (stridx_t) != 0) valstrtab[valstrlen++] = '\0'; twalk (valstrtree, copy_valstr); @@ -590,9 +628,9 @@ compute_tables (void) elements to store in the hash table for the size. This gives enough efficiency. */ #define TEST_RANGE 30 - size_t nhashentries_min = next_prime (MAX (db->nentries, - db->nentries - * 2 - TEST_RANGE)); + size_t nhashentries_min = next_prime (db->nentries < TEST_RANGE + ? db->nentries + : db->nentries * 2 - TEST_RANGE); size_t nhashentries_max = MAX (nhashentries_min, db->nentries * 4); size_t nhashentries_best = nhashentries_min; size_t chainlength_best = db->nentries; @@ -634,7 +672,8 @@ compute_tables (void) hidx -= nhashentries; } - db->hashtable[hidx] = dbe->validx; + db->hashtable[hidx] = ((db->extra_string ? valstrlen : 0) + + dbe->validx); db->keyidxtab[hidx] = stridx; max_chainlength = MAX (max_chainlength, chainlength); @@ -702,8 +741,8 @@ write_output (int fd) iov[0].iov_len = file_offset; iov[1].iov_base = valstrtab; - iov[1].iov_len = valstrlen; - file_offset += valstrlen; + iov[1].iov_len = valstrlen + extrastrlen; + file_offset += iov[1].iov_len; size_t keydataoffset = file_offset + nhashentries_total * sizeof (stridx_t); for (struct database *db = databases; db != NULL; db = db->next) diff --git a/nss/nss_db/db-initgroups.c b/nss/nss_db/db-initgroups.c new file mode 100644 index 0000000000..aa8163b5b0 --- /dev/null +++ b/nss/nss_db/db-initgroups.c @@ -0,0 +1,138 @@ +/* Initgroups handling in nss_db module. + Copyright (C) 2011 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +#include "nss_db.h" + +/* The hashing function we use. */ +#include "../intl/hash-string.h" + + +enum nss_status +_nss_db_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + struct nss_db_map state = { NULL, 0 }; + enum nss_status status = internal_setent (_PATH_VARDB "group.db", &state); + if (status != NSS_STATUS_SUCCESS) + { + *errnop = errno; + return status; + } + + const struct nss_db_header *header = state.header; + int i; + for (i = 0; i < header->ndbs; ++i) + if (header->dbs[i].id == ':') + break; + if (i == header->ndbs) + { + status = NSS_STATUS_UNAVAIL; + goto out; + } + + const stridx_t *hashtable + = (const stridx_t *) ((const char *) header + + header->dbs[i].hashoffset); + const char *valstrtab = (const char *) header + header->valstroffset; + size_t userlen = strlen (user); + uint32_t hashval = __hash_string (user); + size_t hidx = hashval % header->dbs[i].hashsize; + size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2); + + gid_t *groups = *groupsp; + + status = NSS_STATUS_NOTFOUND; + while (hashtable[hidx] != ~((stridx_t) 0)) + { + const char *valstr = valstrtab + hashtable[hidx]; + while (isblank (*valstr)) + ++valstr; + + if (strncmp (valstr, user, userlen) == 0 && isblank (valstr[userlen])) + { + valstr += userlen + 1; + while (isblank (*valstr)) + ++valstr; + + while (*valstr != '\0') + { + errno = 0; + char *endp; + unsigned long int n = strtoul (valstr, &endp, 10); + if (*endp != ',' && *endp != '\0') + break; + valstr = *endp == '\0' ? endp : endp + 1; + + if (n != ULONG_MAX || errno != ERANGE) + { + /* Insert the group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + if (limit > 0 && *size == limit) + { + /* We reached the maximum. */ + status = NSS_STATUS_SUCCESS; + goto out; + } + + long int newsize; + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + gid_t *newgroups = realloc (groups, + newsize * sizeof (*groups)); + if (newgroups == NULL) + { + *errnop = ENOMEM; + status = NSS_STATUS_TRYAGAIN; + goto out; + } + + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = n; + *start += 1; + } + } + + status = NSS_STATUS_SUCCESS; + break; + } + + if ((hidx += hval2) >= header->dbs[i].hashsize) + hidx -= header->dbs[i].hashsize; + } + + out: + internal_endent (&state); + + return status; +} -- cgit v1.2.3