diff options
author | Jakub Jelinek <jakub@redhat.com> | 2006-05-01 07:53:45 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2006-05-01 07:53:45 +0000 |
commit | 410005dea38c87cdd7cb265423903bf42f0a96ef (patch) | |
tree | 74342d303b7b3d860b3163ca084517be942ffde4 /nis/nss_nis | |
parent | 45f1c052dc488bb21093d52bb9a3df18e7b2df36 (diff) |
Updated to fedora-glibc-20060501T0751
Diffstat (limited to 'nis/nss_nis')
-rw-r--r-- | nis/nss_nis/nis-grp.c | 179 | ||||
-rw-r--r-- | nis/nss_nis/nis-initgroups.c | 94 | ||||
-rw-r--r-- | nis/nss_nis/nis-pwd.c | 246 | ||||
-rw-r--r-- | nis/nss_nis/nis-rpc.c | 114 | ||||
-rw-r--r-- | nis/nss_nis/nis-service.c | 133 | ||||
-rw-r--r-- | nis/nss_nis/nis-spwd.c | 2 |
6 files changed, 510 insertions, 258 deletions
diff --git a/nis/nss_nis/nis-grp.c b/nis/nss_nis/nis-grp.c index 68f3ced992..ce642c484f 100644 --- a/nis/nss_nis/nis-grp.c +++ b/nis/nss_nis/nis-grp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999, 2001-2003, 2004, 2006 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999, 2001-2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -17,20 +17,17 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -/* The following is an ugly trick to avoid a prototype declaration for - _nss_nis_endgrent. */ -#define _nss_nis_endgrent _nss_nis_endgrent_XXX -#include <grp.h> -#undef _nss_nis_endgrent #include <ctype.h> #include <errno.h> +#include <grp.h> +#include <nss.h> #include <string.h> #include <bits/libc-lock.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> #include "nss-nis.h" +#include <libnsl.h> /* Get the declaration of the parser function. */ #define ENTNAME grent @@ -44,12 +41,12 @@ __libc_lock_define_initialized (static, lock) static bool_t new_start = 1; static char *oldkey; static int oldkeylen; +static intern_t intern; -enum nss_status -_nss_nis_setgrent (int stayopen) -{ - __libc_lock_lock (lock); +static void +internal_nis_endgrent (void) +{ new_start = 1; if (oldkey != NULL) { @@ -58,21 +55,86 @@ _nss_nis_setgrent (int stayopen) oldkeylen = 0; } + struct response_t *curr = intern.next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endgrent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endgrent (); + __libc_lock_unlock (lock); return NSS_STATUS_SUCCESS; } -/* Make _nss_nis_endgrent an alias of _nss_nis_setgrent. We do this - even though the prototypes don't match. The argument of setgrent - is not used so this makes no difference. */ -strong_alias (_nss_nis_setgrent, _nss_nis_endgrent) + + +enum nss_status +internal_nis_setgrent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "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; +} + + +enum nss_status +_nss_nis_setgrent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endgrent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setgrent (); + + __libc_lock_unlock (lock); + + return result; +} + static enum nss_status internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen, int *errnop) { - char *domain; - if (__builtin_expect (yp_get_default_domain (&domain), 0)) + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; + + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* Get the next entry until we found a correct one. */ @@ -83,23 +145,62 @@ internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen, char *outkey; int len; int keylen; - int yperr; - if (new_start) - yperr = yp_first (domain, "group.byname", &outkey, &keylen, &result, - &len); - else - yperr = yp_next (domain, "group.byname", oldkey, oldkeylen, &outkey, - &keylen, &result, &len); + if (batch_read) + { + struct response_t *bucket; - if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) - { - enum nss_status retval = yperr2nss (yperr); + handle_batch_read: + bucket = intern.next; - if (retval == NSS_STATUS_TRYAGAIN) - *errnop = errno; - return retval; - } + 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; + } + + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } + else + { + int yperr; + + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setgrent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "group.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "group.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); + + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { @@ -112,7 +213,8 @@ internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen, buffer[len] = '\0'; while (isspace (*p)) ++p; - free (result); + if (!batch_read) + free (result); parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, errnop); @@ -123,10 +225,15 @@ internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen, return NSS_STATUS_TRYAGAIN; } - free (oldkey); - oldkey = outkey; - oldkeylen = keylen; - new_start = 0; + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } } while (parse_res < 1); diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c index 647adf5119..a5a3ba6144 100644 --- a/nis/nss_nis/nis-initgroups.c +++ b/nis/nss_nis/nis-initgroups.c @@ -38,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) @@ -86,16 +45,21 @@ 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) @@ -107,18 +71,46 @@ internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, 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 = strncpy (buffer, intern->next->val, buflen); - while (isspace (*p)) - ++p; + char *p; + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; + + size_t len = strlen (p) + 1; + if (__builtin_expect (len > buflen, 0)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* 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); @@ -259,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); diff --git a/nis/nss_nis/nis-pwd.c b/nis/nss_nis/nis-pwd.c index 457574a49b..7972118c84 100644 --- a/nis/nss_nis/nis-pwd.c +++ b/nis/nss_nis/nis-pwd.c @@ -17,20 +17,18 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -/* The following is an ugly trick to avoid a prototype declaration for - _nss_nis_endpwent. */ -#define _nss_nis_endpwent _nss_nis_endpwent_XXX -#include <pwd.h> -#undef _nss_nis_endpwent +#include <assert.h> #include <ctype.h> #include <errno.h> +#include <nss.h> +#include <pwd.h> #include <string.h> #include <bits/libc-lock.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> #include "nss-nis.h" +#include <libnsl.h> /* Get the declaration of the parser function. */ #define ENTNAME pwent @@ -44,12 +42,72 @@ __libc_lock_define_initialized (static, lock) static bool_t new_start = 1; static char *oldkey; static int oldkeylen; +static intern_t intern; -enum nss_status -_nss_nis_setpwent (int stayopen) + +int +_nis_saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) { - __libc_lock_lock (lock); + intern_t *intern = (intern_t *) indata; + + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response_t *bucket = intern->next; + + if (__builtin_expect (bucket == NULL, 0)) + { +#define MINSIZE 4096 - 4 * sizeof (void *) + const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1)); + bucket = malloc (sizeof (struct response_t) + minsize); + if (bucket == NULL) + /* We have no error code for out of memory. */ + return 1; + + bucket->next = NULL; + bucket->size = minsize; + intern->start = intern->next = bucket; + intern->offset = 0; + } + else if (__builtin_expect (invallen + 1 > bucket->size - intern->offset, + 0)) + { + /* We need a new (larger) buffer. */ + const size_t newsize = 2 * MAX (bucket->size, invallen + 1); + struct response_t *newp = malloc (sizeof (struct response_t) + + newsize); + if (newp == NULL) + /* We have no error code for out of memory. */ + return 1; + + /* Mark the old bucket as full. */ + bucket->size = intern->offset; + + newp->next = NULL; + newp->size = newsize; + bucket = intern->next = bucket->next = newp; + intern->offset = 0; + } + + char *p = mempcpy (&bucket->mem[intern->offset], inval, invallen); + if (__builtin_expect (p[-1] != '\0', 0)) + { + *p = '\0'; + ++invallen; + } + intern->offset += invallen; + } + + return 0; +} + +static void +internal_nis_endpwent (void) +{ new_start = 1; if (oldkey != NULL) { @@ -58,21 +116,86 @@ _nss_nis_setpwent (int stayopen) oldkeylen = 0; } + struct response_t *curr = intern.next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endpwent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endpwent (); + __libc_lock_unlock (lock); return NSS_STATUS_SUCCESS; } -/* Make _nss_nis_endpwent an alias of _nss_nis_setpwent. We do this - even though the prototypes don't match. The argument of setpwent - is not used so this makes no difference. */ -strong_alias (_nss_nis_setpwent, _nss_nis_endpwent) + + +enum nss_status +internal_nis_setpwent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "passwd.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; +} + + +enum nss_status +_nss_nis_setpwent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endpwent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setpwent (); + + __libc_lock_unlock (lock); + + return result; +} + static enum nss_status internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { - char *domain; - if (__builtin_expect (yp_get_default_domain (&domain), 0)) + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; + + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* Get the next entry until we found a correct one. */ @@ -83,23 +206,62 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, char *outkey; int len; int keylen; - int yperr; - if (new_start) - yperr = yp_first (domain, "passwd.byname", &outkey, &keylen, &result, - &len); + if (batch_read) + { + struct response_t *bucket; + + handle_batch_read: + 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; + } + + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } else - yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen, &outkey, - &keylen, &result, &len); + { + int yperr; + + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setpwent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "passwd.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); - if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) - { - enum nss_status retval = yperr2nss (yperr); + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) + { + enum nss_status retval = yperr2nss (yperr); - if (retval == NSS_STATUS_TRYAGAIN) - *errnop = errno; - return retval; - } + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } /* Check for adjunct style secret passwords. They can be recognized by a password starting with "##". */ @@ -140,10 +302,10 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, return NSS_STATUS_TRYAGAIN; } - __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen), - ":", 1), - encrypted, endp - encrypted), - p, restlen + 1); + mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); p = buffer; free (result2); @@ -158,13 +320,14 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); - buffer[len] = '\0'; + p = buffer; + *((char *) mempcpy (buffer, result, len)) = '\0'; } while (isspace (*p)) ++p; - free (result); + if (!batch_read) + free (result); parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, errnop); @@ -175,10 +338,15 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, return NSS_STATUS_TRYAGAIN; } - free (oldkey); - oldkey = outkey; - oldkeylen = keylen; - new_start = 0; + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } } while (parse_res < 1); diff --git a/nis/nss_nis/nis-rpc.c b/nis/nss_nis/nis-rpc.c index 162f3572bf..e7049ffa9f 100644 --- a/nis/nss_nis/nis-rpc.c +++ b/nis/nss_nis/nis-rpc.c @@ -36,59 +36,22 @@ __libc_lock_define_initialized (static, lock) -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 intern_t intern = {NULL, NULL}; +static intern_t intern; -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 void internal_nis_endrpcent (intern_t *intern) { - while (intern->start != NULL) + struct response_t *curr = intern->next; + + while (curr != NULL) { - intern->next = intern->start; - intern->start = intern->start->next; - free (intern->next); + struct response_t *last = curr; + curr = curr->next; + free (last); } + + intern->next = intern->start = NULL; } static enum nss_status @@ -103,10 +66,16 @@ internal_nis_setrpcent (intern_t *intern) internal_nis_endrpcent (intern); - ypcb.foreach = saveit; - ypcb.data = (char *)intern; - status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb)); + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "rpc.bynumber", &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; } @@ -139,29 +108,56 @@ _nss_nis_endrpcent (void) static enum nss_status internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, - int *errnop, intern_t *data) + int *errnop, intern_t *intern) { struct parser_data *pdata = (void *) buffer; int parse_res; char *p; - if (data->start == NULL) - internal_nis_setrpcent (data); + if (intern->start == NULL) + internal_nis_setrpcent (intern); /* Get the next entry until we found a correct one. */ do { - if (data->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; + } + + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; - p = strncpy (buffer, data->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; + } + + /* 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_rpcent (p, rpc, pdata, buflen, errnop); if (__builtin_expect (parse_res == -1, 0)) return NSS_STATUS_TRYAGAIN; - data->next = data->next->next; + + intern->offset += len; } while (!parse_res); @@ -193,7 +189,7 @@ _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc, return NSS_STATUS_UNAVAIL; } - intern_t data = { NULL, NULL }; + intern_t data = { NULL, NULL, 0 }; enum nss_status status = internal_nis_setrpcent (&data); if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0)) return status; diff --git a/nis/nss_nis/nis-service.c b/nis/nss_nis/nis-service.c index 40772ae743..cb728335f9 100644 --- a/nis/nss_nis/nis-service.c +++ b/nis/nss_nis/nis-service.c @@ -37,20 +37,7 @@ __libc_lock_define_initialized (static, lock) -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 intern_t intern = { NULL, NULL }; +static intern_t intern; struct search_t { @@ -65,35 +52,6 @@ struct search_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 int dosearch (int instatus, char *inkey, int inkeylen, char *inval, int invallen, char *indata) { @@ -152,35 +110,35 @@ dosearch (int instatus, char *inkey, int inkeylen, char *inval, return 0; } -static enum nss_status -internal_nis_endservent (intern_t * intern) +static void +internal_nis_endservent (void) { - while (intern->start != NULL) + struct response_t *curr = intern.next; + + while (curr != NULL) { - intern->next = intern->start; - intern->start = intern->start->next; - free (intern->next); + struct response_t *last = curr; + curr = curr->next; + free (last); } - return NSS_STATUS_SUCCESS; + intern.next = intern.start = NULL; } enum nss_status _nss_nis_endservent (void) { - enum nss_status status; - __libc_lock_lock (lock); - status = internal_nis_endservent (&intern); + internal_nis_endservent (); __libc_lock_unlock (lock); - return status; + return NSS_STATUS_SUCCESS; } static enum nss_status -internal_nis_setservent (intern_t *intern) +internal_nis_setservent (void) { char *domainname; struct ypall_callback ypcb; @@ -189,12 +147,18 @@ internal_nis_setservent (intern_t *intern) if (yp_get_default_domain (&domainname)) return NSS_STATUS_UNAVAIL; - (void) internal_nis_endservent (intern); + internal_nis_endservent (); - ypcb.foreach = saveit; - ypcb.data = (char *) intern; + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); - intern->next = intern->start; + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; return status; } @@ -206,7 +170,7 @@ _nss_nis_setservent (int stayopen) __libc_lock_lock (lock); - status = internal_nis_setservent (&intern); + status = internal_nis_setservent (); __libc_lock_unlock (lock); @@ -215,29 +179,56 @@ _nss_nis_setservent (int stayopen) static enum nss_status internal_nis_getservent_r (struct servent *serv, char *buffer, - size_t buflen, int *errnop, intern_t *data) + size_t buflen, int *errnop) { struct parser_data *pdata = (void *) buffer; int parse_res; char *p; - if (data->start == NULL) - internal_nis_setservent (data); + if (intern.start == NULL) + internal_nis_setservent (); - /* Get the next entry until we found a correct one. */ + /* Get the next entry until we found a correct one. */ do { - if (data->next == NULL) - return NSS_STATUS_NOTFOUND; + struct response_t *bucket = intern.next; - p = strncpy (buffer, data->next->val, buflen); - while (isspace (*p)) - ++p; + 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; + } + + for (p = &bucket->mem[intern.offset]; isspace (*p); ++p) + ++intern.offset; + + size_t len = strlen (p) + 1; + if (__builtin_expect (len > buflen, 0)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* 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_servent (p, serv, pdata, buflen, errnop); if (__builtin_expect (parse_res == -1, 0)) return NSS_STATUS_TRYAGAIN; - data->next = data->next->next; + + intern.offset += len; } while (!parse_res); @@ -252,7 +243,7 @@ _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen, __libc_lock_lock (lock); - status = internal_nis_getservent_r (serv, buffer, buflen, errnop, &intern); + status = internal_nis_getservent_r (serv, buffer, buflen, errnop); __libc_lock_unlock (lock); diff --git a/nis/nss_nis/nis-spwd.c b/nis/nss_nis/nis-spwd.c index 820bfb25e5..0fc4e17c42 100644 --- a/nis/nss_nis/nis-spwd.c +++ b/nis/nss_nis/nis-spwd.c @@ -68,8 +68,6 @@ static enum nss_status internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - char *domain; if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; |