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 | |
parent | 45f1c052dc488bb21093d52bb9a3df18e7b2df36 (diff) | |
download | glibc-410005dea38c87cdd7cb265423903bf42f0a96ef.tar glibc-410005dea38c87cdd7cb265423903bf42f0a96ef.tar.gz glibc-410005dea38c87cdd7cb265423903bf42f0a96ef.tar.bz2 glibc-410005dea38c87cdd7cb265423903bf42f0a96ef.zip |
Updated to fedora-glibc-20060501T0751
30 files changed, 1163 insertions, 444 deletions
@@ -1,3 +1,89 @@ +2006-04-30 Ulrich Drepper <drepper@redhat.com> + + * elf/dl-load.c (_dl_map_object_from_fd): Move state change + notification... + (lose): ...to here. + + * posix/Makefile (tests): Add tst-getaddrinfo3. + * posix/tst-getaddrinfo3.c: New file. + + * sysdeps/posix/getaddrinfo.c (gaih_inet): Add parenthesis in test + for better readability. + + * nscd/nscd.h (struct database_dyn): Change filename to an array + to avoid relocations. + + * elf/ldd.bash.in: If --verify loop fails to find a dynamic linker + for the file don't just try the first one listed in RTLDLIST + again. We already have the status. + + * nis/nss_nisplus/nisplus-publickey.c (parse_grp_str): PIDLIST is + supposed to have NGRPS elements. + + * nis/nss_nisplus/nisplus-parser.c: Minor optimizations and + cleanups. Avoid copying data if it can be used in the old place. + +2006-04-29 Ulrich Drepper <drepper@redhat.com> + + * nis/nss_nisplus/nisplus-ethers.c: Add missing null pointer check. + * nis/nss_nisplus/nisplus-hosts.c: Likewise. + * nis/nss_nisplus/nisplus-network.c: Likewise. + * nis/nss_nisplus/nisplus-proto.c: Likewise. + * nis/nss_nisplus/nisplus-rpc.c: Likewise. + * nis/nss_nisplus/nisplus-service.c: Likewise. + * nis/nss_nisplus/nisplus-spwd.c: Likewise. + + * nis/nisplus-parser.h (_nss_nisplus_parse_pwent): Add entry + parameter. + (_nss_nisplus_parse_pwent_chk): New prototype. + * nis/nss_nisplus/nisplus-parser.c (_nss_nisplus_parse_pwent): + Add entry parameter. Use it for column value in all accesses. + Move checks for well-formed reply to... + (_nss_nisplus_parse_pwent_chk): ...here. New function. + * nis/nss_nisplus/nisplus-pwd.c: Support SETENT_BATCH_READ option. + + * nis/nss_nisplus/nisplus-parser.c: Some cleanups. Remove + hidden_def definitions. + * nis/nisplus-parser.h: Add parameter names. Remove hidden_proto + definitions. + +2006-04-28 Ulrich Drepper <drepper@redhat.com> + + * nis/nss_nis/nis-spwd.c (internal_nis_getspent_r): Remove data + variable. + + * nis/nss-nis.h: Define response_t and intern_t. Declare _nis_saveit. + * nis/nss_nis/nis-pwd.c: Remove response_t and intern_t definition. + (saveit): Renamed to _nis_saveit. Take parameter which is pointer + to the intern_t object. Change all users. + * nis/nss_nis/nis-grp.c: Remove response_t, intern_t, and saveit + definition. Use _nis_saveit instead of saveit. + * nis/nss_nis/nis-service.c: Likewise. + * nis/nss_nis/nis-initgroups.c: Likewise. + (internal_setgrent): Adjust for buffer handling. + (internal_getgrent_r): Likewise. + * nis/nss_nis/nis-rpc.c: Likewise. + + * nis/nss-default.c (vars): Add SETENT_BATCH_READ. + * nis/nss: Document SETENT_BATCH_READ. + * nis/libnsl.h: Define NSS_FLAG_SETENT_BATCH_READ. + * nis/nss_nis/nis-service.c (saveit): Don't add NUL byte if the + string is already NUL terminated. + (internal_nis_endservent): No need to return anything. Change callers. + (internal_nis_setservent): One more initialization. + * nis/nss_nis/nis-pwd.c: Support SETENT_BATCH_READ option. + * nis/nss_nis/nis-grp.c: Likewise. + + * nis/nss-default.c (init): Rewrite parser to get the variables + from a table. + + * nis/nss_nis/nis-service.c: Avoid passing pointer to static + variable around. Reduce number of memory allocations by creating + list of memory pools. + + * nis/ypclnt.c (__xdr_ypresp_all): Minor optimization in string + handling. Fix typo in comment. + 2006-04-27 Ulrich Drepper <drepper@redhat.com> * nscd/connections.c (restart): If we want to switch back to the diff --git a/elf/dl-load.c b/elf/dl-load.c index 088954a04f..29fdfd8f19 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1,6 +1,5 @@ /* Map in a shared object's segments from the file. - Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -786,7 +785,7 @@ _dl_init_paths (const char *llp) static void __attribute__ ((noreturn, noinline)) lose (int code, int fd, const char *name, char *realname, struct link_map *l, - const char *msg) + const char *msg, struct r_debug *r) { /* The file might already be closed. */ if (fd != -1) @@ -805,6 +804,13 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l, free (l); } free (realname); + + if (r != NULL) + { + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + } + _dl_signal_error (code, name, NULL, msg); } @@ -840,13 +846,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp, call_lose_errno: errval = errno; call_lose: - if (make_consistent) - { - r->r_state = RT_CONSISTENT; - _dl_debug_state (); - } - - lose (errval, fd, name, realname, l, errstring); + lose (errval, fd, name, realname, l, errstring, + make_consistent ? r : NULL); } /* Look again to see if the real name matched another already loaded. */ @@ -1642,7 +1643,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader, name = strdupa (realname); free (realname); } - lose (errval, fd, name, NULL, NULL, errstring); + lose (errval, fd, name, NULL, NULL, errstring, NULL); } /* See whether the ELF header is what we expect. */ diff --git a/elf/ldd.bash.in b/elf/ldd.bash.in index a22ad15b59..d1591a5785 100644 --- a/elf/ldd.bash.in +++ b/elf/ldd.bash.in @@ -154,6 +154,7 @@ for file do test -x "$file" || echo 'ldd:' $"\ warning: you do not have execution permission for" "\`$file'" >&2 RTLD= + ret=1 for rtld in ${RTLDLIST}; do if test -x $rtld; then verify_out=`${rtld} --verify "$file"` @@ -163,12 +164,6 @@ warning: you do not have execution permission for" "\`$file'" >&2 esac fi done - if test -z "${RTLD}"; then - set ${RTLDLIST} - RTLD=$1 - verify_out=`${RTLD} --verify "$file"` - ret=$? - fi case $ret in 0) # If the program exits with exit code 5, it means the process has been diff --git a/fedora/branch.mk b/fedora/branch.mk index 60cebf722c..3c1ff4fcb9 100644 --- a/fedora/branch.mk +++ b/fedora/branch.mk @@ -3,5 +3,5 @@ glibc-branch := fedora glibc-base := HEAD DIST_BRANCH := devel COLLECTION := dist-fc4 -fedora-sync-date := 2006-04-27 21:22 UTC -fedora-sync-tag := fedora-glibc-20060427T2122 +fedora-sync-date := 2006-05-01 07:51 UTC +fedora-sync-tag := fedora-glibc-20060501T0751 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 @@ -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; diff --git a/nscd/nscd.h b/nscd/nscd.h index f826c7ada4..8b95630807 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -64,11 +64,11 @@ struct database_dyn int persistent; int shared; int propagate; - size_t max_db_size; - const char *filename; + const char filename[12]; const char *db_filename; time_t file_mtime; size_t suggested_module; + size_t max_db_size; unsigned long int postimeout; /* In seconds. */ unsigned long int negtimeout; /* In seconds. */ diff --git a/posix/Makefile b/posix/Makefile index 57f2f94d59..30ade92836 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -88,7 +88,8 @@ tests := tstgetopt testfnm runtests runptests \ tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \ tst-execve1 tst-execve2 tst-execle1 tst-execle2 \ - tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 + tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \ + tst-getaddrinfo3 xtests := bug-ga2 ifeq (yes,$(build-shared)) test-srcs := globtest diff --git a/posix/tst-getaddrinfo3.c b/posix/tst-getaddrinfo3.c new file mode 100644 index 0000000000..5077f311fc --- /dev/null +++ b/posix/tst-getaddrinfo3.c @@ -0,0 +1,151 @@ +#include <mcheck.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + + +static int +do_test (void) +{ + mtrace (); + + int result = 0; + struct addrinfo hints; + struct addrinfo *ai_res; + int s; + +#define T(no, fail, addr, fam, coraddr) \ + s = getaddrinfo (addr, NULL, &hints, &ai_res); \ + if (s != 0) \ + { \ + if (s != fail) \ + { \ + printf ("getaddrinfo test %d failed: %s\n", no, gai_strerror (s)); \ + result = 1; \ + } \ + ai_res = NULL; \ + } \ + else if (fail) \ + { \ + printf ("getaddrinfo test %d should have failed but did not\n", no); \ + result = 1; \ + } \ + else if (ai_res->ai_family != fam) \ + { \ + printf ("\ +getaddrinfo test %d return address of family %d, expected %d\n", \ + no, ai_res->ai_family, fam); \ + result = 1; \ + } \ + else if (fam == AF_INET) \ + { \ + if (ai_res->ai_addrlen != sizeof (struct sockaddr_in)) \ + { \ + printf ("getaddrinfo test %d: address size %zu, expected %zu\n", \ + no, (size_t) ai_res->ai_addrlen, \ + sizeof (struct sockaddr_in)); \ + result = 1; \ + } \ + else if (strcmp (coraddr, \ + inet_ntoa (((struct sockaddr_in *) ai_res->ai_addr)->sin_addr))\ + != 0) \ + { \ + printf ("getaddrinfo test %d: got value %s, expected %s\n", \ + no, \ + inet_ntoa (((struct sockaddr_in *) ai_res->ai_addr)->sin_addr), \ + coraddr); \ + result = 1; \ + } \ + } \ + else \ + { \ + char buf[100]; \ + \ + if (ai_res->ai_addrlen != sizeof (struct sockaddr_in6)) \ + { \ + printf ("getaddrinfo test %d: address size %zu, expected %zu\n", \ + no, (size_t) ai_res->ai_addrlen, \ + sizeof (struct sockaddr_in6)); \ + result = 1; \ + } \ + else if (strcmp (coraddr, \ + inet_ntop (AF_INET6, \ + &((struct sockaddr_in6 *) ai_res->ai_addr)->sin6_addr,\ + buf, sizeof (buf))) \ + != 0) \ + { \ + printf ("getaddrinfo test %d: got value %s, expected %s\n", \ + no, \ + inet_ntop (AF_INET6, \ + & ((struct sockaddr_in6 *) ai_res->ai_addr)->sin6_addr, \ + buf, sizeof (buf)), \ + coraddr); \ + result = 1; \ + } \ + } \ + if (ai_res != NULL && ai_res->ai_next != NULL) \ + { \ + puts ("expected only one result"); \ + result = 1; \ + } \ + freeaddrinfo (ai_res) + + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + T (1, 0, "127.0.0.1", AF_INET, "127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + T (2, 0, "127.0.0.1", AF_INET, "127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_V4MAPPED; + T (3, 0, "127.0.0.1", AF_INET6, "::ffff:127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + T (4, EAI_ADDRFAMILY, "127.0.0.1", AF_INET6, ""); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + T (5, 0, "::1", AF_INET6, "::1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + T (6, EAI_ADDRFAMILY, "::1", AF_INET6, ""); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + T (7, 0, "::1", AF_INET6, "::1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + T (8, 0, "::ffff:127.0.0.1", AF_INET6, "::ffff:127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + T (9, 0, "::ffff:127.0.0.1", AF_INET, "127.0.0.1"); + + memset (&hints, '\0', sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + T (10, 0, "::ffff:127.0.0.1", AF_INET6, "::ffff:127.0.0.1"); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index 03d26086ac..fa3bbe44cf 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -529,7 +529,7 @@ gaih_inet (const char *name, const struct gaih_service *service, { if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) at->family = AF_INET; - else if (req->ai_family == AF_INET6 && req->ai_flags & AI_V4MAPPED) + else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) { at->addr[3] = at->addr[0]; at->addr[2] = htonl (0xffff); |