diff options
Diffstat (limited to 'nis/nss_nis/nis-initgroups.c')
-rw-r--r-- | nis/nss_nis/nis-initgroups.c | 121 |
1 files changed, 55 insertions, 66 deletions
diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c index 33a9662..a5a3ba6 100644 --- a/nis/nss_nis/nis-initgroups.c +++ b/nis/nss_nis/nis-initgroups.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1998-2000, 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1998-2000,2002,2003,2004,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. @@ -30,6 +30,7 @@ #include <sys/param.h> #include "nss-nis.h" +#include <libnsl.h> /* Get the declaration of the parser function. */ #define ENTNAME grent @@ -37,47 +38,6 @@ #define EXTERN_PARSER #include <nss/nss_files/files-parse.c> -struct response_t -{ - struct response_t *next; - char val[0]; -}; - -struct intern_t -{ - struct response_t *start; - struct response_t *next; -}; -typedef struct intern_t intern_t; - -static int -saveit (int instatus, char *inkey, int inkeylen, char *inval, - int invallen, char *indata) -{ - intern_t *intern = (intern_t *) indata; - - if (instatus != YP_TRUE) - return 1; - - if (inkey && inkeylen > 0 && inval && invallen > 0) - { - struct response_t *newp = malloc (sizeof (struct response_t) - + invallen + 1); - if (newp == NULL) - return 1; /* We have no error code for out of memory */ - - if (intern->start == NULL) - intern->start = newp; - else - intern->next->next = newp; - intern->next = newp; - - newp->next = NULL; - *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; - } - - return 0; -} static enum nss_status internal_setgrent (char *domainname, intern_t *intern) @@ -85,41 +45,72 @@ internal_setgrent (char *domainname, intern_t *intern) struct ypall_callback ypcb; enum nss_status status; - intern->start = NULL; - - ypcb.foreach = saveit; + ypcb.foreach = _nis_saveit; ypcb.data = (char *) intern; status = yperr2nss (yp_all (domainname, "group.byname", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern->next != NULL) + intern->next->size = intern->offset; + intern->next = intern->start; + intern->offset = 0; return status; } + static enum nss_status internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, int *errnop, intern_t *intern) { - struct parser_data *data = (void *) buffer; - int parse_res; - char *p; - if (intern->start == NULL) return NSS_STATUS_NOTFOUND; /* Get the next entry until we found a correct one. */ + int parse_res; do { - if (intern->next == NULL) - return NSS_STATUS_NOTFOUND; + struct response_t *bucket = intern->next; + + if (__builtin_expect (intern->offset >= bucket->size, 0)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern->next = bucket->next; + intern->offset = 0; + } + + char *p; + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; - p = strncpy (buffer, intern->next->val, buflen); - while (isspace (*p)) - ++p; + size_t len = strlen (p) + 1; + if (__builtin_expect (len > buflen, 0)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } - parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop); - if (parse_res == -1) + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern->offset], len); + + parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res == -1, 0)) return NSS_STATUS_TRYAGAIN; - intern->next = intern->next->next; + + intern->offset += len; } while (!parse_res); @@ -166,13 +157,12 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s", (unsigned long int) uid, domainname); - enum nss_status retval; char *result; int reslen; - retval = yperr2nss (yp_match (domainname, "netid.byname", key, keylen, - &result, &reslen)); - if (retval != NSS_STATUS_SUCCESS) - return retval; + int yperr = yp_match (domainname, "netid.byname", key, keylen, &result, + &reslen); + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) + return yperr2nss (yperr); /* Parse the result: following the colon is a comma separated list of group IDs. */ @@ -207,7 +197,6 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, if (*start == *size) { /* Need a bigger buffer. */ - gid_t *newgroups; long int newsize; if (limit > 0 && *size == limit) @@ -219,7 +208,7 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, else newsize = MIN (limit, 2 * *size); - newgroups = realloc (groups, newsize * sizeof (*groups)); + gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) goto errout; *groupsp = groups = newgroups; @@ -247,7 +236,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, return NSS_STATUS_UNAVAIL; /* Check whether we are supposed to use the netid.byname map. */ - if (_nis_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) + if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) { /* We need the user ID. */ uid_t uid; @@ -262,7 +251,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); char *tmpbuf; enum nss_status status; - intern_t intern = { NULL, NULL }; + intern_t intern = { NULL, NULL, 0 }; gid_t *groups = *groupsp; status = internal_setgrent (domainname, &intern); |