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 | |
parent | 45f1c052dc488bb21093d52bb9a3df18e7b2df36 (diff) | |
download | glibc-410005dea38c87cdd7cb265423903bf42f0a96ef.tar.gz glibc-410005dea38c87cdd7cb265423903bf42f0a96ef.tar.xz glibc-410005dea38c87cdd7cb265423903bf42f0a96ef.zip |
Updated to fedora-glibc-20060501T0751
Diffstat (limited to 'nis')
-rw-r--r-- | nis/libnsl.h | 1 | ||||
-rw-r--r-- | nis/nisplus-parser.h | 23 | ||||
-rw-r--r-- | nis/nss | 12 | ||||
-rw-r--r-- | nis/nss-default.c | 41 | ||||
-rw-r--r-- | nis/nss-nis.h | 20 | ||||
-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 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-ethers.c | 10 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-hosts.c | 15 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-network.c | 13 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-parser.c | 177 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-proto.c | 11 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-publickey.c | 8 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-pwd.c | 188 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-rpc.c | 10 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-service.c | 10 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-spwd.c | 10 | ||||
-rw-r--r-- | nis/ypclnt.c | 10 |
22 files changed, 906 insertions, 421 deletions
diff --git a/nis/libnsl.h b/nis/libnsl.h index e45f24df0e..9f78469fe2 100644 --- a/nis/libnsl.h +++ b/nis/libnsl.h @@ -18,6 +18,7 @@ #define NSS_FLAG_NETID_AUTHORITATIVE 1 #define NSS_FLAG_SERVICES_AUTHORITATIVE 2 +#define NSS_FLAG_SETENT_BATCH_READ 4 /* Get current set of default flags. */ diff --git a/nis/nisplus-parser.h b/nis/nisplus-parser.h index f4b8d49596..97580d224a 100644 --- a/nis/nisplus-parser.h +++ b/nis/nisplus-parser.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1997, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -24,15 +24,16 @@ #include <grp.h> #include <shadow.h> -extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *, - char *, size_t, int *); -extern int _nss_nisplus_parse_grent (nis_result *, u_long, struct group *, - char *, size_t, int *); -extern int _nss_nisplus_parse_spent (nis_result *, struct spwd *, - char *, size_t, int *); - -libnss_nisplus_hidden_proto (_nss_nisplus_parse_pwent) -libnss_nisplus_hidden_proto (_nss_nisplus_parse_grent) -libnss_nisplus_hidden_proto (_nss_nisplus_parse_spent) +extern int _nss_nisplus_parse_pwent (nis_result *result, size_t entry, + struct passwd *pw, char *buffer, + size_t buflen, int *errnop); +extern int _nss_nisplus_parse_pwent_chk (nis_result *result, struct passwd *pw, + char *buffer, size_t buflen, + int *errnop); +extern int _nss_nisplus_parse_grent (nis_result *result, u_long entry, + struct group *gr, char *buffer, + size_t buflen, int *errnop); +extern int _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, + char *buffer, size_t buflen, int *errnop); #endif diff --git a/nis/nss b/nis/nss index 4f65f81120..aab40ab3f0 100644 --- a/nis/nss +++ b/nis/nss @@ -1,7 +1,7 @@ # /etc/default/nss # This file can theoretically contain a bunch of customization variables -# for Name Service Switch in the GNU C library. For now there are only two -# variables: +# for Name Service Switch in the GNU C library. For now there are only +# three variables: # # NETID_AUTHORITATIVE # If set to TRUE, the initgroups() function will accept the information @@ -18,3 +18,11 @@ # primary service names and service aliases. The system administrator # has to make sure it is correctly generated. #SERVICES_AUTHORITATIVE=TRUE +# +# SETENT_BATCH_READ +# If set to TRUE, various setXXent() functions will read the entire +# database at once and then hand out the requests one by one from +# memory with every getXXent() call. Otherwise each getXXent() call +# might result into a network communication with the server to get +# the next entry. +#SETENT_BATCH_READ=TRUE diff --git a/nis/nss-default.c b/nis/nss-default.c index 3287e68b86..577f7c2d47 100644 --- a/nis/nss-default.c +++ b/nis/nss-default.c @@ -35,6 +35,21 @@ static int default_nss_flags; /* Code to make sure we call 'init' once. */ __libc_once_define (static, once); +/* Table of the recognized variables. */ +static const struct +{ + char name[23]; + unsigned int len; + int flag; +} vars[] = + { +#define STRNLEN(s) s, sizeof (s) - 1 + { STRNLEN ("NETID_AUTHORITATIVE"), NSS_FLAG_NETID_AUTHORITATIVE }, + { STRNLEN ("SERVICES_AUTHORITATIVE"), NSS_FLAG_SERVICES_AUTHORITATIVE }, + { STRNLEN ("SETENT_BATCH_READ"), NSS_FLAG_SETENT_BATCH_READ } + }; +#define nvars (sizeof (vars) / sizeof (vars[0])) + static void init (void) @@ -53,11 +68,9 @@ init (void) if (n <= 0) break; - /* There currently are only two variables we expect, so - simplify the parsing. Recognize only + /* Recognize only - NETID_AUTHORITATIVE = TRUE - SERVICES_AUTHORITATIVE = TRUE + <THE-VARIABLE> = TRUE with arbitrary white spaces. */ char *cp = line; @@ -68,18 +81,14 @@ init (void) if (*cp == '#') continue; - static const char netid_authoritative[] = "NETID_AUTHORITATIVE"; - static const char services_authoritative[] - = "SERVICES_AUTHORITATIVE"; - size_t flag_len; - if (strncmp (cp, netid_authoritative, - flag_len = sizeof (netid_authoritative) - 1) != 0 - && strncmp (cp, services_authoritative, - flag_len = sizeof (services_authoritative) - 1) - != 0) + int idx; + for (idx = 0; idx < nvars; ++idx) + if (strncmp (cp, vars[idx].name, vars[idx].len) == 0) + break; + if (idx == nvars) continue; - cp += flag_len; + cp += vars[idx].len; while (isspace (*cp)) ++cp; if (*cp++ != '=') @@ -95,9 +104,7 @@ init (void) ++cp; if (*cp == '\0') - default_nss_flags |= (flag_len == sizeof (netid_authoritative) - 1 - ? NSS_FLAG_NETID_AUTHORITATIVE - : NSS_FLAG_SERVICES_AUTHORITATIVE); + default_nss_flags |= vars[idx].flag; } free (line); diff --git a/nis/nss-nis.h b/nis/nss-nis.h index cdf34c648f..5ac968e28e 100644 --- a/nis/nss-nis.h +++ b/nis/nss-nis.h @@ -36,4 +36,24 @@ yperr2nss (int errval) return __yperr2nss_tab[(unsigned int) errval]; } + +struct response_t +{ + struct response_t *next; + size_t size; + char mem[0]; +}; + +typedef struct intern_t +{ + struct response_t *start; + struct response_t *next; + size_t offset; +} intern_t; + + +extern int _nis_saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) attribute_hidden; + + #endif /* nis/nss-nis.h */ 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; diff --git a/nis/nss_nisplus/nisplus-ethers.c b/nis/nss_nisplus/nisplus-ethers.c index 2620427243..8d69ad9373 100644 --- a/nis/nss_nisplus/nisplus-ethers.c +++ b/nis/nss_nisplus/nisplus-ethers.c @@ -176,6 +176,11 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer, { saved_result = NULL; result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) return niserr2nss (result->status); } @@ -183,6 +188,11 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer, { saved_result = result; result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { nis_freeresult (saved_result); diff --git a/nis/nss_nisplus/nisplus-hosts.c b/nis/nss_nisplus/nisplus-hosts.c index 023e18f93d..f5f0ac96da 100644 --- a/nis/nss_nisplus/nisplus-hosts.c +++ b/nis/nss_nisplus/nisplus-hosts.c @@ -265,6 +265,11 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer, } result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { enum nss_status retval = niserr2nss (result->status); @@ -279,11 +284,13 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer, } else { - nis_result *res2; - saved_res = result; - res2 = nis_next_entry(tablename_val, &result->cookie); - result = res2; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { enum nss_status retval= niserr2nss (result->status); diff --git a/nis/nss_nisplus/nisplus-network.c b/nis/nss_nisplus/nisplus-network.c index 468520c937..286a4ccbdc 100644 --- a/nis/nss_nisplus/nisplus-network.c +++ b/nis/nss_nisplus/nisplus-network.c @@ -232,6 +232,11 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer, } result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { int retval = niserr2nss (result->status); @@ -249,9 +254,13 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer, } else { - nis_result *res = nis_next_entry (tablename_val, &result->cookie); saved_res = result; - result = res; + result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { int retval = niserr2nss (result->status); diff --git a/nis/nss_nisplus/nisplus-parser.c b/nis/nss_nisplus/nisplus-parser.c index e41751fff2..5ed07d86d9 100644 --- a/nis/nss_nisplus/nisplus-parser.c +++ b/nis/nss_nisplus/nisplus-parser.c @@ -25,24 +25,17 @@ #include "nisplus-parser.h" -#define NISENTRYVAL(idx,col,res) \ - (NIS_RES_OBJECT (res)[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val) +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) -#define NISENTRYLEN(idx,col,res) \ - (NIS_RES_OBJECT (res)[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len) +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) int -_nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw, - char *buffer, size_t buflen, int *errnop) +_nss_nisplus_parse_pwent_chk (nis_result *result, struct passwd *pw, + char *buffer, size_t buflen, int *errnop) { - char *first_unused = buffer; - size_t room_left = buflen; - size_t len; - - if (result == NULL) - return 0; - if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) || NIS_RES_NUMOBJ (result) != 1 || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ @@ -50,7 +43,19 @@ _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw, || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 7) return 0; - if (NISENTRYLEN (0, 0, result) >= room_left) + return _nss_nisplus_parse_pwent (result, 0, pw, buffer, buflen, errnop); +} + + +int +_nss_nisplus_parse_pwent (nis_result *result, size_t entry, struct passwd *pw, + char *buffer, size_t buflen, int *errnop) +{ + char *first_unused = buffer; + size_t room_left = buflen; + size_t len; + + if (NISENTRYLEN (entry, 0, result) >= room_left) { /* The line is too long for our buffer. */ no_more_room: @@ -58,85 +63,94 @@ _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw, return -1; } - strncpy (first_unused, NISENTRYVAL (0, 0, result), - NISENTRYLEN (0, 0, result)); - first_unused[NISENTRYLEN (0, 0, result)] = '\0'; + strncpy (first_unused, NISENTRYVAL (entry, 0, result), + NISENTRYLEN (entry, 0, result)); + first_unused[NISENTRYLEN (entry, 0, result)] = '\0'; len = strlen (first_unused); if (len == 0) /* No name ? Should never happen, database is corrupt */ return 0; pw->pw_name = first_unused; - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; - if (NISENTRYLEN (0, 1, result) >= room_left) + if (NISENTRYLEN (entry, 1, result) >= room_left) goto no_more_room; - strncpy (first_unused, NISENTRYVAL (0, 1, result), - NISENTRYLEN (0, 1, result)); - first_unused[NISENTRYLEN (0, 1, result)] = '\0'; + strncpy (first_unused, NISENTRYVAL (entry, 1, result), + NISENTRYLEN (entry, 1, result)); + first_unused[NISENTRYLEN (entry, 1, result)] = '\0'; pw->pw_passwd = first_unused; len = strlen (first_unused); - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; - if (NISENTRYLEN(0, 2, result) >= room_left) - goto no_more_room; + char *numstr = NISENTRYVAL (entry, 2, result); + len = NISENTRYLEN (entry, 2, result); + if (len == 0 && numstr[len - 1] != '\0') + { + if (len >= room_left) + goto no_more_room; - strncpy (first_unused, NISENTRYVAL (0, 2, result), - NISENTRYLEN (0, 2, result)); - first_unused[NISENTRYLEN (0, 2, result)] = '\0'; - len = strlen (first_unused); - if (len == 0) /* If we don't have a uid, it's an invalid shadow entry */ + strncpy (first_unused, numstr, len); + first_unused[len] = '\0'; + numstr = first_unused; + } + if (numstr[0] == '\0') + /* If we don't have a uid, it's an invalid shadow entry. */ return 0; - pw->pw_uid = strtoul (first_unused, NULL, 10); + pw->pw_uid = strtoul (numstr, NULL, 10); - if (NISENTRYLEN (0, 3, result) >= room_left) - goto no_more_room; + numstr = NISENTRYVAL (entry, 3, result); + len = NISENTRYLEN (entry, 3, result); + if (len == 0 && numstr[len - 1] != '\0') + { + if (len >= room_left) + goto no_more_room; - strncpy (first_unused, NISENTRYVAL (0, 3, result), - NISENTRYLEN (0, 3, result)); - first_unused[NISENTRYLEN (0, 3, result)] = '\0'; - len = strlen (first_unused); - if (len == 0) /* If we don't have a gid, it's an invalid shadow entry */ + strncpy (first_unused, numstr, len); + first_unused[len] = '\0'; + numstr = first_unused; + } + if (numstr[0] == '\0') + /* If we don't have a gid, it's an invalid shadow entry. */ return 0; - pw->pw_gid = strtoul (first_unused, NULL, 10); + pw->pw_gid = strtoul (numstr, NULL, 10); - if (NISENTRYLEN(0, 4, result) >= room_left) + if (NISENTRYLEN(entry, 4, result) >= room_left) goto no_more_room; - strncpy (first_unused, NISENTRYVAL (0, 4, result), - NISENTRYLEN (0, 4, result)); - first_unused[NISENTRYLEN (0, 4, result)] = '\0'; + strncpy (first_unused, NISENTRYVAL (entry, 4, result), + NISENTRYLEN (entry, 4, result)); + first_unused[NISENTRYLEN (entry, 4, result)] = '\0'; pw->pw_gecos = first_unused; len = strlen (first_unused); - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; - if (NISENTRYLEN (0, 5, result) >= room_left) + if (NISENTRYLEN (entry, 5, result) >= room_left) goto no_more_room; - strncpy (first_unused, NISENTRYVAL (0, 5, result), - NISENTRYLEN (0, 5, result)); - first_unused[NISENTRYLEN (0, 5, result)] = '\0'; + strncpy (first_unused, NISENTRYVAL (entry, 5, result), + NISENTRYLEN (entry, 5, result)); + first_unused[NISENTRYLEN (entry, 5, result)] = '\0'; pw->pw_dir = first_unused; len = strlen (first_unused); - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; - if (NISENTRYLEN (0, 6, result) >= room_left) + if (NISENTRYLEN (entry, 6, result) >= room_left) goto no_more_room; - strncpy (first_unused, NISENTRYVAL (0, 6, result), - NISENTRYLEN (0, 6, result)); - first_unused[NISENTRYLEN (0, 6, result)] = '\0'; + strncpy (first_unused, NISENTRYVAL (entry, 6, result), + NISENTRYLEN (entry, 6, result)); + first_unused[NISENTRYLEN (entry, 6, result)] = '\0'; pw->pw_shell = first_unused; len = strlen (first_unused); - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; return 1; } -libnss_nisplus_hidden_def (_nss_nisplus_parse_pwent) int @@ -174,8 +188,8 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, if (len == 0) /* group table is corrupt */ return 0; gr->gr_name = first_unused; - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; if (NISENTRYLEN (entry, 1, result) >= room_left) goto no_more_room; @@ -185,19 +199,24 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, first_unused[NISENTRYLEN (entry, 1, result)] = '\0'; gr->gr_passwd = first_unused; len = strlen (first_unused); - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; - if (NISENTRYLEN (entry, 2, result) >= room_left) - goto no_more_room; + char *numstr = NISENTRYVAL (entry, 2, result); + len = NISENTRYLEN (entry, 2, result); + if (len == 0 && numstr[len - 1] != '\0') + { + if (len >= room_left) + goto no_more_room; - strncpy (first_unused, NISENTRYVAL (entry, 2, result), - NISENTRYLEN (entry, 2, result)); - first_unused[NISENTRYLEN (entry, 2, result)] = '\0'; - len = strlen (first_unused); - if (len == 0) /* We should always have a gid */ + strncpy (first_unused, numstr, len); + first_unused[len] = '\0'; + numstr = first_unused; + } + if (numstr[0] == '\0') + /* We should always have a gid. */ return 0; - gr->gr_gid = strtoul (first_unused, NULL, 10); + gr->gr_gid = strtoul (numstr, NULL, 10); if (NISENTRYLEN (entry, 3, result) >= room_left) goto no_more_room; @@ -207,8 +226,8 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, first_unused[NISENTRYLEN (entry, 3, result)] = '\0'; line = first_unused; len = strlen (line); - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; /* Adjust the pointer so it is aligned for storing pointers. */ size_t adjust = ((__alignof__ (char *) @@ -255,7 +274,6 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, return 1; } -libnss_nisplus_hidden_def (_nss_nisplus_parse_grent) int @@ -291,8 +309,8 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, if (len == 0) return 0; sp->sp_namp = first_unused; - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; if (NISENTRYLEN (0, 1, result) >= room_left) goto no_more_room; @@ -302,8 +320,8 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, first_unused[NISENTRYLEN (0, 1, result)] = '\0'; sp->sp_pwdp = first_unused; len = strlen (first_unused); - room_left -= (len + 1); - first_unused += (len + 1); + room_left -= len + 1; + first_unused += len + 1; sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact = sp->sp_expire = -1; @@ -368,4 +386,3 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, return 1; } -libnss_nisplus_hidden_def (_nss_nisplus_parse_spent) diff --git a/nis/nss_nisplus/nisplus-proto.c b/nis/nss_nisplus/nisplus-proto.c index 0b96153819..42a2d088da 100644 --- a/nis/nss_nisplus/nisplus-proto.c +++ b/nis/nss_nisplus/nisplus-proto.c @@ -227,6 +227,11 @@ internal_nisplus_getprotoent_r (struct protoent *proto, char *buffer, } result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) return niserr2nss (result->status); } @@ -234,7 +239,11 @@ internal_nisplus_getprotoent_r (struct protoent *proto, char *buffer, { saved_res = result; result = nis_next_entry (tablename_val, &result->cookie); - + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { nis_freeresult (saved_res); diff --git a/nis/nss_nisplus/nisplus-publickey.c b/nis/nss_nisplus/nisplus-publickey.c index fe269b2c48..f6b32f8827 100644 --- a/nis/nss_nisplus/nisplus-publickey.c +++ b/nis/nss_nisplus/nisplus-publickey.c @@ -226,8 +226,12 @@ parse_grp_str (const char *s, gid_t *gidp, int *gidlenp, gid_t *gidlist, gidlen = 0; /* After strtoul() ep should point to the marker ',', which means - here starts a new value. */ - while (ep != NULL && *ep == ',') + here starts a new value. + + The Sun man pages show that GIDLIST should contain at least NGRPS + elements. Limiting the number written by this value is the best + we can do. */ + while (ep != NULL && *ep == ',' && gidlen < NGRPS) { ep++; s = ep; diff --git a/nis/nss_nisplus/nisplus-pwd.c b/nis/nss_nisplus/nisplus-pwd.c index 6c222ede02..7957e6a27d 100644 --- a/nis/nss_nisplus/nisplus-pwd.c +++ b/nis/nss_nisplus/nisplus-pwd.c @@ -28,10 +28,18 @@ #include "nss-nisplus.h" #include "nisplus-parser.h" +#include <libnsl.h> + __libc_lock_define_initialized (static, lock) +/* Previous result of iteration. */ static nis_result *result; + +/* All results of batch table load. */ +static nis_result *cached_results; +static size_t cached_results_iter; + nis_name pwd_tablename_val attribute_hidden; size_t pwd_tablename_len attribute_hidden; @@ -69,95 +77,195 @@ _nss_pwd_create_tablename (int *errnop) } -enum nss_status -_nss_nisplus_setpwent (int stayopen) +static void +internal_nisplus_endpwent (void) { - enum nss_status status = NSS_STATUS_SUCCESS; - - __libc_lock_lock (lock); + if (cached_results != NULL) + { + nis_freeresult (cached_results); + cached_results = NULL; + cached_results_iter = 0; + } if (result != NULL) { nis_freeresult (result); result = NULL; } +} + + +static enum nss_status +internal_nisplus_setpwent (int *errnop) +{ + enum nss_status status; + + cached_results = nis_list (pwd_tablename_val, FOLLOW_PATH | FOLLOW_LINKS, + NULL, NULL); + + if (cached_results == NULL) + { + *errnop = errno; + status = NSS_STATUS_TRYAGAIN; + } + else if (__builtin_expect ((status = niserr2nss (cached_results->status)) + != NSS_STATUS_SUCCESS, 0)) + { + nis_freeresult (cached_results); + cached_results = NULL; + } + else if (__builtin_expect (__type_of (NIS_RES_OBJECT (cached_results)) + != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (cached_results)->EN_data.en_type, + "passwd_tbl") != 0 + || NIS_RES_OBJECT (cached_results)->EN_data.en_cols.en_cols_len < 7, + 0)) + { + nis_freeresult (cached_results); + cached_results = NULL; + status = NSS_STATUS_NOTFOUND; + } + + return status; +} + + +enum nss_status +_nss_nisplus_setpwent (int stayopen) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nisplus_endpwent (); if (pwd_tablename_val == NULL) { + // XXX We need to be able to set errno. Pass in new parameter. int err; status = _nss_pwd_create_tablename (&err); } + if (status == NSS_STATUS_SUCCESS + && (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)) + { + // XXX We need to be able to set errno. Pass in new parameter. + int err; + status = internal_nisplus_setpwent (&err); + } + __libc_lock_unlock (lock); return status; } + enum nss_status _nss_nisplus_endpwent (void) { __libc_lock_lock (lock); - if (result != NULL) - { - nis_freeresult (result); - result = NULL; - } + internal_nisplus_endpwent (); __libc_lock_unlock (lock); return NSS_STATUS_SUCCESS; } + static enum nss_status internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen, int *errnop) { - int parse_res; + int parse_res = -1; + nis_result *saved_res = NULL; /* Get the next entry until we found a correct one. */ do { - nis_result *saved_res; - - if (result == NULL) + if (cached_results != NULL) { - saved_res = NULL; - if (pwd_tablename_val == NULL) - { - enum nss_status status = _nss_pwd_create_tablename (errnop); - - if (status != NSS_STATUS_SUCCESS) - return status; - } - - result = nis_first_entry (pwd_tablename_val); - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - return niserr2nss (result->status); + handle_batch_read: + /* See whether we reported the last problem. */ + if (cached_results_iter >= NIS_RES_NUMOBJ (cached_results)) + return NSS_STATUS_NOTFOUND; + + parse_res = _nss_nisplus_parse_pwent (cached_results, + cached_results_iter, pw, + buffer, buflen, errnop); } else { - saved_res = result; - result = nis_next_entry (pwd_tablename_val, &result->cookie); - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + if (result == NULL) + { + if (pwd_tablename_val == NULL) + { + enum nss_status status = _nss_pwd_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + /* Determine whether we should instead read all entries at + once. */ + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + { + enum nss_status status = internal_nisplus_setpwent (errnop); + + if (status == NSS_STATUS_SUCCESS && cached_results != NULL) + goto handle_batch_read; + } + + saved_res = NULL; + + result = nis_first_entry (pwd_tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + return niserr2nss (result->status); + } + else { - nis_freeresult (saved_res); - return niserr2nss (result->status); + saved_res = result; + result = nis_next_entry (pwd_tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + { + nis_freeresult (saved_res); + return niserr2nss (result->status); + } } + + parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer, + buflen, errnop); } - parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, - buflen, errnop); if (__builtin_expect (parse_res == -1, 0)) { - nis_freeresult (result); - result = saved_res; + if (cached_results == NULL) + { + nis_freeresult (result); + result = saved_res; + } *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - if (saved_res) - nis_freeresult (saved_res); + if (cached_results != NULL) + ++cached_results_iter; + else + if (saved_res) + { + nis_freeresult (saved_res); + saved_res = NULL; + } } while (!parse_res); @@ -223,7 +331,8 @@ _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw, return status; } - parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); + parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer, buflen, + errnop); nis_freeresult (result); @@ -282,7 +391,8 @@ _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw, return status; } - parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); + parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer, buflen, + errnop); nis_freeresult (result); diff --git a/nis/nss_nisplus/nisplus-rpc.c b/nis/nss_nisplus/nisplus-rpc.c index 1c3faa7dc0..5875bbe98d 100644 --- a/nis/nss_nisplus/nisplus-rpc.c +++ b/nis/nss_nisplus/nisplus-rpc.c @@ -229,6 +229,11 @@ internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer, } result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) return niserr2nss (result->status); } @@ -236,6 +241,11 @@ internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer, { saved_res = result; result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { nis_freeresult (saved_res); diff --git a/nis/nss_nisplus/nisplus-service.c b/nis/nss_nisplus/nisplus-service.c index 3dd9f4dde6..51c1956e2f 100644 --- a/nis/nss_nisplus/nisplus-service.c +++ b/nis/nss_nisplus/nisplus-service.c @@ -234,6 +234,11 @@ internal_nisplus_getservent_r (struct servent *serv, char *buffer, } result = nis_first_entry (tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) return niserr2nss (result->status); } @@ -241,6 +246,11 @@ internal_nisplus_getservent_r (struct servent *serv, char *buffer, { saved_res = result; result = nis_next_entry (tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { nis_freeresult (saved_res); diff --git a/nis/nss_nisplus/nisplus-spwd.c b/nis/nss_nisplus/nisplus-spwd.c index 8584300698..e63e1eeaec 100644 --- a/nis/nss_nisplus/nisplus-spwd.c +++ b/nis/nss_nisplus/nisplus-spwd.c @@ -99,6 +99,11 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen, } result = nis_first_entry (pwd_tablename_val); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) return niserr2nss (result->status); } @@ -106,6 +111,11 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen, { saved_res = result; result = nis_next_entry (pwd_tablename_val, &result->cookie); + if (result == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) { nis_freeresult (saved_res); diff --git a/nis/ypclnt.c b/nis/ypclnt.c index 65bc8d1f50..ae04ee9212 100644 --- a/nis/ypclnt.c +++ b/nis/ypclnt.c @@ -686,10 +686,10 @@ __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp) if we don't modify the length. So add an extra NUL character to avoid trouble with broken code. */ objp->status = YP_TRUE; - memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen); - key[keylen] = '\0'; - memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen); - val[vallen] = '\0'; + *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val, + keylen)) = '\0'; + *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val, + vallen)) = '\0'; xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); if ((*objp->foreach) (objp->status, key, keylen, val, vallen, objp->data)) @@ -700,7 +700,7 @@ __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp) objp->status = resp.ypresp_all_u.val.stat; xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); /* Sun says we don't need to make this call, but must return - immediatly. Since Solaris makes this call, we will call + immediately. Since Solaris makes this call, we will call the callback function, too. */ (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data); return TRUE; |