diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
commit | 0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch) | |
tree | 2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /nis/nss_nisplus | |
parent | 7d58530341304d403a6626d7f7a1913165fe2f32 (diff) | |
download | glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz |
2.5-18.1
Diffstat (limited to 'nis/nss_nisplus')
-rw-r--r-- | nis/nss_nisplus/nisplus-alias.c | 257 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-ethers.c | 251 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-grp.c | 380 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-hosts.c | 371 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-initgroups.c | 150 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-netgrp.c | 30 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-network.c | 318 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-parser.c | 252 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-proto.c | 323 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-publickey.c | 62 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-pwd.c | 388 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-rpc.c | 336 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-service.c | 341 | ||||
-rw-r--r-- | nis/nss_nisplus/nisplus-spwd.c | 151 |
14 files changed, 2102 insertions, 1508 deletions
diff --git a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c index 152e5fc3fc..57858721a1 100644 --- a/nis/nss_nisplus/nisplus-alias.c +++ b/nis/nss_nisplus/nisplus-alias.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 1998, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -17,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <atomic.h> #include <nss.h> #include <errno.h> #include <ctype.h> @@ -32,32 +34,39 @@ __libc_lock_define_initialized (static, lock) static nis_result *result; static u_long next_entry; static nis_name tablename_val; -static u_long tablename_len; +static size_t tablename_len; -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(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) static enum nss_status _nss_create_tablename (int *errnop) { if (tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "mail_aliases.org_dir."; - p = __stpcpy (buf, "mail_aliases.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; } + return NSS_STATUS_SUCCESS; } @@ -70,86 +79,87 @@ _nss_nisplus_parse_aliasent (nis_result *result, unsigned long entry, return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) - || __type_of (&result->objects.objects_val[entry]) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val[entry].EN_data.en_type, + || __type_of (&NIS_RES_OBJECT (result)[entry]) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type, "mail_aliases") != 0 - || result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 2) + || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 2) return 0; - else + + if (NISENTRYLEN (entry, 1, result) >= buflen) { - char *first_unused = buffer + NISENTRYLEN (0, 1, result) + 1; - size_t room_left = - buflen - (buflen % __alignof__ (char *)) - - NISENTRYLEN (0, 1, result) - 2; - char *line; - char *cp; - - if (NISENTRYLEN (entry, 1, result) >= buflen) - { - /* The line is too long for our buffer. */ - no_more_room: - *errnop = ERANGE; - return -1; - } - else - { - cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result), - NISENTRYLEN (entry, 1, result)); - *cp = '\0'; - } + /* The line is too long for our buffer. */ + no_more_room: + *errnop = ERANGE; + return -1; + } + + char *cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result), + NISENTRYLEN (entry, 1, result)); + *cp = '\0'; + + char *first_unused = cp + 1; + size_t room_left = buflen - (first_unused - buffer); - if (NISENTRYLEN(entry, 0, result) >= room_left) + alias->alias_local = 0; + alias->alias_members_len = 0; + + if (NISENTRYLEN (entry, 0, result) >= room_left) + goto no_more_room; + + cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result), + NISENTRYLEN (entry, 0, result)); + *cp = '\0'; + alias->alias_name = first_unused; + + /* Terminate the line for any case. */ + cp = strpbrk (alias->alias_name, "#\n"); + if (cp != NULL) + *cp = '\0'; + + size_t len = strlen (alias->alias_name) + 1; + first_unused += len; + room_left -= len; + + /* Adjust the pointer so it is aligned for + storing pointers. */ + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; + + alias->alias_members = (char **) first_unused; + + char *line = buffer; + while (*line != '\0') + { + /* Skip leading blanks. */ + while (isspace (*line)) + ++line; + + if (*line == '\0') + break; + + if (room_left < sizeof (char *)) goto no_more_room; + room_left -= sizeof (char *); + alias->alias_members[alias->alias_members_len] = line; + + while (*line != '\0' && *line != ',') + ++line; - alias->alias_local = 0; - alias->alias_members_len = 0; - *first_unused = '\0'; - ++first_unused; - cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result), - NISENTRYLEN (entry, 0, result)); - *cp = '\0'; - alias->alias_name = first_unused; - - /* Terminate the line for any case. */ - cp = strpbrk (alias->alias_name, "#\n"); - if (cp != NULL) - *cp = '\0'; - - first_unused += strlen (alias->alias_name) +1; - /* Adjust the pointer so it is aligned for - storing pointers. */ - first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); - alias->alias_members = (char **) first_unused; - - line = buffer; - - while (*line != '\0') + if (line != alias->alias_members[alias->alias_members_len]) { - /* Skip leading blanks. */ - while (isspace (*line)) - ++line; - - if (*line == '\0') - break; - - if (room_left < sizeof (char *)) - goto no_more_room; - room_left -= sizeof (char *); - alias->alias_members[alias->alias_members_len] = line; - - while (*line != '\0' && *line != ',') - ++line; - - if (line != alias->alias_members[alias->alias_members_len]) - { - *line++ = '\0'; - alias->alias_members_len++; - } + *line++ = '\0'; + ++alias->alias_members_len; } - - return alias->alias_members_len == 0 ? 0 : 1; + else if (*line == ',') + ++line; } + + return alias->alias_members_len == 0 ? 0 : 1; } static enum nss_status @@ -158,9 +168,11 @@ internal_setaliasent (void) enum nss_status status; int err; - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS) return NSS_STATUS_UNAVAIL; @@ -203,9 +215,11 @@ _nss_nisplus_endaliasent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } next_entry = 0; __libc_lock_unlock (lock); @@ -240,7 +254,8 @@ internal_nisplus_getaliasent_r (struct aliasent *alias, return NSS_STATUS_TRYAGAIN; ++next_entry; - } while (!parse_res); + } + while (!parse_res); return NSS_STATUS_SUCCESS; } @@ -268,7 +283,12 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias, if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } @@ -278,35 +298,42 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias, *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - else + + char buf[strlen (name) + 9 + tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + + if (result == NULL) { - nis_result *result; - char buf[strlen (name) + 30 + tablename_len]; - int olderr = errno; + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - sprintf (buf, "[name=%s],%s", name, tablename_val); + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + nis_freeresult (result); + return status; + } - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + parse_res = _nss_nisplus_parse_aliasent (result, 0, alias, + buffer, buflen, errnop); - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - return niserr2nss (result->status); + /* We do not need the lookup result anymore. */ + nis_freeresult (result); - parse_res = _nss_nisplus_parse_aliasent (result, 0, alias, - buffer, buflen, errnop); - if (parse_res < 1) - { - __set_errno (olderr); + if (__builtin_expect (parse_res < 1, 0)) + { + __set_errno (olderr); - if (parse_res == -1) - return NSS_STATUS_TRYAGAIN; - else - return NSS_STATUS_NOTFOUND; - } - return NSS_STATUS_SUCCESS; + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + else + return NSS_STATUS_NOTFOUND; } + + return NSS_STATUS_SUCCESS; } diff --git a/nis/nss_nisplus/nisplus-ethers.c b/nis/nss_nisplus/nisplus-ethers.c index 028309c841..298869f931 100644 --- a/nis/nss_nisplus/nisplus-ethers.c +++ b/nis/nss_nisplus/nisplus-ethers.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997,1998,2000,2001,2002,2003 Free Software Foundation, Inc. +/* Copyright (C) 1997,1998,2000-2003,2005,2006,2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -17,15 +18,17 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -#include <errno.h> +#include <atomic.h> #include <ctype.h> -#include <string.h> -#include <bits/libc-lock.h> +#include <errno.h> +#include <inttypes.h> #include <netdb.h> +#include <nss.h> +#include <string.h> #include <netinet/ether.h> -#include <rpcsvc/nis.h> #include <netinet/if_ether.h> +#include <rpcsvc/nis.h> +#include <bits/libc-lock.h> #include "nss-nisplus.h" @@ -36,11 +39,11 @@ static nis_name tablename_val; static u_long tablename_len; -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val) +#define NISENTRYVAL(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].zo_data.objdata_u.en_data.en_cols.en_cols_val[col].ec_value.ec_value_val) -#define NISENTRYLEN(idx,col,res) \ - ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len) +#define NISENTRYLEN(idx, col, res) \ + (NIS_RES_OBJECT (res)[idx].zo_data.objdata_u.en_data.en_cols.en_cols_val[col].ec_value.ec_value_len) static int _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether, @@ -53,7 +56,7 @@ _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether, return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) - || result->objects.objects_len != 1 + || NIS_RES_NUMOBJ (result) != 1 || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "ethers_tbl") != 0 @@ -61,16 +64,25 @@ _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether, return 0; /* Generate the ether entry format and use the normal parser */ - if (NISENTRYLEN (0, 0, result) +1 > room_left) + if (NISENTRYLEN (0, 0, result) + 1 > room_left) { *errnop = ERANGE; return -1; } - strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result)); - room_left -= (NISENTRYLEN (0, 0, result) +1); + char *cp = __stpncpy (p, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + *cp = '\0'; + room_left -= NISENTRYLEN (0, 0, result) + 1; ether->e_name = p; - ether->e_addr = *ether_aton (NISENTRYVAL (0, 1, result)); + struct ether_addr *ea = ether_aton (NISENTRYVAL (0, 1, result)); + if (ea == NULL) + { + *errnop = EINVAL; + return -2; + } + + ether->e_addr = *ea; return 1; } @@ -80,18 +92,24 @@ _nss_create_tablename (int *errnop) { if (tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "ethers.org_dir."; - p = __stpcpy (buf, "ethers.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; } return NSS_STATUS_SUCCESS; } @@ -107,9 +125,11 @@ _nss_nisplus_setetherent (int stayopen) __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS) status = NSS_STATUS_UNAVAIL; @@ -124,9 +144,11 @@ _nss_nisplus_endetherent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } __libc_lock_unlock (lock); @@ -137,8 +159,6 @@ static enum nss_status internal_nisplus_getetherent_r (struct etherent *ether, char *buffer, size_t buflen, int *errnop) { - int parse_res; - if (tablename_val == NULL) { enum nss_status status = _nss_create_tablename (errnop); @@ -148,6 +168,7 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer, } /* Get the next entry until we found a correct one. */ + int parse_res; do { nis_result *saved_result; @@ -156,16 +177,23 @@ 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); } else { - nis_result *res2; - - res2 = nis_next_entry(tablename_val, &result->cookie); saved_result = result; - 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) { nis_freeresult (saved_result); @@ -178,17 +206,15 @@ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer, if (parse_res == -1) { nis_freeresult (result); - *errnop = ERANGE; result = saved_result; return NSS_STATUS_TRYAGAIN; } - else - { - if (saved_result != NULL) - nis_freeresult (saved_result); - } - } while (!parse_res); + if (saved_result != NULL) + nis_freeresult (saved_result); + + } + while (!parse_res); return NSS_STATUS_SUCCESS; } @@ -212,8 +238,6 @@ enum nss_status _nss_nisplus_gethostton_r (const char *name, struct etherent *eth, char *buffer, size_t buflen, int *errnop) { - int parse_res; - if (tablename_val == NULL) { enum nss_status status = _nss_create_tablename (errnop); @@ -227,56 +251,59 @@ _nss_nisplus_gethostton_r (const char *name, struct etherent *eth, *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - else - { - nis_result *result; - char buf[strlen (name) + 40 + tablename_len]; - int olderr = errno; - sprintf (buf, "[name=%s],%s", name, tablename_val); + char buf[strlen (name) + 9 + tablename_len]; + int olderr = errno; - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); - nis_freeresult (result); - return status; - } + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); - parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, buflen, errnop); - if (parse_res < 1) - { - __set_errno (olderr); - if (parse_res == -1) - { - nis_freeresult (result); - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - return NSS_STATUS_NOTFOUND; - } - return NSS_STATUS_SUCCESS; + /* We do not need the lookup result anymore. */ + nis_freeresult (result); + + if (__builtin_expect (parse_res < 1, 0)) + { + __set_errno (olderr); + + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + + return NSS_STATUS_NOTFOUND; } + + return NSS_STATUS_SUCCESS; } enum nss_status -_nss_nisplus_getntohost_r (const struct ether_addr *addr, - struct etherent *eth, +_nss_nisplus_getntohost_r (const struct ether_addr *addr, struct etherent *eth, char *buffer, size_t buflen, int *errnop) { if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } @@ -286,44 +313,46 @@ _nss_nisplus_getntohost_r (const struct ether_addr *addr, *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - else - { - int parse_res; - nis_result *result; - char buf[255 + tablename_len]; - sprintf (buf, "[addr=%x:%x:%x:%x:%x:%x],ethers.org_dir", - addr->ether_addr_octet[0], addr->ether_addr_octet[1], - addr->ether_addr_octet[2], addr->ether_addr_octet[3], - addr->ether_addr_octet[4], addr->ether_addr_octet[5]); + char buf[26 + tablename_len]; - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + snprintf (buf, sizeof (buf), + "[addr=%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 + ":%" PRIx8 "],%s", + addr->ether_addr_octet[0], addr->ether_addr_octet[1], + addr->ether_addr_octet[2], addr->ether_addr_octet[3], + addr->ether_addr_octet[4], addr->ether_addr_octet[5], + tablename_val); - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); - nis_freeresult (result); - return status; - } + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + nis_freeresult (result); + return status; + } - parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, + int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer, buflen, errnop); - if (parse_res < 1) - { - if (parse_res == -1) - { - nis_freeresult (result); - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - return NSS_STATUS_NOTFOUND; - } - return NSS_STATUS_SUCCESS; + + /* We do not need the lookup result anymore. */ + nis_freeresult (result); + + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) + return NSS_STATUS_TRYAGAIN; + + return NSS_STATUS_NOTFOUND; } + + return NSS_STATUS_SUCCESS; } diff --git a/nis/nss_nisplus/nisplus-grp.c b/nis/nss_nisplus/nisplus-grp.c index daca94fc87..7cc762fea9 100644 --- a/nis/nss_nisplus/nisplus-grp.c +++ b/nis/nss_nisplus/nisplus-grp.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2006 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -17,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <atomic.h> #include <nss.h> #include <grp.h> #include <ctype.h> @@ -27,68 +29,110 @@ #include "nss-nisplus.h" #include "nisplus-parser.h" +#include <libnsl.h> +#include <nis_intern.h> +#include <nis_xdr.h> + __libc_lock_define_initialized (static, lock); -static nis_result *result; -static unsigned long next_entry; -static nis_name tablename_val; -static u_long tablename_len; +/* Connection information. */ +static ib_request *ibreq; +static directory_obj *dir; +static dir_binding bptr; +static char *tablepath; +static char *tableptr; +/* Cursor. */ +static netobj cursor; -static enum nss_status -_nss_create_tablename (int *errnop) + +nis_name grp_tablename_val attribute_hidden; +size_t grp_tablename_len attribute_hidden; + +enum nss_status +_nss_grp_create_tablename (int *errnop) { - if (tablename_val == NULL) + if (grp_tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "group.org_dir."; - p = __stpcpy (buf, "group.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + grp_tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + if (atomic_compare_and_exchange_bool_acq (&grp_tablename_val, p, NULL)) + { + /* Another thread already installed the value. */ + free (p); + grp_tablename_len = strlen (grp_tablename_val); + } } + return NSS_STATUS_SUCCESS; } -static enum nss_status -internal_setgrent (void) + +static void +internal_endgrent (void) { - enum nss_status status; - int err; + __nisbind_destroy (&bptr); + memset (&bptr, '\0', sizeof (bptr)); - if (result) - nis_freeresult (result); - result = NULL; - next_entry = 0; + nis_free_directory (dir); + dir = NULL; - if (tablename_val == NULL) - if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS) - return NSS_STATUS_UNAVAIL; + nis_free_request (ibreq); + ibreq = NULL; - result = nis_list (tablename_val, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); - if (result == NULL) - { - status = NSS_STATUS_TRYAGAIN; - __set_errno (ENOMEM); - } - else + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + memset (&cursor, '\0', sizeof (cursor)); + + free (tablepath); + tableptr = tablepath = NULL; +} + + +static enum nss_status +internal_setgrent (int *errnop) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (grp_tablename_val == NULL) + status = _nss_grp_create_tablename (errnop); + + if (status == NSS_STATUS_SUCCESS) { - status = niserr2nss (result->status); - if (status != NSS_STATUS_SUCCESS) + ibreq = __create_ib_request (grp_tablename_val, 0); + if (ibreq == NULL) { - nis_freeresult (result); - result = NULL; + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + nis_error retcode = __prepare_niscall (grp_tablename_val, &dir, &bptr, 0); + if (retcode != NIS_SUCCESS) + { + nis_free_request (ibreq); + ibreq = NULL; + status = niserr2nss (retcode); } } + return status; } + enum nss_status _nss_nisplus_setgrent (int stayopen) { @@ -96,58 +140,133 @@ _nss_nisplus_setgrent (int stayopen) __libc_lock_lock (lock); - status = internal_setgrent (); + internal_endgrent (); + + // XXX We need to be able to set errno. Pass in new parameter. + int err; + status = internal_setgrent (&err); __libc_lock_unlock (lock); return status; } + enum nss_status _nss_nisplus_endgrent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + internal_endgrent (); __libc_lock_unlock (lock); return NSS_STATUS_SUCCESS; } + static enum nss_status internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen, int *errnop) { - int parse_res; - - if (result == NULL) - { - enum nss_status status; - - status = internal_setgrent (); - if (result == NULL || status != NSS_STATUS_SUCCESS) - return status; - } + int parse_res = -1; + enum nss_status retval = NSS_STATUS_SUCCESS; /* Get the next entry until we found a correct one. */ do { - if (next_entry >= result->objects.objects_len) - return NSS_STATUS_NOTFOUND; + nis_error status; + nis_result result; + memset (&result, '\0', sizeof (result)); + + if (cursor.n_bytes == NULL) + { + if (ibreq == NULL) + { + retval = internal_setgrent (errnop); + if (retval != NSS_STATUS_SUCCESS) + return retval; + } + + status = __do_niscall3 (&bptr, NIS_IBFIRST, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); + } + else + { + ibreq->ibr_cookie.n_bytes = cursor.n_bytes; + ibreq->ibr_cookie.n_len = cursor.n_len; + + status = __do_niscall3 (&bptr, NIS_IBNEXT, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); + + ibreq->ibr_cookie.n_bytes = NULL; + ibreq->ibr_cookie.n_len = 0; + } + + if (status != NIS_SUCCESS) + return niserr2nss (status); - parse_res = _nss_nisplus_parse_grent (result, next_entry, gr, + if (NIS_RES_STATUS (&result) == NIS_NOTFOUND) + { + /* No more entries on this server. This means we have to go + to the next server on the path. */ + status = __follow_path (&tablepath, &tableptr, ibreq, &bptr); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + directory_obj *newdir = NULL; + dir_binding newbptr; + status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + nis_free_directory (dir); + dir = newdir; + __nisbind_destroy (&bptr); + bptr = newbptr; + + xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie); + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + parse_res = 0; + goto next; + } + else if (NIS_RES_STATUS (&result) != NIS_SUCCESS) + return niserr2nss (NIS_RES_STATUS (&result)); + + parse_res = _nss_nisplus_parse_grent (&result, gr, buffer, buflen, errnop); - if (parse_res == -1) - return NSS_STATUS_TRYAGAIN; + if (__builtin_expect (parse_res == -1, 0)) + { + *errnop = ERANGE; + retval = NSS_STATUS_TRYAGAIN; + goto freeres; + } - ++next_entry; + next: + /* Free the old cursor. */ + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + /* Remember the new one. */ + cursor.n_bytes = result.cookie.n_bytes; + cursor.n_len = result.cookie.n_len; + /* Free the result structure. NB: we do not remove the cookie. */ + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + freeres: + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result); + memset (&result, '\0', sizeof (result)); } while (!parse_res); - return NSS_STATUS_SUCCESS; + return retval; } enum nss_status @@ -171,9 +290,9 @@ _nss_nisplus_getgrnam_r (const char *name, struct group *gr, { int parse_res; - if (tablename_val == NULL) + if (grp_tablename_val == NULL) { - enum nss_status status = _nss_create_tablename (errnop); + enum nss_status status = _nss_grp_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; @@ -184,102 +303,101 @@ _nss_nisplus_getgrnam_r (const char *name, struct group *gr, *errnop = EINVAL; return NSS_STATUS_NOTFOUND; } - else + + nis_result *result; + char buf[strlen (name) + 9 + grp_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[name=%s],%s", name, grp_tablename_val); + + result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + + if (result == NULL) { - nis_result *result; - char buf[strlen (name) + 24 + tablename_len]; - int olderr = errno; + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - sprintf (buf, "[name=%s],%s", name, tablename_val); + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); - result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + nis_freeresult (result); + return status; + } - if (result == NULL) + parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop); + nis_freeresult (result); + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) { - *errnop = ENOMEM; + *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) + else { - enum nss_status status = niserr2nss (result->status); - - nis_freeresult (result); - return status; - } - - parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen, - errnop); - nis_freeresult (result); - if (parse_res < 1) - { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } - return NSS_STATUS_SUCCESS; } + + return NSS_STATUS_SUCCESS; } enum nss_status _nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr, char *buffer, size_t buflen, int *errnop) { - if (tablename_val == NULL) + if (grp_tablename_val == NULL) { - enum nss_status status = _nss_create_tablename (errnop); + enum nss_status status = _nss_grp_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } - { - int parse_res; - nis_result *result; - char buf[36 + tablename_len]; - int olderr = errno; + int parse_res; + nis_result *result; + char buf[8 + 3 * sizeof (unsigned long int) + grp_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[gid=%lu],%s", + (unsigned long int) gid, grp_tablename_val); - sprintf (buf, "[gid=%lu],%s", (unsigned long int) gid, tablename_val); + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); - __set_errno (olderr); + __set_errno (olderr); - nis_freeresult (result); - return status; - } - - parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen, - errnop); - - nis_freeresult (result); - if (parse_res < 1) - { - __set_errno (olderr); - - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - return NSS_STATUS_NOTFOUND; - } - return NSS_STATUS_SUCCESS; - } + nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop); + + nis_freeresult (result); + if (__builtin_expect (parse_res < 1, 0)) + { + __set_errno (olderr); + + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + return NSS_STATUS_NOTFOUND; + } + + return NSS_STATUS_SUCCESS; } diff --git a/nis/nss_nisplus/nisplus-hosts.c b/nis/nss_nisplus/nisplus-hosts.c index 540469894e..f5f0ac96da 100644 --- a/nis/nss_nisplus/nisplus-hosts.c +++ b/nis/nss_nisplus/nisplus-hosts.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1997-2002, 2003, 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -17,15 +17,16 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -#include <netdb.h> -#include <errno.h> +#include <atomic.h> #include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <nss.h> #include <string.h> -#include <netinet/in.h> #include <arpa/inet.h> -#include <bits/libc-lock.h> +#include <netinet/in.h> #include <rpcsvc/nis.h> +#include <bits/libc-lock.h> #include "nss-nisplus.h" @@ -35,15 +36,16 @@ static nis_result *result; static nis_name tablename_val; static u_long tablename_len; -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(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) /* Get implementation for some internal functions. */ #include <resolv/mapv4v6addr.h> + static int _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, @@ -52,27 +54,26 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, unsigned int i; char *first_unused = buffer; size_t room_left = buflen; - char *data, *p, *line; if (result == NULL) return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) || - __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ || - strcmp(result->objects.objects_val[0].EN_data.en_type, - "hosts_tbl") != 0 || - result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 4) + __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ || + strcmp(NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 || + NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4) return 0; - if (room_left < NISENTRYLEN (0, 2, result) + 1) + char *data = first_unused; + + if (room_left < (af == AF_INET6 || (flags & AI_V4MAPPED) != 0 + ? IN6ADDRSZ : INADDRSZ)) { no_more_room: *errnop = ERANGE; return -1; } - data = first_unused; - /* Parse address. */ if (af == AF_INET && inet_pton (af, NISENTRYVAL (0, 2, result), data) > 0) { @@ -98,51 +99,53 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, /* Illegal address: ignore line. */ return 0; - first_unused+=host->h_length; - room_left-=host->h_length; + first_unused += host->h_length; + room_left -= host->h_length; if (NISENTRYLEN (0, 0, result) + 1 > room_left) goto no_more_room; - p = __stpncpy (first_unused, NISENTRYVAL (0, 0, result), - NISENTRYLEN (0, 0, result)); - *p = '\0'; - room_left -= (NISENTRYLEN (0, 0, result) + 1); host->h_name = first_unused; - first_unused += NISENTRYLEN (0, 0, result) +1; - p = first_unused; - - line = p; - for (i = 0; i < result->objects.objects_len; ++i) + first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result), + NISENTRYLEN (0, 0, result)); + *first_unused++ = '\0'; + room_left -= NISENTRYLEN (0, 0, result) + 1; + + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + char *line = first_unused; + for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) { if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0) { if (NISENTRYLEN (i, 1, result) + 2 > room_left) goto no_more_room; - *p++ = ' '; - p = __stpncpy (p, NISENTRYVAL (i, 1, result), - NISENTRYLEN (i, 1, result)); - *p = '\0'; - room_left -= (NISENTRYLEN (i, 1, result) + 1); + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + *first_unused = '\0'; + room_left -= NISENTRYLEN (i, 1, result) + 1; } } - *p++ = '\0'; - first_unused = p; + *first_unused++ = '\0'; /* Adjust the pointer so it is aligned for storing pointers. */ - first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); - host->h_addr_list = (char **) first_unused; - if (room_left < 2 * sizeof (char *)) + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + 3 * sizeof (char *)) goto no_more_room; + first_unused += adjust; + room_left -= adjust; + host->h_addr_list = (char **) first_unused; - room_left -= (2 * sizeof (char *)); + room_left -= 3 * sizeof (char *); host->h_addr_list[0] = data; host->h_addr_list[1] = NULL; host->h_aliases = &host->h_addr_list[2]; - host->h_aliases[0] = NULL; i = 0; while (*line != '\0') @@ -158,41 +161,46 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host, goto no_more_room; room_left -= sizeof (char *); - host->h_aliases[i] = line; + host->h_aliases[i++] = line; while (*line != '\0' && *line != ' ') ++line; if (*line == ' ') - { - *line = '\0'; - ++line; - ++i; - } - else - host->h_aliases[i+1] = NULL; + *line++ = '\0'; } + + host->h_aliases[i] = NULL; + return 1; } + static enum nss_status _nss_create_tablename (int *errnop) { if (tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "hosts.org_dir."; - p = __stpcpy (buf, "hosts.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; } + return NSS_STATUS_SUCCESS; } @@ -204,9 +212,11 @@ _nss_nisplus_sethostent (int stayopen) __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } if (tablename_val == NULL) status = _nss_create_tablename (&err); @@ -221,9 +231,11 @@ _nss_nisplus_endhostent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } __libc_lock_unlock (lock); @@ -253,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); @@ -267,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); @@ -335,8 +354,12 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) { *herrnop = NETDB_INTERNAL; @@ -350,75 +373,81 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, *herrnop = NETDB_INTERNAL; return NSS_STATUS_NOTFOUND; } - else - { - nis_result *result; - char buf[strlen (name) + 255 + tablename_len]; - int olderr = errno; - - /* Search at first in the alias list, and use the correct name - for the next search */ - sprintf (buf, "[name=%s],%s", name, tablename_val); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - if (result != NULL) - { - /* If we do not find it, try it as original name. But if the - database is correct, we should find it in the first case, too */ - if ((result->status != NIS_SUCCESS - && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "hosts_tbl") != 0 - || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) - sprintf (buf, "[cname=%s],%s", name, tablename_val); - else - sprintf (buf, "[cname=%s],%s", NISENTRYVAL(0, 0, result), - tablename_val); + nis_result *result; + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; - nis_freeresult (result); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - } + /* Search at first in the alias list, and use the correct name + for the next search. */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - if (result == NULL) + if (result != NULL) + { + char *bufptr = buf; + + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too. */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ + || strcmp (result->objects.objects_val->EN_data.en_type, + "hosts_tbl") != 0 + || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) + snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); + else { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL(0, 0, result); + size_t buflen = strlen (entryval) + 10 + tablename_len; + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s],%s", + entryval, tablename_val); } - retval = niserr2nss (result->status); - if (retval != NSS_STATUS_SUCCESS) - { - if (retval == NSS_STATUS_TRYAGAIN) - { - *errnop = errno; - *herrnop = NETDB_INTERNAL; - } - else - __set_errno (olderr); - nis_freeresult (result); - return retval; - } - - parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer, - buflen, errnop, flags); nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + } - if (parse_res > 0) - return NSS_STATUS_SUCCESS; + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - *herrnop = NETDB_INTERNAL; - if (parse_res == -1) + retval = niserr2nss (result->status); + if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0)) + { + if (retval == NSS_STATUS_TRYAGAIN) { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; + *errnop = errno; + *herrnop = NETDB_INTERNAL; } else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + __set_errno (olderr); + nis_freeresult (result); + return retval; + } + + parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer, + buflen, errnop, flags); + + nis_freeresult (result); + + if (parse_res > 0) + return NSS_STATUS_SUCCESS; + + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; } + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } enum nss_status @@ -431,17 +460,6 @@ _nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)); } -#if 0 -enum nss_status -_nss_nisplus_getipnodebyname_r (const char *name, int af, int flags, - struct hostent *result, char *buffer, - size_t buflen, int *errnop, int *herrnop) -{ - return internal_gethostbyname2_r (name, af, result, buffer, buflen, - errnop, herrnop, flags); -} -#endif - enum nss_status _nss_nisplus_gethostbyname_r (const char *name, struct hostent *host, char *buffer, size_t buflen, int *errnop, @@ -469,62 +487,63 @@ _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, { if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } if (addr == NULL) return NSS_STATUS_NOTFOUND; - else - { - nis_result *result; - char buf[255 + tablename_len]; - int retval, parse_res; - int olderr = errno; - - sprintf (buf, "[addr=%s],%s", - inet_ntoa (*(const struct in_addr *) addr), tablename_val); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - if (result == NULL) - { - __set_errno (ENOMEM); - return NSS_STATUS_TRYAGAIN; - } - retval = niserr2nss (result->status); - if (retval != NSS_STATUS_SUCCESS) - { - if (retval == NSS_STATUS_TRYAGAIN) - { - *errnop = errno; - *herrnop = NETDB_INTERNAL; - } - else - __set_errno (olderr); - nis_freeresult (result); - return retval; - } + char buf[24 + tablename_len]; + int retval, parse_res; + int olderr = errno; - parse_res = _nss_nisplus_parse_hostent (result, af, host, - buffer, buflen, errnop, - ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)); - nis_freeresult (result); + snprintf (buf, sizeof (buf), "[addr=%s],%s", + inet_ntoa (*(const struct in_addr *) addr), tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - if (parse_res > 0) - return NSS_STATUS_SUCCESS; + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } - *herrnop = NETDB_INTERNAL; - if (parse_res == -1) + retval = niserr2nss (result->status); + if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0)) + { + if (retval == NSS_STATUS_TRYAGAIN) { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; + *errnop = errno; + *herrnop = NETDB_INTERNAL; } else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + __set_errno (olderr); + nis_freeresult (result); + return retval; } + + parse_res = _nss_nisplus_parse_hostent (result, af, host, + buffer, buflen, errnop, + ((_res.options & RES_USE_INET6) + ? AI_V4MAPPED : 0)); + nis_freeresult (result); + + if (parse_res > 0) + return NSS_STATUS_SUCCESS; + + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } diff --git a/nis/nss_nisplus/nisplus-initgroups.c b/nis/nss_nisplus/nisplus-initgroups.c new file mode 100644 index 0000000000..6588ec2533 --- /dev/null +++ b/nis/nss_nisplus/nisplus-initgroups.c @@ -0,0 +1,150 @@ +/* Copyright (C) 1997, 2001, 2002, 2003, 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 + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <atomic.h> +#include <nss.h> +#include <grp.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <bits/libc-lock.h> +#include <rpcsvc/nis.h> + +#include "nss-nisplus.h" +#include "nisplus-parser.h" +#include <libnsl.h> +#include <nis_intern.h> +#include <nis_xdr.h> + +#define NISOBJVAL(col, obj) \ + ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISOBJLEN(col, obj) \ + ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) + +extern nis_name grp_tablename_val attribute_hidden; +extern size_t grp_tablename_len attribute_hidden; +extern enum nss_status _nss_grp_create_tablename (int *errnop); + + +enum nss_status +_nss_nisplus_initgroups_dyn (const char *user, gid_t group, long int *start, + long int *size, gid_t **groupsp, long int limit, + int *errnop) +{ + if (grp_tablename_val == NULL) + { + enum nss_status status = _nss_grp_create_tablename (errnop); + + if (status != NSS_STATUS_SUCCESS) + return status; + } + + nis_result *result; + char buf[strlen (user) + 12 + grp_tablename_len]; + + snprintf (buf, sizeof (buf), "[members=%s],%s", user, grp_tablename_val); + + result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | ALL_RESULTS, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + + nis_freeresult (result); + return status; + } + + if (NIS_RES_NUMOBJ (result) == 0) + { + errout: + nis_freeresult (result); + return NSS_STATUS_NOTFOUND; + } + + gid_t *groups = *groupsp; + nis_object *obj = NIS_RES_OBJECT (result); + for (unsigned int cnt = 0; cnt < NIS_RES_NUMOBJ (result); ++cnt, ++obj) + { + if (__type_of (obj) != NIS_ENTRY_OBJ + || strcmp (obj->EN_data.en_type, "group_tbl") != 0 + || obj->EN_data.en_cols.en_cols_len < 4) + continue; + + char *numstr = NISOBJVAL (2, obj); + size_t len = NISOBJLEN (2, obj); + if (len == 0 || numstr[0] == '\0') + continue; + + gid_t gid; + char *endp; + if (__builtin_expect (numstr[len - 1] != '\0', 0)) + { + char numstrbuf[len + 1]; + memcpy (numstrbuf, numstr, len); + numstrbuf[len] = '\0'; + gid = strtoul (numstrbuf, &endp, 10); + if (*endp) + continue; + } + else + { + gid = strtoul (numstr, &endp, 10); + if (*endp) + continue; + } + + if (gid == group) + continue; + + /* Insert this group. */ + if (*start == *size) + { + /* Need a bigger buffer. */ + long int newsize; + + if (limit > 0 && *size == limit) + /* We reached the maximum. */ + break; + + if (limit <= 0) + newsize = 2 * *size; + else + newsize = MIN (limit, 2 * *size); + + gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); + if (newgroups == NULL) + goto errout; + *groupsp = groups = newgroups; + *size = newsize; + } + + groups[*start] = gid; + *start += 1; + } + + nis_freeresult (result); + return NSS_STATUS_SUCCESS; +} diff --git a/nis/nss_nisplus/nisplus-netgrp.c b/nis/nss_nisplus/nisplus-netgrp.c index 607bc2c1ca..24303b1474 100644 --- a/nis/nss_nisplus/nisplus-netgrp.c +++ b/nis/nss_nisplus/nisplus-netgrp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1997, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -27,11 +27,11 @@ #include "nss-nisplus.h" -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(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) enum nss_status _nss_nisplus_getnetgrent_r (struct __netgrent *result, char *buffer, @@ -141,29 +141,23 @@ _nss_nisplus_getnetgrent_r (struct __netgrent *result, char *buffer, static void internal_endnetgrent (struct __netgrent *netgrp) { - if (netgrp->data != NULL) - { - nis_freeresult ((nis_result *) netgrp->data); - netgrp->data = NULL; - netgrp->data_size = 0; - netgrp->position = 0; - } + nis_freeresult ((nis_result *) netgrp->data); + netgrp->data = NULL; + netgrp->data_size = 0; + netgrp->position = 0; } enum nss_status _nss_nisplus_setnetgrent (const char *group, struct __netgrent *netgrp) { - enum nss_status status; - char buf[strlen (group) + 30]; + char buf[strlen (group) + 25]; if (group == NULL || group[0] == '\0') return NSS_STATUS_UNAVAIL; - status = NSS_STATUS_SUCCESS; - - internal_endnetgrent (netgrp); + enum nss_status status = NSS_STATUS_SUCCESS; - sprintf (buf, "[name=%s],netgroup.org_dir", group); + snprintf (buf, sizeof (buf), "[name=%s],netgroup.org_dir", group); netgrp->data = (char *) nis_list (buf, EXPAND_NAME, NULL, NULL); diff --git a/nis/nss_nisplus/nisplus-network.c b/nis/nss_nisplus/nisplus-network.c index 422b02b82a..1cf652f071 100644 --- a/nis/nss_nisplus/nisplus-network.c +++ b/nis/nss_nisplus/nisplus-network.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997,1998,2000,2001,2002,2003 Free Software Foundation, Inc. +/* Copyright (C) 1997,1998,2000-2003,2005,2006,2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -17,15 +18,16 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -#include <netdb.h> -#include <errno.h> +#include <atomic.h> #include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <nss.h> #include <stdint.h> #include <string.h> #include <arpa/inet.h> -#include <bits/libc-lock.h> #include <rpcsvc/nis.h> +#include <bits/libc-lock.h> #include "nss-nisplus.h" @@ -35,33 +37,31 @@ static nis_result *result; static nis_name tablename_val; static u_long tablename_len; -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(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) static int _nss_nisplus_parse_netent (nis_result *result, struct netent *network, - char *buffer, size_t buflen, int *errnop) + char *buffer, size_t buflen, int *errnop) { char *first_unused = buffer; size_t room_left = buflen; - unsigned int i; - char *p, *line; if (result == NULL) return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val[0].EN_data.en_type, + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "networks_tbl") != 0 - || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3) + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3) return 0; - if (NISENTRYLEN(0, 0, result) >= room_left) + if (NISENTRYLEN (0, 0, result) >= room_left) { /* The line is too long for our buffer. */ no_more_room: @@ -69,50 +69,56 @@ _nss_nisplus_parse_netent (nis_result *result, struct netent *network, return -1; } - strncpy (first_unused, NISENTRYVAL(0, 0, result), + strncpy (first_unused, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result)); first_unused[NISENTRYLEN (0, 0, result)] = '\0'; network->n_name = first_unused; - room_left -= (strlen (first_unused) +1); - first_unused += strlen (first_unused) +1; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; + network->n_addrtype = 0; network->n_net = inet_network (NISENTRYVAL (0, 2, result)); - p = first_unused; - line = p; - for (i = 0; i < result->objects.objects_len; ++i) + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + char *line = first_unused; + for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i) { if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0) { if (NISENTRYLEN (i, 1, result) + 2 > room_left) goto no_more_room; - *p++ = ' '; - p = __stpncpy (p, NISENTRYVAL (i, 1, result), - NISENTRYLEN (i, 1, result)); - *p = '\0'; + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); room_left -= (NISENTRYLEN (i, 1, result) + 1); } } - *p++ = '\0'; - first_unused = p; + *first_unused++ = '\0'; /* Adjust the pointer so it is aligned for storing pointers. */ - first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); - network->n_aliases = (char **) first_unused; - if (room_left < 2 * sizeof (char *)) + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) goto no_more_room; - room_left -= (2 * sizeof (char *)); - network->n_aliases[0] = NULL; + first_unused += adjust; + room_left -= adjust; + network->n_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ + room_left -= sizeof (char *); - i = 0; + unsigned int i = 0; while (*line != '\0') { /* Skip leading blanks. */ while (isspace (*line)) - line++; + ++line; if (*line == '\0') break; @@ -121,42 +127,45 @@ _nss_nisplus_parse_netent (nis_result *result, struct netent *network, goto no_more_room; room_left -= sizeof (char *); - network->n_aliases[i] = line; + network->n_aliases[i++] = line; while (*line != '\0' && *line != ' ') ++line; if (*line == ' ') - { - *line = '\0'; - ++line; - ++i; - } - else - network->n_aliases[i+1] = NULL; + *line++ = '\0'; } + network->n_aliases[i] = NULL; return 1; } + static enum nss_status _nss_create_tablename (int *errnop) { if (tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "networks.org_dir."; - p = __stpcpy (buf, "networks.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; } + return NSS_STATUS_SUCCESS; } @@ -164,16 +173,20 @@ enum nss_status _nss_nisplus_setnetent (int stayopen) { enum nss_status status = NSS_STATUS_SUCCESS; - int err; __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } if (tablename_val == NULL) - status = _nss_create_tablename (&err); + { + int err; + status = _nss_create_tablename (&err); + } __libc_lock_unlock (lock); @@ -185,9 +198,11 @@ _nss_nisplus_endnetent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } __libc_lock_unlock (lock); @@ -218,11 +233,14 @@ 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; - - retval = niserr2nss (result->status); + int retval = niserr2nss (result->status); nis_freeresult (result); result = NULL; if (retval == NSS_STATUS_TRYAGAIN) @@ -237,16 +255,16 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer, } else { - nis_result *res; - - 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; - - retval = niserr2nss (result->status); + int retval = niserr2nss (result->status); nis_freeresult (result); result = saved_res; if (retval == NSS_STATUS_TRYAGAIN) @@ -266,7 +284,8 @@ internal_nisplus_getnetent_r (struct netent *network, char *buffer, return NSS_STATUS_TRYAGAIN; } - } while (!parse_res); + } + while (!parse_res); return NSS_STATUS_SUCCESS; } @@ -296,8 +315,12 @@ _nss_nisplus_getnetbyname_r (const char *name, struct netent *network, if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } @@ -308,76 +331,83 @@ _nss_nisplus_getnetbyname_r (const char *name, struct netent *network, *herrnop = NETDB_INTERNAL; return NSS_STATUS_UNAVAIL; } - else - { - nis_result *result; - char buf[strlen (name) + 255 + tablename_len]; - int olderr = errno; - /* Search at first in the alias list, and use the correct name - for the next search */ - sprintf (buf, "[name=%s],%s", name, tablename_val); - result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + nis_result *result; + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; - if (result != NULL) - { - /* If we do not find it, try it as original name. But if the - database is correct, we should find it in the first case, too */ - if ((result->status != NIS_SUCCESS - && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val[0].EN_data.en_type, - "networks_tbl") != 0 - || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len - < 3)) - sprintf (buf, "[cname=%s],%s", name, tablename_val); - else - sprintf (buf, "[cname=%s],%s", NISENTRYVAL (0, 0, result), - tablename_val); - - nis_freeresult (result); - result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); - } + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, NULL, NULL); - if (result == NULL) - { - __set_errno (ENOMEM); - return NSS_STATUS_TRYAGAIN; - } - retval = niserr2nss (result->status); - if (retval != NSS_STATUS_SUCCESS) + if (result != NULL) + { + char *bufptr = buf; + + /* If we do not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ + || strcmp (result->objects.objects_val[0].EN_data.en_type, + "networks_tbl") != 0 + || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len + < 3)) + snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); + else { - if (retval == NSS_STATUS_TRYAGAIN) - { - *errnop = errno; - *herrnop = NETDB_INTERNAL; - } - else - __set_errno (olderr); - nis_freeresult (result); - return retval; + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL (0, 0, result); + size_t buflen = strlen (entryval) + 10 + tablename_len; + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s],%s", + entryval, tablename_val); } - parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen, - errnop); - nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, + NULL, NULL); + } - if (parse_res > 0) - return NSS_STATUS_SUCCESS; + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } - *herrnop = NETDB_INTERNAL; - if (parse_res == -1) + retval = niserr2nss (result->status); + if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0)) + { + if (retval == NSS_STATUS_TRYAGAIN) { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; + *errnop = errno; + *herrnop = NETDB_INTERNAL; } else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + __set_errno (olderr); + nis_freeresult (result); + return retval; } + + parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res > 0) + return NSS_STATUS_SUCCESS; + + *herrnop = NETDB_INTERNAL; + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } /* XXX type is ignored, SUN's NIS+ table doesn't support it */ @@ -388,48 +418,48 @@ _nss_nisplus_getnetbyaddr_r (uint32_t addr, const int type, { if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } { - int parse_res, retval; - nis_result *result; - char buf[1024 + tablename_len]; - struct in_addr in; - char buf2[256]; - int b2len; + char buf[27 + tablename_len]; + char buf2[18]; int olderr = errno; - in = inet_makeaddr (addr, 0); + struct in_addr in = inet_makeaddr (addr, 0); strcpy (buf2, inet_ntoa (in)); - b2len = strlen (buf2); + size_t b2len = strlen (buf2); while (1) { - sprintf (buf, "[addr=%s],%s", buf2, tablename_val); - result = nis_list (buf, EXPAND_NAME, NULL, NULL); + snprintf (buf, sizeof (buf), "[addr=%s],%s", buf2, tablename_val); + nis_result *result = nis_list (buf, EXPAND_NAME | USE_DGRAM, + NULL, NULL); if (result == NULL) { __set_errno (ENOMEM); return NSS_STATUS_TRYAGAIN; } - retval = niserr2nss (result->status); - if (retval != NSS_STATUS_SUCCESS) + enum nss_status retval = niserr2nss (result->status); + if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0)) { - if (buf2[b2len -2] == '.' && buf2[b2len -1] == '0') + if (b2len > 2 && buf2[b2len - 2] == '.' && buf2[b2len - 1] == '0') { /* Try again, but with trailing dot(s) removed (one by one) */ buf2[b2len - 2] = '\0'; b2len -= 2; + nis_freeresult (result); continue; } - else - return NSS_STATUS_NOTFOUND; if (retval == NSS_STATUS_TRYAGAIN) { @@ -442,8 +472,8 @@ _nss_nisplus_getnetbyaddr_r (uint32_t addr, const int type, return retval; } - parse_res = _nss_nisplus_parse_netent (result, network, buffer, - buflen, errnop); + int parse_res = _nss_nisplus_parse_netent (result, network, buffer, + buflen, errnop); nis_freeresult (result); diff --git a/nis/nss_nisplus/nisplus-parser.c b/nis/nss_nisplus/nisplus-parser.c index b61733a628..1e1a343d52 100644 --- a/nis/nss_nisplus/nisplus-parser.c +++ b/nis/nss_nisplus/nisplus-parser.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 1999, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1999, 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. @@ -25,33 +25,36 @@ #include "nisplus-parser.h" -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(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) + +#define NISOBJVAL(col, obj) \ + ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) + +#define NISOBJLEN(col, obj) \ + ((obj)->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) { + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || NIS_RES_NUMOBJ (result) != 1 + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 7) + return 0; + + nis_object *obj = NIS_RES_OBJECT (result); 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) - || result->objects.objects_len != 1 - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "passwd_tbl") != 0 - || result->objects.objects_val->EN_data.en_cols.en_cols_len < 7) - return 0; - - if (NISENTRYLEN (0, 0, result) >= room_left) + if (NISOBJLEN (0, obj) >= room_left) { /* The line is too long for our buffer. */ no_more_room: @@ -59,111 +62,109 @@ _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, NISOBJVAL (0, obj), NISOBJLEN (0, obj)); + first_unused[NISOBJLEN (0, obj)] = '\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 (NISOBJLEN (1, obj) >= 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, NISOBJVAL (1, obj), NISOBJLEN (1, obj)); + first_unused[NISOBJLEN (1, obj)] = '\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 = NISOBJVAL (2, obj); + len = NISOBJLEN (2, obj); + 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); - room_left -= (len + 1); - first_unused += (len + 1); + pw->pw_uid = strtoul (numstr, NULL, 10); - if (NISENTRYLEN (0, 3, result) >= room_left) - goto no_more_room; + numstr = NISOBJVAL (3, obj); + len = NISOBJLEN (3, obj); + 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); - room_left -= (len + 1); - first_unused += (len + 1); + pw->pw_gid = strtoul (numstr, NULL, 10); - if (NISENTRYLEN(0, 4, result) >= room_left) + if (NISOBJLEN(4, obj) >= 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, NISOBJVAL (4, obj), NISOBJLEN (4, obj)); + first_unused[NISOBJLEN (4, obj)] = '\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 (NISOBJLEN (5, obj) >= 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, NISOBJVAL (5, obj), NISOBJLEN (5, obj)); + first_unused[NISOBJLEN (5, obj)] = '\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 (NISOBJLEN (6, obj) >= 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, NISOBJVAL (6, obj), NISOBJLEN (6, obj)); + first_unused[NISOBJLEN (6, obj)] = '\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 -_nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, +_nss_nisplus_parse_grent (nis_result *result, struct group *gr, char *buffer, size_t buflen, int *errnop) { + if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) + || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "group_tbl") != 0 + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4) + return 0; + + nis_object *obj = NIS_RES_OBJECT (result); char *first_unused = buffer; size_t room_left = buflen; char *line; int count; size_t len; - if (result == NULL) - return 0; - - if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) - || __type_of(result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val[entry].EN_data.en_type, - "group_tbl") != 0 - || result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 4) - return 0; - - if (NISENTRYLEN (entry, 0, result) >= room_left) + if (NISOBJLEN (0, obj) >= room_left) { /* The line is too long for our buffer. */ no_more_room: @@ -171,54 +172,59 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, return -1; } - strncpy (first_unused, NISENTRYVAL (entry, 0, result), - NISENTRYLEN (entry, 0, result)); - first_unused[NISENTRYLEN (entry, 0, result)] = '\0'; + strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj)); + first_unused[NISOBJLEN (0, obj)] = '\0'; len = strlen (first_unused); 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) + if (NISOBJLEN (1, obj) >= room_left) goto no_more_room; - strncpy (first_unused, NISENTRYVAL (entry, 1, result), - NISENTRYLEN (entry, 1, result)); - first_unused[NISENTRYLEN (entry, 1, result)] = '\0'; + strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj)); + first_unused[NISOBJLEN (1, obj)] = '\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 = NISOBJVAL (2, obj); + len = NISOBJLEN (2, obj); + 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 an 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); - room_left -= (strlen (first_unused) + 1); - first_unused += strlen (first_unused) + 1; + gr->gr_gid = strtoul (numstr, NULL, 10); - if (NISENTRYLEN (entry, 3, result) >= room_left) + if (NISOBJLEN (3, obj) >= room_left) goto no_more_room; - strncpy (first_unused, NISENTRYVAL (entry, 3, result), - NISENTRYLEN (entry, 3, result)); - first_unused[NISENTRYLEN (entry, 3, result)] = '\0'; + strncpy (first_unused, NISOBJVAL (3, obj), NISOBJLEN (3, obj)); + first_unused[NISOBJLEN (3, obj)] = '\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. */ - first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust) + goto no_more_room; + first_unused += adjust; + room_left -= adjust; gr->gr_mem = (char **) first_unused; count = 0; @@ -243,12 +249,10 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, { int is = isspace (*line); - *line = '\0'; + *line++ = '\0'; if (is) while (*line != '\0' && (*line == ',' || isspace (*line))) ++line; - else - ++line; } } if (room_left < sizeof (char *)) @@ -258,7 +262,7 @@ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr, return 1; } -libnss_nisplus_hidden_def (_nss_nisplus_parse_grent) + int _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, @@ -272,11 +276,10 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) - || result->objects.objects_len != 1 - || __type_of(result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "passwd_tbl") != 0 - || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 8) + || NIS_RES_NUMOBJ (result) != 1 + || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 8) return 0; if (NISENTRYLEN (0, 0, result) >= room_left) @@ -294,8 +297,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; @@ -305,8 +308,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; @@ -314,10 +317,8 @@ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, if (NISENTRYLEN (0, 7, result) > 0) { - char *line, *cp; - - line = NISENTRYVAL (0, 7, result); - cp = strchr (line, ':'); + char *line = NISENTRYVAL (0, 7, result); + char *cp = strchr (line, ':'); if (cp == NULL) return 1; *cp++ = '\0'; @@ -373,4 +374,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 83456cae64..42a2d088da 100644 --- a/nis/nss_nisplus/nisplus-proto.c +++ b/nis/nss_nisplus/nisplus-proto.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 1998, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -17,13 +18,14 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -#include <errno.h> +#include <atomic.h> #include <ctype.h> +#include <errno.h> #include <netdb.h> +#include <nss.h> #include <string.h> -#include <bits/libc-lock.h> #include <rpcsvc/nis.h> +#include <bits/libc-lock.h> #include "nss-nisplus.h" @@ -33,20 +35,20 @@ static nis_result *result; static nis_name tablename_val; static u_long tablename_len; -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len) static int -_nss_nisplus_parse_protoent (nis_result * result, struct protoent *proto, +_nss_nisplus_parse_protoent (nis_result *result, struct protoent *proto, char *buffer, size_t buflen, int *errnop) { char *first_unused = buffer; size_t room_left = buflen; unsigned int i; - char *p, *line; if (result == NULL) return 0; @@ -69,41 +71,44 @@ _nss_nisplus_parse_protoent (nis_result * result, struct protoent *proto, NISENTRYLEN (0, 0, result)); first_unused[NISENTRYLEN (0, 0, result)] = '\0'; proto->p_name = first_unused; - room_left -= (strlen (first_unused) +1); - first_unused += strlen (first_unused) +1; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; - if (NISENTRYLEN (0, 2, result) + 1 > room_left) - goto no_more_room; proto->p_proto = atoi (NISENTRYVAL (0, 2, result)); - p = first_unused; - line = p; - for (i = 0; i < result->objects.objects_len; ++i) + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + char *line = first_unused; + for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) { if (strcmp (NISENTRYVAL (i, 1, result), proto->p_name) != 0) { if (NISENTRYLEN (i, 1, result) + 2 > room_left) goto no_more_room; - *p++ = ' '; - p = __stpncpy (p, NISENTRYVAL (i, 1, result), - NISENTRYLEN (i, 1, result)); - *p = '\0'; - room_left -= (NISENTRYLEN (i, 1, result) + 1); + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + room_left -= NISENTRYLEN (i, 1, result) + 1; } } - *p++ = '\0'; - first_unused = p; + *first_unused++ = '\0'; /* Adjust the pointer so it is aligned for storing pointers. */ - first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); - proto->p_aliases = (char **) first_unused; - if (room_left < sizeof (char *)) + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) goto no_more_room; + first_unused += adjust; + room_left -= adjust; + proto->p_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ room_left -= sizeof (char *); - proto->p_aliases[0] = NULL; i = 0; while (*line != '\0') @@ -118,20 +123,15 @@ _nss_nisplus_parse_protoent (nis_result * result, struct protoent *proto, goto no_more_room; room_left -= sizeof (char *); - proto->p_aliases[i] = line; + proto->p_aliases[i++] = line; while (*line != '\0' && *line != ' ') ++line; if (*line == ' ') - { - *line = '\0'; - ++line; - ++i; - } - else - proto->p_aliases[i+1] = NULL; + *line++ = '\0'; } + proto->p_aliases[i] = NULL; return 1; } @@ -141,19 +141,26 @@ _nss_create_tablename (int *errnop) { if (tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "protocols.org_dir."; - p = __stpcpy (buf, "protocols.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; } + return NSS_STATUS_SUCCESS; } @@ -164,9 +171,11 @@ _nss_nisplus_setprotoent (int stayopen) __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } if (tablename_val == NULL) { @@ -184,9 +193,11 @@ _nss_nisplus_endprotoent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } __libc_lock_unlock (lock); @@ -216,17 +227,23 @@ 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); } else { - nis_result *res; - saved_res = result; - res = nis_next_entry (tablename_val, &result->cookie); - 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) { nis_freeresult (saved_res); @@ -277,79 +294,91 @@ _nss_nisplus_getprotobyname_r (const char *name, struct protoent *proto, if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } if (name == NULL) return NSS_STATUS_NOTFOUND; - else - { - nis_result *result; - char buf[strlen (name) + 255 + tablename_len]; - int olderr = errno; - /* Search at first in the alias list, and use the correct name - for the next search */ - sprintf (buf, "[name=%s],%s", name, tablename_val); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - - if (result != NULL) - { - /* If we do not find it, try it as original name. But if the - database is correct, we should find it in the first case, too */ - if ((result->status != NIS_SUCCESS - && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "protocols_tbl") != 0 - || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) - sprintf (buf, "[cname=%s],%s", name, tablename_val); - else - sprintf (buf, "[cname=%s],%s", NISENTRYVAL (0, 0, result), - tablename_val); + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; - nis_freeresult (result); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - } + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - if (result == NULL) + if (result != NULL) + { + char *bufptr = buf; + + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ + || strcmp (result->objects.objects_val->EN_data.en_type, + "protocols_tbl") != 0 + || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) + snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); + else { - __set_errno (ENOMEM); - return NSS_STATUS_TRYAGAIN; + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL (0, 0, result); + size_t buflen = strlen (entryval) + 10 + tablename_len; + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s],%s", + entryval, tablename_val); } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); - __set_errno (olderr); + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + } - nis_freeresult (result); - return status; - } + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } - parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen, - errnop); + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); nis_freeresult (result); + return status; + } - if (parse_res < 1) + parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } - return NSS_STATUS_SUCCESS; } + + return NSS_STATUS_SUCCESS; } enum nss_status @@ -358,55 +387,57 @@ _nss_nisplus_getprotobynumber_r (const int number, struct protoent *proto, { if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } - { - int parse_res; - nis_result *result; - char buf[46 + tablename_len]; - int olderr = errno; + char buf[12 + 3 * sizeof (number) + tablename_len]; + int olderr = errno; - sprintf (buf, "[number=%d],%s", number, tablename_val); + snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val); - result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); - if (result == NULL) - { - __set_errno (ENOMEM); - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); + if (result == NULL) + { + __set_errno (ENOMEM); + return NSS_STATUS_TRYAGAIN; + } - __set_errno (olderr); + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); - nis_freeresult (result); - return status; - } - - parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen, - errnop); - - nis_freeresult (result); - - if (parse_res < 1) - { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } - } - return NSS_STATUS_SUCCESS; - } + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; } diff --git a/nis/nss_nisplus/nisplus-publickey.c b/nis/nss_nisplus/nisplus-publickey.c index 58ae7012af..f6b32f8827 100644 --- a/nis/nss_nisplus/nisplus-publickey.c +++ b/nis/nss_nisplus/nisplus-publickey.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1999, 2001, 2003 Free Software Foundation, Inc. +/* Copyright (c) 1997,1999,2001,2003,2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -37,7 +37,7 @@ _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop) { nis_result *res; enum nss_status retval; - char buf[NIS_MAXNAMELEN+2]; + char buf[NIS_MAXNAMELEN + 2]; size_t slen; char *domain, *cptr; int len; @@ -91,20 +91,20 @@ _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop) return retval; } - if (res->objects.objects_len > 1) + if (NIS_RES_NUMOBJ (res) > 1) { /* * More than one principal with same uid? * something wrong with cred table. Should be unique * Warn user and continue. */ - printf (_("DES entry for netname %s not unique\n"), netname); + syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname); nis_freeresult (res); return NSS_STATUS_SUCCESS; } - len = ENTRY_LEN (res->objects.objects_val, 3); - memcpy (pkey, ENTRY_VAL (res->objects.objects_val,3), len); + len = ENTRY_LEN (NIS_RES_OBJECT (res), 3); + memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len); pkey[len] = 0; cptr = strchr (pkey, ':'); if (cptr) @@ -114,13 +114,14 @@ _nss_nisplus_getpublickey (const char *netname, char *pkey, int *errnop) return NSS_STATUS_SUCCESS; } + enum nss_status _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd, int *errnop) { nis_result *res; enum nss_status retval; - char buf[NIS_MAXNAMELEN+2]; + char buf[NIS_MAXNAMELEN + 2]; size_t slen; char *domain, *cptr; int len; @@ -154,7 +155,7 @@ _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd, buf[slen] = '\0'; } - res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH, + res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); if (res == NULL) @@ -172,20 +173,20 @@ _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd, return retval; } - if (res->objects.objects_len > 1) + if (NIS_RES_NUMOBJ (res) > 1) { /* * More than one principal with same uid? * something wrong with cred table. Should be unique * Warn user and continue. */ - printf (_("DES entry for netname %s not unique\n"), netname); + syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname); nis_freeresult (res); return NSS_STATUS_SUCCESS; } - len = ENTRY_LEN (res->objects.objects_val, 4); - memcpy (buf, ENTRY_VAL (res->objects.objects_val,4), len); + len = ENTRY_LEN (NIS_RES_OBJECT (res), 4); + memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len); buf[len] = '\0'; cptr = strchr (buf, ':'); if (cptr) @@ -204,6 +205,7 @@ _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd, return NSS_STATUS_SUCCESS; } + /* Parse information from the passed string. The format of the string passed is gid,grp,grp, ... */ static enum nss_status @@ -224,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; @@ -242,9 +248,9 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, { char *domain; nis_result *res; - char sname[NIS_MAXNAMELEN+2]; /* search criteria + table name */ + char sname[NIS_MAXNAMELEN + 2]; /* search criteria + table name */ size_t slen; - char principal[NIS_MAXNAMELEN+1]; + char principal[NIS_MAXNAMELEN + 1]; int len; /* 1. Get home domain of user. */ @@ -255,10 +261,6 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, ++domain; /* skip '@' */ /* 2. Get user's nisplus principal name. */ - if ((strlen (netname) + strlen (domain)+45) > - (size_t) NIS_MAXNAMELEN) - return NSS_STATUS_UNAVAIL; - slen = snprintf (sname, NIS_MAXNAMELEN, "[auth_name=%s,auth_type=DES],cred.org_dir.%s", netname, domain); @@ -309,7 +311,7 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, return NSS_STATUS_UNAVAIL; } - if (res->objects.objects_len > 1) + if (NIS_RES_NUMOBJ (res) > 1) /* * A netname belonging to more than one principal? * Something wrong with cred table. should be unique. @@ -319,8 +321,8 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, _("netname2user: DES entry for %s in directory %s not unique"), netname, domain); - len = ENTRY_LEN (res->objects.objects_val, 0); - strncpy (principal, ENTRY_VAL (res->objects.objects_val, 0), len); + len = ENTRY_LEN (NIS_RES_OBJECT (res), 0); + strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len); principal[len] = '\0'; nis_freeresult (res); @@ -332,15 +334,16 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, * LOCAL entry in **local** cred table. */ domain = nis_local_directory (); - if ((strlen (principal) + strlen (domain) + 45) > (size_t) NIS_MAXNAMELEN) + if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN) { syslog (LOG_ERR, _("netname2user: principal name `%s' too long"), principal); return NSS_STATUS_UNAVAIL; } - slen = sprintf (sname, "[cname=%s,auth_type=LOCAL],cred.org_dir.%s", - principal, domain); + slen = snprintf (sname, sizeof (sname), + "[cname=%s,auth_type=LOCAL],cred.org_dir.%s", + principal, domain); if (sname[slen - 1] != '.') { @@ -382,7 +385,7 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, return NSS_STATUS_UNAVAIL; } - if (res->objects.objects_len > 1) + if (NIS_RES_NUMOBJ (res) > 1) /* * A principal can have more than one LOCAL entry? * Something wrong with cred table. @@ -392,15 +395,16 @@ _nss_nisplus_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, _("netname2user: LOCAL entry for %s in directory %s not unique"), netname, domain); /* Fetch the uid */ - *uidp = strtoul (ENTRY_VAL (res->objects.objects_val, 2), NULL, 10); + *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10); if (*uidp == 0) { syslog (LOG_ERR, _("netname2user: should not have uid 0")); + nis_freeresult (res); return NSS_STATUS_NOTFOUND; } - parse_grp_str (ENTRY_VAL (res->objects.objects_val, 3), + parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3), gidp, gidlenp, gidlist, errnop); nis_freeresult (res); diff --git a/nis/nss_nisplus/nisplus-pwd.c b/nis/nss_nisplus/nisplus-pwd.c index 8f3bc997b3..cd33aebbcc 100644 --- a/nis/nss_nisplus/nisplus-pwd.c +++ b/nis/nss_nisplus/nisplus-pwd.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 1999, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1999, 2001, 2002, 2003, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -17,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <atomic.h> #include <nss.h> #include <errno.h> #include <pwd.h> @@ -26,126 +28,246 @@ #include "nss-nisplus.h" #include "nisplus-parser.h" +#include <libnsl.h> +#include <nis_intern.h> +#include <nis_xdr.h> + __libc_lock_define_initialized (static, lock) -static nis_result *result; -static nis_name tablename_val; -static u_long tablename_len; +/* Connection information. */ +static ib_request *ibreq; +static directory_obj *dir; +static dir_binding bptr; +static char *tablepath; +static char *tableptr; +/* Cursor. */ +static netobj cursor; -static enum nss_status -_nss_create_tablename (int *errnop) + +nis_name pwd_tablename_val attribute_hidden; +size_t pwd_tablename_len attribute_hidden; + +enum nss_status +_nss_pwd_create_tablename (int *errnop) { - if (tablename_val == NULL) + if (pwd_tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "passwd.org_dir."; - p = __stpcpy (buf, "passwd.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + pwd_tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + if (atomic_compare_and_exchange_bool_acq (&pwd_tablename_val, p, NULL)) + { + /* Another thread already installed the value. */ + free (p); + pwd_tablename_len = strlen (pwd_tablename_val); + } } + return NSS_STATUS_SUCCESS; } +static void +internal_nisplus_endpwent (void) +{ + __nisbind_destroy (&bptr); + memset (&bptr, '\0', sizeof (bptr)); + + nis_free_directory (dir); + dir = NULL; + + nis_free_request (ibreq); + ibreq = NULL; + + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + memset (&cursor, '\0', sizeof (cursor)); + + free (tablepath); + tableptr = tablepath = NULL; +} + + +static enum nss_status +internal_nisplus_setpwent (int *errnop) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (pwd_tablename_val == NULL) + status = _nss_pwd_create_tablename (errnop); + + if (status == NSS_STATUS_SUCCESS) + { + ibreq = __create_ib_request (pwd_tablename_val, 0); + if (ibreq == NULL) + { + *errnop = errno; + return NSS_STATUS_TRYAGAIN; + } + + nis_error retcode = __prepare_niscall (pwd_tablename_val, &dir, + &bptr, 0); + if (retcode != NIS_SUCCESS) + { + nis_free_request (ibreq); + ibreq = NULL; + status = niserr2nss (retcode); + } + } + + return status; +} + + enum nss_status _nss_nisplus_setpwent (int stayopen) { - enum nss_status status = NSS_STATUS_SUCCESS; - int err; + enum nss_status status; __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + internal_nisplus_endpwent (); - if (tablename_val == NULL) - status = _nss_create_tablename (&err); + // 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) - 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; + enum nss_status retval = NSS_STATUS_SUCCESS; /* Get the next entry until we found a correct one. */ do { - nis_result *saved_res; + nis_error status; + nis_result result; + memset (&result, '\0', sizeof (result)); - if (result == NULL) + if (cursor.n_bytes == NULL) { - saved_res = NULL; - if (tablename_val == NULL) + if (ibreq == NULL) { - enum nss_status status = _nss_create_tablename (errnop); - - if (status != NSS_STATUS_SUCCESS) - return status; + retval = internal_nisplus_setpwent (errnop); + if (retval != NSS_STATUS_SUCCESS) + return retval; } - result = nis_first_entry (tablename_val); - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - return niserr2nss (result->status); + status = __do_niscall3 (&bptr, NIS_IBFIRST, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); } else { - nis_result *res; + ibreq->ibr_cookie.n_bytes = cursor.n_bytes; + ibreq->ibr_cookie.n_len = cursor.n_len; + + status = __do_niscall3 (&bptr, NIS_IBNEXT, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) &result, + 0, NULL); + + ibreq->ibr_cookie.n_bytes = NULL; + ibreq->ibr_cookie.n_len = 0; + } - saved_res = result; - res = nis_next_entry (tablename_val, &result->cookie); - result = res; - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - nis_freeresult (saved_res); - return niserr2nss (result->status); - } + if (status != NIS_SUCCESS) + return niserr2nss (status); + + if (NIS_RES_STATUS (&result) == NIS_NOTFOUND) + { + /* No more entries on this server. This means we have to go + to the next server on the path. */ + status = __follow_path (&tablepath, &tableptr, ibreq, &bptr); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + directory_obj *newdir = NULL; + dir_binding newbptr; + status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0); + if (status != NIS_SUCCESS) + return niserr2nss (status); + + nis_free_directory (dir); + dir = newdir; + __nisbind_destroy (&bptr); + bptr = newbptr; + + xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie); + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + parse_res = 0; + goto next; } + else if (NIS_RES_STATUS (&result) != NIS_SUCCESS) + return niserr2nss (NIS_RES_STATUS (&result)); - parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, + parse_res = _nss_nisplus_parse_pwent (&result, pw, buffer, buflen, errnop); - if (parse_res == -1) + + if (__builtin_expect (parse_res == -1, 0)) { - nis_freeresult (result); - result = saved_res; *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; + retval = NSS_STATUS_TRYAGAIN; + goto freeres; } - else - { - if (saved_res) - nis_freeresult (saved_res); - } - } while (!parse_res); - return NSS_STATUS_SUCCESS; + next: + /* Free the old cursor. */ + xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); + /* Remember the new one. */ + cursor.n_bytes = result.cookie.n_bytes; + cursor.n_len = result.cookie.n_len; + /* Free the result structure. NB: we do not remove the cookie. */ + result.cookie.n_bytes = NULL; + result.cookie.n_len = 0; + freeres: + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result); + memset (&result, '\0', sizeof (result)); + } + while (!parse_res); + + return retval; } enum nss_status @@ -169,9 +291,9 @@ _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw, { int parse_res; - if (tablename_val == NULL) + if (pwd_tablename_val == NULL) { - enum nss_status status = _nss_create_tablename (errnop); + enum nss_status status = _nss_pwd_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; @@ -182,107 +304,107 @@ _nss_nisplus_getpwnam_r (const char *name, struct passwd *pw, *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - else - { - nis_result *result; - char buf[strlen (name) + 24 + tablename_len]; - int olderr = errno; - sprintf (buf, "[name=%s],%s", name, tablename_val); + nis_result *result; + char buf[strlen (name) + 9 + pwd_tablename_len]; + int olderr = errno; - result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val); - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); - __set_errno (olderr); + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - nis_freeresult (result); - return status; - } + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); - parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, - errnop); + __set_errno (olderr); nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); - if (parse_res < 1) + nis_freeresult (result); + + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } - return NSS_STATUS_SUCCESS; } + + return NSS_STATUS_SUCCESS; } enum nss_status _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw, char *buffer, size_t buflen, int *errnop) { - if (tablename_val == NULL) + if (pwd_tablename_val == NULL) { - enum nss_status status = _nss_create_tablename (errnop); + enum nss_status status = _nss_pwd_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } - { - int parse_res; - nis_result *result; - char buf[100 + tablename_len]; - int olderr = errno; + int parse_res; + nis_result *result; + char buf[8 + 3 * sizeof (unsigned long int) + pwd_tablename_len]; + int olderr = errno; + + snprintf (buf, sizeof (buf), "[uid=%lu],%s", + (unsigned long int) uid, pwd_tablename_val); + + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); + + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); - sprintf (buf, "[uid=%lu],%s", (unsigned long int) uid, tablename_val); + __set_errno (olderr); - result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + nis_freeresult (result); + return status; + } - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); + parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); - __set_errno (olderr); + nis_freeresult (result); - nis_freeresult (result); - return status; - } - - parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop); - - nis_freeresult (result); - - if (parse_res < 1) - { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } - } - return NSS_STATUS_SUCCESS; - } + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; } diff --git a/nis/nss_nisplus/nisplus-rpc.c b/nis/nss_nisplus/nisplus-rpc.c index 31d48d17a3..711c6bc273 100644 --- a/nis/nss_nisplus/nisplus-rpc.c +++ b/nis/nss_nisplus/nisplus-rpc.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 1998, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -17,13 +18,14 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -#include <errno.h> +#include <atomic.h> #include <ctype.h> +#include <errno.h> +#include <nss.h> #include <string.h> -#include <bits/libc-lock.h> #include <rpc/netdb.h> #include <rpcsvc/nis.h> +#include <bits/libc-lock.h> #include "nss-nisplus.h" @@ -33,11 +35,12 @@ static nis_result *result; static nis_name tablename_val; static u_long tablename_len; -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len) static int _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc, @@ -46,17 +49,16 @@ _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc, char *first_unused = buffer; size_t room_left = buflen; unsigned int i; - char *p, *line; + char *line; if (result == NULL) return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val[0].EN_data.en_type, - "rpc_tbl") != 0 - || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "rpc_tbl") != 0 + || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3) return 0; if (NISENTRYLEN (0, 0, result) >= room_left) @@ -69,37 +71,43 @@ _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc, NISENTRYLEN (0, 0, result)); first_unused[NISENTRYLEN (0, 0, result)] = '\0'; rpc->r_name = first_unused; - room_left -= (strlen (first_unused) + 1); - first_unused += strlen (first_unused) + 1; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; + rpc->r_number = atoi (NISENTRYVAL (0, 2, result)); - p = first_unused; - line = p; - for (i = 0; i < result->objects.objects_len; ++i) + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + line = first_unused; + for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) { if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0) { if (NISENTRYLEN (i, 1, result) + 2 > room_left) goto no_more_room; - *p++ = ' '; - p = __stpncpy (p, NISENTRYVAL (i, 1, result), - NISENTRYLEN (i, 1, result)); - *p = '\0'; - room_left -= (NISENTRYLEN (i, 1, result) + 1); + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + room_left -= NISENTRYLEN (i, 1, result) + 1; } } - ++p; - first_unused = p; + *first_unused++ = '\0'; /* Adjust the pointer so it is aligned for storing pointers. */ - first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); - rpc->r_aliases = (char **) first_unused; - if (room_left < sizeof (char *)) + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) goto no_more_room; + first_unused += adjust; + room_left -= adjust; + rpc->r_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ room_left -= sizeof (char *); - rpc->r_aliases[0] = NULL; i = 0; while (*line != '\0') @@ -115,42 +123,45 @@ _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc, goto no_more_room; room_left -= sizeof (char *); - rpc->r_aliases[i] = line; + rpc->r_aliases[i++] = line; while (*line != '\0' && *line != ' ') ++line; if (*line == ' ') - { - *line = '\0'; - ++line; - ++i; - } - else - rpc->r_aliases[i+1] = NULL; + *line++ = '\0'; } + rpc->r_aliases[i] = NULL; return 1; } + static enum nss_status _nss_create_tablename (int *errnop) { if (tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "rpc.org_dir."; - p = __stpcpy (buf, "rpc.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; } + return NSS_STATUS_SUCCESS; } @@ -159,16 +170,20 @@ enum nss_status _nss_nisplus_setrpcent (int stayopen) { enum nss_status status = NSS_STATUS_SUCCESS; - int err; __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } if (tablename_val == NULL) - status = _nss_create_tablename (&err); + { + int err; + status = _nss_create_tablename (&err); + } __libc_lock_unlock (lock); @@ -180,9 +195,11 @@ _nss_nisplus_endrpcent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } __libc_lock_unlock (lock); @@ -212,16 +229,23 @@ 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); } else { - nis_result *res; - saved_res = result; - res = nis_next_entry (tablename_val, &result->cookie); - 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) { nis_freeresult (saved_res); @@ -243,7 +267,8 @@ internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer, if (saved_res) nis_freeresult (saved_res); } - } while (!parse_res); + } + while (!parse_res); return NSS_STATUS_SUCCESS; } @@ -271,77 +296,91 @@ _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc, if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } if (name == NULL) return NSS_STATUS_NOTFOUND; - else - { - nis_result *result; - char buf[strlen (name) + 255 + tablename_len]; - int olderr = errno; - /* Search at first in the alias list, and use the correct name - for the next search */ - sprintf (buf, "[name=%s],%s", name, tablename_val); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + char buf[strlen (name) + 10 + tablename_len]; + int olderr = errno; - if (result != NULL) - { - /* If we do not find it, try it as original name. But if the - database is correct, we should find it in the first case, too */ - if ((result->status != NIS_SUCCESS - && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "rpc_tbl") != 0 - || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) - sprintf (buf, "[cname=%s],%s", name, tablename_val); - else - sprintf (buf, "[cname=%s],%s", NISENTRYVAL (0, 0, result), - tablename_val); - - nis_freeresult (result); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL); - } + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); - if (result == NULL) + if (result != NULL) + { + char *bufptr = buf; + + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ + || strcmp (result->objects.objects_val->EN_data.en_type, + "rpc_tbl") != 0 + || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) + snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); + else { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL (0, 0, result); + size_t buflen = strlen (entryval) + 10 + tablename_len; + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s],%s", + entryval, tablename_val); } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); - __set_errno (olderr); + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + } - nis_freeresult (result); - return status; - } + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, - errnop); + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); nis_freeresult (result); + return status; + } - if (parse_res < 1) - { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } + parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, + errnop); - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; } - return NSS_STATUS_SUCCESS; + + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } + + return NSS_STATUS_SUCCESS; } enum nss_status @@ -350,55 +389,58 @@ _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc, { if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } - { - int parse_res; - nis_result *result; - char buf[100 + tablename_len]; - int olderr = errno; + char buf[12 + 3 * sizeof (number) + tablename_len]; + int olderr = errno; - sprintf (buf, "[number=%d],%s", number, tablename_val); + snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val); - result = nis_list(buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); + nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, + NULL, NULL); - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - __set_errno (olderr); + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); - nis_freeresult (result); - return status; - } - - parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, - errnop); - - nis_freeresult (result); - - if (parse_res < 1) - { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } - } - return NSS_STATUS_SUCCESS; - } + __set_errno (olderr); + + nis_freeresult (result); + return status; + } + + int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, + errnop); + + nis_freeresult (result); + + if (parse_res < 1) + { + if (parse_res == -1) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; + } + } + + return NSS_STATUS_SUCCESS; } diff --git a/nis/nss_nisplus/nisplus-service.c b/nis/nss_nisplus/nisplus-service.c index fbb6987e9e..607ce80b01 100644 --- a/nis/nss_nisplus/nisplus-service.c +++ b/nis/nss_nisplus/nisplus-service.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997,1998,1999,2001,2002,2003 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998, 1999, 2001, 2002, 2003, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -17,13 +18,14 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -#include <errno.h> +#include <atomic.h> #include <ctype.h> +#include <errno.h> #include <netdb.h> +#include <nss.h> #include <string.h> -#include <bits/libc-lock.h> #include <rpcsvc/nis.h> +#include <bits/libc-lock.h> #include "nss-nisplus.h" @@ -33,11 +35,12 @@ static nis_result *result; static nis_name tablename_val; static u_long tablename_len; -#define NISENTRYVAL(idx,col,res) \ - ((res)->objects.objects_val[(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) \ - ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len) static int _nss_nisplus_parse_servent (nis_result *result, struct servent *serv, @@ -45,17 +48,14 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv, { char *first_unused = buffer; size_t room_left = buflen; - unsigned int i; - char *p, *line; if (result == NULL) return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "services_tbl") != 0 - || result->objects.objects_val->EN_data.en_cols.en_cols_len < 4) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "services_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4) return 0; if (NISENTRYLEN (0, 0, result) >= room_left) @@ -68,8 +68,9 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv, NISENTRYLEN (0, 0, result)); first_unused[NISENTRYLEN (0, 0, result)] = '\0'; serv->s_name = first_unused; - room_left -= (strlen (first_unused) +1); - first_unused += strlen (first_unused) +1; + size_t len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; if (NISENTRYLEN (0, 2, result) >= room_left) goto no_more_room; @@ -77,40 +78,45 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv, NISENTRYLEN (0, 2, result)); first_unused[NISENTRYLEN (0, 2, result)] = '\0'; serv->s_proto = first_unused; - room_left -= strlen (first_unused) + 1; - first_unused += strlen (first_unused) + 1; + len = strlen (first_unused) + 1; + room_left -= len; + first_unused += len; serv->s_port = htons (atoi (NISENTRYVAL (0, 3, result))); - p = first_unused; - line = p; - for (i = 0; i < result->objects.objects_len; ++i) + /* XXX Rewrite at some point to allocate the array first and then + copy the strings. It wasteful to first concatenate the strings + to just split them again later. */ + char *line = first_unused; + for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i) { if (strcmp (NISENTRYVAL (i, 1, result), serv->s_name) != 0) { if (NISENTRYLEN (i, 1, result) + 2 > room_left) goto no_more_room; - *p++ = ' '; - p = __stpncpy (p, NISENTRYVAL (i, 1, result), - NISENTRYLEN (i, 1, result)); - *p = '\0'; - room_left -= (NISENTRYLEN (i, 1, result) + 1); + *first_unused++ = ' '; + first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), + NISENTRYLEN (i, 1, result)); + room_left -= NISENTRYLEN (i, 1, result) + 1; } } - *p++ = '\0'; - first_unused = p; + *first_unused++ = '\0'; /* Adjust the pointer so it is aligned for storing pointers. */ - first_unused += __alignof__ (char *) - 1; - first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *)); - serv->s_aliases = (char **) first_unused; - if (room_left < sizeof (char *)) + size_t adjust = ((__alignof__ (char *) + - (first_unused - (char *) 0) % __alignof__ (char *)) + % __alignof__ (char *)); + if (room_left < adjust + sizeof (char *)) goto no_more_room; + first_unused += adjust; + room_left -= adjust; + serv->s_aliases = (char **) first_unused; + + /* For the terminating NULL pointer. */ room_left -= (sizeof (char *)); - serv->s_aliases[0] = NULL; - i = 0; + unsigned int i = 0; while (*line != '\0') { /* Skip leading blanks. */ @@ -124,42 +130,45 @@ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv, goto no_more_room; room_left -= sizeof (char *); - serv->s_aliases[i] = line; + serv->s_aliases[i++] = line; while (*line != '\0' && *line != ' ') ++line; if (*line == ' ') - { - *line = '\0'; - ++line; - ++i; - } - else - serv->s_aliases[i+1] = NULL; + *line++ = '\0'; } + serv->s_aliases[i] = NULL; return 1; } + static enum nss_status _nss_create_tablename (int *errnop) { if (tablename_val == NULL) { - char buf [40 + strlen (nis_local_directory ())]; - char *p; + const char *local_dir = nis_local_directory (); + size_t local_dir_len = strlen (local_dir); + static const char prefix[] = "services.org_dir."; - p = __stpcpy (buf, "services.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) + char *p = malloc (sizeof (prefix) + local_dir_len); + if (p == NULL) { *errnop = errno; return NSS_STATUS_TRYAGAIN; } - tablename_len = strlen (tablename_val); + + memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); + + tablename_len = sizeof (prefix) - 1 + local_dir_len; + + atomic_write_barrier (); + + tablename_val = p; } + return NSS_STATUS_SUCCESS; } @@ -172,9 +181,11 @@ _nss_nisplus_setservent (int stayopen) __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } if (tablename_val == NULL) status = _nss_create_tablename (&err); @@ -189,9 +200,11 @@ _nss_nisplus_endservent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } __libc_lock_unlock (lock); @@ -221,16 +234,23 @@ 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); } else { - nis_result *res; - saved_res = result; - res = nis_next_entry (tablename_val, &result->cookie); - 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) { nis_freeresult (saved_res); @@ -240,7 +260,7 @@ internal_nisplus_getservent_r (struct servent *serv, char *buffer, parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen, errnop); - if (parse_res == -1) + if (__builtin_expect (parse_res == -1, 0)) { nis_freeresult (result); result = saved_res; @@ -262,11 +282,9 @@ enum nss_status _nss_nisplus_getservent_r (struct servent *result, char *buffer, size_t buflen, int *errnop) { - int status; - __libc_lock_lock (lock); - status = internal_nisplus_getservent_r (result, buffer, buflen, errnop); + int status = internal_nisplus_getservent_r (result, buffer, buflen, errnop); __libc_lock_unlock (lock); @@ -278,12 +296,14 @@ _nss_nisplus_getservbyname_r (const char *name, const char *protocol, struct servent *serv, char *buffer, size_t buflen, int *errnop) { - int parse_res; - if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } @@ -293,72 +313,84 @@ _nss_nisplus_getservbyname_r (const char *name, const char *protocol, *errnop = EINVAL; return NSS_STATUS_NOTFOUND; } - else - { - nis_result *result; - char buf[strlen (name) + 255 + tablename_len]; - int olderr = errno; - /* Search at first in the alias list, and use the correct name - for the next search */ - sprintf (buf, "[name=%s,proto=%s],%s", name, protocol, - tablename_val); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + size_t protocol_len = strlen (protocol); + char buf[strlen (name) + protocol_len + 17 + tablename_len]; + int olderr = errno; - if (result != NULL) - { - /* If we do not find it, try it as original name. But if the - database is correct, we should find it in the first case, too */ - if ((result->status != NIS_SUCCESS - && result->status != NIS_S_SUCCESS) - || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ - || strcmp (result->objects.objects_val->EN_data.en_type, - "services_tbl") != 0 - || result->objects.objects_val->EN_data.en_cols.en_cols_len < 4) - sprintf (buf, "[cname=%s,proto=%s],%s", name, protocol, - tablename_val); - else - sprintf (buf, "[cname=%s,proto=%s],%s", - NISENTRYVAL (0, 0, result), protocol, tablename_val); - - nis_freeresult (result); - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); - } + /* Search at first in the alias list, and use the correct name + for the next search */ + snprintf (buf, sizeof (buf), "[name=%s,proto=%s],%s", name, protocol, + tablename_val); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); - if (result == NULL) + if (result != NULL) + { + char *bufptr = buf; + + /* If we did not find it, try it as original name. But if the + database is correct, we should find it in the first case, too */ + if ((result->status != NIS_SUCCESS + && result->status != NIS_S_SUCCESS) + || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ + || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, + "services_tbl") != 0 + || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4) + snprintf (buf, sizeof (buf), "[cname=%s,proto=%s],%s", name, protocol, + tablename_val); + else { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; + /* We need to allocate a new buffer since there is no + guarantee the returned name has a length limit. */ + const char *entryval = NISENTRYVAL(0, 0, result); + size_t buflen = (strlen (entryval) + protocol_len + 17 + + tablename_len); + bufptr = alloca (buflen); + snprintf (bufptr, buflen, "[cname=%s,proto=%s],%s", + entryval, protocol, tablename_val); } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); - __set_errno (olderr); + nis_freeresult (result); + result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); + } - nis_freeresult (result); - return status; - } + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); - parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen, - errnop); nis_freeresult (result); + return status; + } - if (parse_res < 1) + int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen, + errnop); + nis_freeresult (result); + + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } - return NSS_STATUS_SUCCESS; } + + return NSS_STATUS_SUCCESS; } enum nss_status @@ -368,8 +400,12 @@ _nss_nisplus_getservbyport_r (const int number, const char *protocol, { if (tablename_val == NULL) { + __libc_lock_lock (lock); + enum nss_status status = _nss_create_tablename (errnop); + __libc_lock_unlock (lock); + if (status != NSS_STATUS_SUCCESS) return status; } @@ -379,50 +415,49 @@ _nss_nisplus_getservbyport_r (const int number, const char *protocol, *errnop = EINVAL; return NSS_STATUS_NOTFOUND; } - else - { - int parse_res; - nis_result *result; - char buf[60 + strlen (protocol) + tablename_len]; - int olderr = errno; - sprintf (buf, "[port=%d,proto=%s],%s", - number, protocol, tablename_val); + char buf[17 + 3 * sizeof (int) + strlen (protocol) + tablename_len]; + int olderr = errno; - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + snprintf (buf, sizeof (buf), "[port=%d,proto=%s],%s", + number, protocol, tablename_val); - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); + nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, + NULL, NULL); - __set_errno (olderr); + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - nis_freeresult (result); - return status; - } + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); - parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen, - errnop); nis_freeresult (result); + return status; + } - if (parse_res < 1) + int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen, + errnop); + nis_freeresult (result); + + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } - return NSS_STATUS_SUCCESS; } + + return NSS_STATUS_SUCCESS; } diff --git a/nis/nss_nisplus/nisplus-spwd.c b/nis/nss_nisplus/nisplus-spwd.c index c317469137..f256f3eb90 100644 --- a/nis/nss_nisplus/nisplus-spwd.c +++ b/nis/nss_nisplus/nisplus-spwd.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -30,29 +31,12 @@ __libc_lock_define_initialized (static, lock) static nis_result *result; -static nis_name tablename_val; -static u_long tablename_len; -static enum nss_status -_nss_create_tablename (int *errnop) -{ - if (tablename_val == NULL) - { - char buf [40 + strlen (nis_local_directory ())]; - char *p; +/* Defined in nisplus-pwd.c. */ +extern nis_name pwd_tablename_val attribute_hidden; +extern size_t pwd_tablename_len attribute_hidden; +extern enum nss_status _nss_pwd_create_tablename (int *errnop); - p = __stpcpy (buf, "passwd.org_dir."); - p = __stpcpy (p, nis_local_directory ()); - tablename_val = __strdup (buf); - if (tablename_val == NULL) - { - *errnop = errno; - return NSS_STATUS_TRYAGAIN; - } - tablename_len = strlen (tablename_val); - } - return NSS_STATUS_SUCCESS; -} enum nss_status _nss_nisplus_setspent (int stayopen) @@ -62,12 +46,14 @@ _nss_nisplus_setspent (int stayopen) __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } - if (tablename_val == NULL) - status = _nss_create_tablename (&err); + if (pwd_tablename_val == NULL) + status = _nss_pwd_create_tablename (&err); __libc_lock_unlock (lock); @@ -79,9 +65,11 @@ _nss_nisplus_endspent (void) { __libc_lock_lock (lock); - if (result) - nis_freeresult (result); - result = NULL; + if (result != NULL) + { + nis_freeresult (result); + result = NULL; + } __libc_lock_unlock (lock); @@ -103,25 +91,32 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen, { saved_res = NULL; - if (tablename_val == NULL) + if (pwd_tablename_val == NULL) { - enum nss_status status = _nss_create_tablename (errnop); + enum nss_status status = _nss_pwd_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; } - result = nis_first_entry (tablename_val); + 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_result *res; - saved_res = result; - res = nis_next_entry (tablename_val, &result->cookie); - result = res; + 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); @@ -131,19 +126,18 @@ internal_nisplus_getspent_r (struct spwd *sp, char *buffer, size_t buflen, parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen, errnop); - if (parse_res == -1) + if (__builtin_expect (parse_res == -1, 0)) { nis_freeresult (result); result = saved_res; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - else - { - if (saved_res) - nis_freeresult (saved_res); - } - } while (!parse_res); + + if (saved_res != NULL) + nis_freeresult (saved_res); + } + while (!parse_res); return NSS_STATUS_SUCCESS; } @@ -169,9 +163,9 @@ _nss_nisplus_getspnam_r (const char *name, struct spwd *sp, { int parse_res; - if (tablename_val == NULL) + if (pwd_tablename_val == NULL) { - enum nss_status status = _nss_create_tablename (errnop); + enum nss_status status = _nss_pwd_create_tablename (errnop); if (status != NSS_STATUS_SUCCESS) return status; @@ -182,48 +176,47 @@ _nss_nisplus_getspnam_r (const char *name, struct spwd *sp, *errnop = EINVAL; return NSS_STATUS_NOTFOUND; } - else - { - nis_result *result; - char buf[strlen (name) + 24 + tablename_len]; - int olderr = errno; - sprintf (buf, "[name=%s],%s", name, tablename_val); + nis_result *result; + char buf[strlen (name) + 9 + pwd_tablename_len]; + int olderr = errno; - result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val); - if (result == NULL) - { - *errnop = ENOMEM; - return NSS_STATUS_TRYAGAIN; - } - if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) - { - enum nss_status status = niserr2nss (result->status); + result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL); - __set_errno (olderr); + if (result == NULL) + { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } - nis_freeresult (result); - return status; - } + if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) + { + enum nss_status status = niserr2nss (result->status); + + __set_errno (olderr); - parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen, - errnop); nis_freeresult (result); + return status; + } + + parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen, errnop); + nis_freeresult (result); - if (parse_res < 1) + if (__builtin_expect (parse_res < 1, 0)) + { + if (parse_res == -1) { - if (parse_res == -1) - { - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - else - { - __set_errno (olderr); - return NSS_STATUS_NOTFOUND; - } + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + else + { + __set_errno (olderr); + return NSS_STATUS_NOTFOUND; } - return NSS_STATUS_SUCCESS; } + + return NSS_STATUS_SUCCESS; } |