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 | |
parent | 7d58530341304d403a6626d7f7a1913165fe2f32 (diff) | |
download | glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.bz2 glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.zip |
2.5-18.1
Diffstat (limited to 'nis')
70 files changed, 5093 insertions, 3666 deletions
diff --git a/nis/Makefile b/nis/Makefile index fa5c4dfd30..8083ee8044 100644 --- a/nis/Makefile +++ b/nis/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1996, 1997, 1998, 2001, 2004 Free Software Foundation, Inc. +# Copyright (C) 1996,1997,1998,2001,2004,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 @@ -54,7 +54,7 @@ libnsl-routines = yp_xdr ypclnt ypupdate_xdr \ nis_print_group_entry nis_domain_of nis_domain_of_r\ nis_modify nis_remove nis_add nis_defaults\ nis_findserv nis_callback nis_clone_dir nis_clone_obj\ - nis_clone_res + nis_clone_res nss-default libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups) libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) @@ -64,7 +64,7 @@ libnss_nis-routines := $(addprefix nis-,$(databases)) nis-initgroups \ libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes)) libnss_nisplus-routines := $(addprefix nisplus-,$(databases)) nisplus-parser \ - nss-nisplus + nss-nisplus nisplus-initgroups libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes)) include ../Rules diff --git a/nis/Versions b/nis/Versions index d6b6a972f6..be4453e285 100644 --- a/nis/Versions +++ b/nis/Versions @@ -57,6 +57,10 @@ libnsl { GLIBC_2.2 { xdr_ypall; } + GLIBC_PRIVATE { + _nsl_default_nss; __prepare_niscall; __follow_path; __do_niscall3; + __create_ib_request; _xdr_ib_request; _xdr_nis_result; + } } libnss_compat { @@ -117,11 +121,10 @@ libnss_nisplus { _nss_nisplus_getservbyname_r; _nss_nisplus_getservbynumber_r; _nss_nisplus_getservent_r; _nss_nisplus_getspent_r; _nss_nisplus_getspnam_r; _nss_nisplus_netname2user; - _nss_nisplus_parse_grent; _nss_nisplus_parse_pwent; - _nss_nisplus_parse_spent; _nss_nisplus_setaliasent; + _nss_nisplus_setaliasent; _nss_nisplus_setetherent; _nss_nisplus_setgrent; _nss_nisplus_sethostent; _nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent; _nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent; - _nss_nisplus_setspent; + _nss_nisplus_setspent; _nss_nisplus_initgroups_dyn; } } diff --git a/nis/libnsl.h b/nis/libnsl.h new file mode 100644 index 0000000000..c6ceb321d7 --- /dev/null +++ b/nis/libnsl.h @@ -0,0 +1,40 @@ +/* Copyright (C) 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 <rpcsvc/nis.h> + +#define NSS_FLAG_NETID_AUTHORITATIVE 1 +#define NSS_FLAG_SERVICES_AUTHORITATIVE 2 +#define NSS_FLAG_SETENT_BATCH_READ 4 + + +/* Get current set of default flags. */ +extern int _nsl_default_nss (void); + +/* Set up everything for a call to __do_niscall3. */ +extern nis_error __prepare_niscall (const_nis_name name, directory_obj **dirp, + dir_binding *bptrp, unsigned int flags); +libnsl_hidden_proto (__prepare_niscall) + +extern struct ib_request *__create_ib_request (const_nis_name name, + unsigned int flags); +libnsl_hidden_proto (__create_ib_request) + +extern nis_error __follow_path (char **tablepath, char **tableptr, + struct ib_request *ibreq, dir_binding *bptr); +libnsl_hidden_proto (__follow_path) diff --git a/nis/nis_addmember.c b/nis/nis_addmember.c index bbe1c23977..5e342ad0d0 100644 --- a/nis/nis_addmember.c +++ b/nis/nis_addmember.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 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. @@ -28,13 +28,12 @@ nis_addmember (const_nis_name member, const_nis_name group) { size_t grouplen = strlen (group); char buf[grouplen + 14 + NIS_MAXNAMELEN]; - char leafbuf[grouplen + 2]; char domainbuf[grouplen + 2]; nis_result *res, *res2; nis_error status; char *cp, *cp2; - cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1)); + cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0'); cp = stpcpy (cp, ".groups_dir"); cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); if (cp2 != NULL && cp2[0] != '\0') @@ -42,30 +41,35 @@ nis_addmember (const_nis_name member, const_nis_name group) *cp++ = '.'; stpcpy (cp, cp2); } - res = nis_lookup (buf, FOLLOW_LINKS|EXPAND_NAME); + res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME); if (NIS_RES_STATUS (res) != NIS_SUCCESS) { status = NIS_RES_STATUS (res); nis_freeresult (res); return status; } - if ((NIS_RES_NUMOBJ (res) != 1) || - (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)) + if (NIS_RES_NUMOBJ (res) != 1 + || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ) { nis_freeresult (res); return NIS_INVALIDOBJ; } - NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val + u_int gr_members_len + = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len; + + nis_name *new_gr_members_val = realloc (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val, - (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len + 1) - * sizeof (char *)); - if (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val == NULL) + (gr_members_len + 1) * sizeof (nis_name)); + if (new_gr_members_val == NULL) goto nomem_out; - NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len] = strdup (member); - if (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len] == NULL) + + NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val + = new_gr_members_val; + + new_gr_members_val[gr_members_len] = strdup (member); + if (new_gr_members_val[gr_members_len] == NULL) { - free (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val); nomem_out: nis_freeresult (res); return NIS_NOMEMORY; diff --git a/nis/nis_call.c b/nis/nis_call.c index 14041a160c..c571e8f367 100644 --- a/nis/nis_call.c +++ b/nis/nis_call.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 1998, 2001, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998, 2001, 2004, 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. @@ -25,11 +26,15 @@ #include <rpc/auth.h> #include <rpcsvc/nis.h> #include <sys/socket.h> +#include <sys/stat.h> +#include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <bits/libc-lock.h> #include "nis_xdr.h" #include "nis_intern.h" +#include <libnsl.h> static const struct timeval RPCTIMEOUT = {10, 0}; static const struct timeval UDPTIMEOUT = {5, 0}; @@ -37,28 +42,19 @@ static const struct timeval UDPTIMEOUT = {5, 0}; extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program, u_long version, u_int protocol); -unsigned long +unsigned long int inetstr2int (const char *str) { - char buffer[strlen (str) + 3]; - size_t buflen; - size_t i, j; - - buflen = stpcpy (buffer, str) - buffer; - - j = 0; - for (i = 0; i < buflen; ++i) - if (buffer[i] == '.') + size_t j = 0; + for (size_t i = 0; str[i] != '\0'; ++i) + if (str[i] == '.' && __builtin_expect (++j == 4, 0)) { - ++j; - if (j == 4) - { - buffer[i] = '\0'; - break; - } + char buffer[i + 1]; + buffer[i] = '\0'; + return inet_addr (memcpy (buffer, str, i)); } - return inet_addr (buffer); + return inet_addr (str); } void @@ -76,8 +72,6 @@ libnsl_hidden_def (__nisbind_destroy) nis_error __nisbind_next (dir_binding *bind) { - u_int j; - if (bind->clnt != NULL) { if (bind->use_auth) @@ -89,7 +83,7 @@ __nisbind_next (dir_binding *bind) if (bind->trys >= bind->server_len) return NIS_FAIL; - for (j = bind->current_ep + 1; + for (u_int j = bind->current_ep + 1; j < bind->server_val[bind->server_used].ep.ep_len; ++j) if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family, "inet") == 0) @@ -104,7 +98,7 @@ __nisbind_next (dir_binding *bind) if (bind->server_used >= bind->server_len) bind->server_used = 0; - for (j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j) + for (u_int j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j) if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family, "inet") == 0) if (bind->server_val[bind->server_used].ep.ep_val[j].proto[0] == '-') @@ -117,10 +111,79 @@ __nisbind_next (dir_binding *bind) } libnsl_hidden_def (__nisbind_next) +static struct ckey_cache_entry +{ + struct in_addr inaddr; + in_port_t port; + unsigned int protocol; + des_block ckey; +} *ckey_cache; +static size_t ckey_cache_size; +static size_t ckey_cache_allocated; +static pid_t ckey_cache_pid; +static uid_t ckey_cache_euid; +__libc_lock_define_initialized (static, ckey_cache_lock) + +static bool_t +get_ckey (des_block *ckey, struct sockaddr_in *addr, unsigned int protocol) +{ + size_t i; + pid_t pid = getpid (); + uid_t euid = geteuid (); + bool_t ret = FALSE; + + __libc_lock_lock (ckey_cache_lock); + + if (ckey_cache_pid != pid || ckey_cache_euid != euid) + { + ckey_cache_size = 0; + ckey_cache_pid = pid; + ckey_cache_euid = euid; + } + + for (i = 0; i < ckey_cache_size; ++i) + if (ckey_cache[i].port == addr->sin_port + && ckey_cache[i].protocol == protocol + && memcmp (&ckey_cache[i].inaddr, &addr->sin_addr, + sizeof (addr->sin_addr)) == 0) + { + *ckey = ckey_cache[i].ckey; + ret = TRUE; + break; + } + + if (!ret && key_gendes (ckey) >= 0) + { + ret = TRUE; + /* Don't grow the cache indefinitely. */ + if (ckey_cache_size == 256) + ckey_cache_size = 0; + if (ckey_cache_size == ckey_cache_allocated) + { + size_t size = ckey_cache_allocated ? ckey_cache_allocated * 2 : 16; + struct ckey_cache_entry *new_cache + = realloc (ckey_cache, size * sizeof (*ckey_cache)); + if (new_cache != NULL) + { + ckey_cache = new_cache; + ckey_cache_allocated = size; + } + } + ckey_cache[ckey_cache_size].inaddr = addr->sin_addr; + ckey_cache[ckey_cache_size].port = addr->sin_port; + ckey_cache[ckey_cache_size].protocol = protocol; + ckey_cache[ckey_cache_size++].ckey = *ckey; + } + + __libc_lock_unlock (ckey_cache_lock); + return ret; +} + nis_error __nisbind_connect (dir_binding *dbp) { nis_server *serv; + u_short port; if (dbp == NULL) return NIS_FAIL; @@ -133,14 +196,17 @@ __nisbind_connect (dir_binding *dbp) dbp->addr.sin_addr.s_addr = inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr); - if (dbp->addr.sin_addr.s_addr == 0) + if (dbp->addr.sin_addr.s_addr == INADDR_NONE) return NIS_FAIL; /* Check, if the host is online and rpc.nisd is running. Much faster then the clnt*_create functions: */ - if (__pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION, IPPROTO_UDP) == 0) + port = __pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION, + dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP); + if (port == 0) return NIS_RPCERROR; + dbp->addr.sin_port = htons (port); dbp->socket = RPC_ANYSOCK; if (dbp->use_udp) dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION, @@ -163,23 +229,21 @@ __nisbind_connect (dir_binding *dbp) { char netname[MAXNETNAMELEN + 1]; char *p; + des_block ckey; - p = stpcpy (netname, "unix."); + p = stpcpy (netname, "unix@"); strncpy (p, serv->name, MAXNETNAMELEN - 5); netname[MAXNETNAMELEN] = '\0'; - // XXX What is this supposed to do? If we really want to replace - // XXX the first dot, then we might as well use unix@ as the - // XXX prefix string. --drepper - p = strchr (netname, '.'); - *p = '@'; - dbp->clnt->cl_auth = - authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL); + dbp->clnt->cl_auth = NULL; + if (get_ckey (&ckey, &dbp->addr, + dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP)) + dbp->clnt->cl_auth = + authdes_pk_create (netname, &serv->pkey, 300, NULL, &ckey); if (!dbp->clnt->cl_auth) dbp->clnt->cl_auth = authunix_create_default (); } else dbp->clnt->cl_auth = authunix_create_default (); - dbp->use_auth = TRUE; } return NIS_SUCCESS; @@ -188,7 +252,8 @@ libnsl_hidden_def (__nisbind_connect) nis_error __nisbind_create (dir_binding *dbp, const nis_server *serv_val, - unsigned int serv_len, unsigned int flags) + unsigned int serv_len, unsigned int server_used, + unsigned int current_ep, unsigned int flags) { dbp->clnt = NULL; @@ -214,10 +279,15 @@ __nisbind_create (dir_binding *dbp, const nis_server *serv_val, dbp->trys = 1; dbp->class = -1; - if (__nis_findfastest (dbp) < 1) + if (server_used == ~0) { - __nisbind_destroy (dbp); - return NIS_NAMEUNREACHABLE; + if (__nis_findfastest (dbp) < 1) + return NIS_NAMEUNREACHABLE; + } + else + { + dbp->server_used = server_used; + dbp->current_ep = current_ep; } return NIS_SUCCESS; @@ -269,6 +339,7 @@ __do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req, || ((nis_result *)resp)->status == NIS_NOSUCHNAME || ((nis_result *)resp)->status == NIS_NOT_ME) { + next_server: if (__nisbind_next (dbp) == NIS_SUCCESS) { while (__nisbind_connect (dbp) != NIS_SUCCESS) @@ -286,38 +357,14 @@ __do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req, if (((fd_result *)resp)->status == NIS_SYSTEMERROR || ((fd_result *)resp)->status == NIS_NOSUCHNAME || ((fd_result *)resp)->status == NIS_NOT_ME) - { - if (__nisbind_next (dbp) == NIS_SUCCESS) - { - while (__nisbind_connect (dbp) != NIS_SUCCESS) - { - if (__nisbind_next (dbp) != NIS_SUCCESS) - return NIS_SUCCESS; - } - } - else - break; /* No more servers to search in */ - goto again; - } + goto next_server; break; case NIS_DUMPLOG: /* log_result */ case NIS_DUMP: if (((log_result *)resp)->lr_status == NIS_SYSTEMERROR || ((log_result *)resp)->lr_status == NIS_NOSUCHNAME || ((log_result *)resp)->lr_status == NIS_NOT_ME) - { - if (__nisbind_next (dbp) == NIS_SUCCESS) - { - while (__nisbind_connect (dbp) != NIS_SUCCESS) - { - if (__nisbind_next (dbp) != NIS_SUCCESS) - return NIS_SUCCESS; - } - } - else - break; /* No more servers to search in */ - goto again; - } + goto next_server; break; default: break; @@ -329,6 +376,8 @@ __do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req, return retcode; } +libnsl_hidden_def (__do_niscall3) + nis_error __do_niscall2 (const nis_server *server, u_int server_len, u_long prog, @@ -341,7 +390,7 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog, if (flags & MASTER_ONLY) server_len = 1; - status = __nisbind_create (&dbp, server, server_len, flags); + status = __nisbind_create (&dbp, server, server_len, ~0, ~0, flags); if (status != NIS_SUCCESS) return status; @@ -373,14 +422,18 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status) case HIGHER_NAME: { /* We need data from a parent domain */ directory_obj *obj; - char ndomain [strlen (name) + 3]; - - nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain)); + const char *ndomain = __nis_domain_of (dir->do_name); /* The root server of our domain is a replica of the parent domain ! (Now I understand why a root server must be a replica of the parent domain) */ fd_res = __nis_finddirectory (dir, ndomain); + if (fd_res == NULL) + { + nis_free_directory (dir); + *status = NIS_NOMEMORY; + return NULL; + } *status = fd_res->status; if (fd_res->status != NIS_SUCCESS) { @@ -388,36 +441,33 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status) __free_fdresult (fd_res); return dir; } + nis_free_directory (dir); obj = calloc (1, sizeof (directory_obj)); + if (obj == NULL) + { + __free_fdresult (fd_res); + *status = NIS_NOMEMORY; + return NULL; + } xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val, fd_res->dir_data.dir_data_len, XDR_DECODE); _xdr_directory_obj (&xdrs, obj); xdr_destroy (&xdrs); __free_fdresult (fd_res); - if (obj != NULL) - { - /* We have found a NIS+ server serving ndomain, now - let us search for "name" */ - nis_free_directory (dir); - return rec_dirsearch (name, obj, status); - } - else - { - /* Ups, very bad. Are we already the root server ? */ - nis_free_directory (dir); - return NULL; - } + + /* We have found a NIS+ server serving ndomain, now + let us search for "name" */ + return rec_dirsearch (name, obj, status); } - break; + break; case LOWER_NAME: { directory_obj *obj; size_t namelen = strlen (name); char leaf[namelen + 3]; char domain[namelen + 3]; - char ndomain[namelen + 3]; + const char *ndomain; char *cp; - u_int run = 0; strcpy (domain, name); @@ -429,23 +479,22 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status) return NULL; } nis_leaf_of_r (domain, leaf, sizeof (leaf)); - nis_domain_of_r (domain, ndomain, sizeof (ndomain)); - strcpy (domain, ndomain); - ++run; + ndomain = __nis_domain_of (domain); + memmove (domain, ndomain, strlen (ndomain) + 1); } while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME); - if (run == 1) - { - /* We have found the directory above. Use it. */ - return dir; - } - - cp = strchr (leaf, '\0'); + cp = rawmemchr (leaf, '\0'); *cp++ = '.'; strcpy (cp, domain); fd_res = __nis_finddirectory (dir, leaf); + if (fd_res == NULL) + { + nis_free_directory (dir); + *status = NIS_NOMEMORY; + return NULL; + } *status = fd_res->status; if (fd_res->status != NIS_SUCCESS) { @@ -453,21 +502,24 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, nis_error *status) __free_fdresult (fd_res); return dir; } - obj = calloc(1, sizeof(directory_obj)); - xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val, - fd_res->dir_data.dir_data_len, XDR_DECODE); - _xdr_directory_obj(&xdrs, obj); - xdr_destroy(&xdrs); - __free_fdresult (fd_res); - if (obj != NULL) + nis_free_directory (dir); + obj = calloc (1, sizeof(directory_obj)); + if (obj == NULL) { - /* We have found a NIS+ server serving ndomain, now - let us search for "name" */ - nis_free_directory (dir); - return rec_dirsearch (name, obj, status); + __free_fdresult (fd_res); + *status = NIS_NOMEMORY; + return NULL; } + xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val, + fd_res->dir_data.dir_data_len, XDR_DECODE); + _xdr_directory_obj (&xdrs, obj); + xdr_destroy (&xdrs); + __free_fdresult (fd_res); + /* We have found a NIS+ server serving ndomain, now + let us search for "name" */ + return rec_dirsearch (name, obj, status); } - break; + break; case BAD_NAME: nis_free_directory (dir); *status = NIS_BADNAME; @@ -486,24 +538,26 @@ first_shoot (const_nis_name name, directory_obj *dir) directory_obj *obj = NULL; fd_result *fd_res; XDR xdrs; - char domain[strlen (name) + 3]; if (nis_dir_cmp (name, dir->do_name) == SAME_NAME) return dir; - nis_domain_of_r (name, domain, sizeof (domain)); - - if (nis_dir_cmp (domain, dir->do_name) == SAME_NAME) - return dir; - - fd_res = __nis_finddirectory (dir, domain); + fd_res = __nis_finddirectory (dir, name); + if (fd_res == NULL) + return NULL; if (fd_res->status == NIS_SUCCESS && (obj = calloc (1, sizeof (directory_obj))) != NULL) { - xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val, - fd_res->dir_data.dir_data_len, XDR_DECODE); + xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val, + fd_res->dir_data.dir_data_len, XDR_DECODE); _xdr_directory_obj (&xdrs, obj); xdr_destroy (&xdrs); + + if (strcmp (dir->do_name, obj->do_name) != 0) + { + nis_free_directory (obj); + obj = NULL; + } } __free_fdresult (fd_res); @@ -514,87 +568,271 @@ first_shoot (const_nis_name name, directory_obj *dir) return obj; } +static struct nis_server_cache +{ + int search_parent; + int uses; + unsigned int size; + unsigned int server_used; + unsigned int current_ep; + time_t expires; + char name[]; +} *nis_server_cache[16]; +static time_t nis_cold_start_mtime; +__libc_lock_define_initialized (static, nis_server_cache_lock) + +static directory_obj * +nis_server_cache_search (const_nis_name name, int search_parent, + unsigned int *server_used, unsigned int *current_ep, + struct timeval *now) +{ + directory_obj *ret = NULL; + int i; + char *addr; + XDR xdrs; + struct stat64 st; + + if (stat64 ("/var/nis/NIS_COLD_START", &st) < 0) + st.st_mtime = nis_cold_start_mtime + 1; + + __libc_lock_lock (nis_server_cache_lock); + + for (i = 0; i < 16; ++i) + if (nis_server_cache[i] == NULL) + continue; + else if (st.st_mtime != nis_cold_start_mtime + || now->tv_sec > nis_server_cache[i]->expires) + { + free (nis_server_cache[i]); + nis_server_cache[i] = NULL; + } + else if (nis_server_cache[i]->search_parent == search_parent + && strcmp (nis_server_cache[i]->name, name) == 0) + { + ret = calloc (1, sizeof (directory_obj)); + if (ret == NULL) + break; + + addr = rawmemchr (nis_server_cache[i]->name, '\0') + 8; + addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7); + xdrmem_create (&xdrs, addr, nis_server_cache[i]->size, XDR_DECODE); + if (!_xdr_directory_obj (&xdrs, ret)) + { + xdr_destroy (&xdrs); + free (ret); + ret = NULL; + free (nis_server_cache[i]); + nis_server_cache[i] = NULL; + break; + } + xdr_destroy (&xdrs); + *server_used = nis_server_cache[i]->server_used; + *current_ep = nis_server_cache[i]->current_ep; + break; + } + + nis_cold_start_mtime = st.st_mtime; + + __libc_lock_unlock (nis_server_cache_lock); + return ret; +} + +static void +nis_server_cache_add (const_nis_name name, int search_parent, + directory_obj *dir, unsigned int server_used, + unsigned int current_ep, struct timeval *now) +{ + struct nis_server_cache **loc; + struct nis_server_cache *new; + struct nis_server_cache *old; + int i; + char *addr; + unsigned int size; + XDR xdrs; + + if (dir == NULL) + return; + + size = xdr_sizeof ((xdrproc_t) _xdr_directory_obj, (char *) dir); + new = calloc (1, sizeof (*new) + strlen (name) + 8 + size); + if (new == NULL) + return; + new->search_parent = search_parent; + new->uses = 1; + new->expires = now->tv_sec + dir->do_ttl; + new->size = size; + new->server_used = server_used; + new->current_ep = current_ep; + addr = stpcpy (new->name, name) + 8; + addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7); + + xdrmem_create(&xdrs, addr, size, XDR_ENCODE); + if (!_xdr_directory_obj (&xdrs, dir)) + { + xdr_destroy (&xdrs); + free (new); + return; + } + xdr_destroy (&xdrs); + + __libc_lock_lock (nis_server_cache_lock); + + /* Choose which entry should be evicted from the cache. */ + loc = &nis_server_cache[0]; + if (*loc != NULL) + for (i = 1; i < 16; ++i) + if (nis_server_cache[i] == NULL) + { + loc = &nis_server_cache[i]; + break; + } + else if ((*loc)->uses > nis_server_cache[i]->uses + || ((*loc)->uses == nis_server_cache[i]->uses + && (*loc)->expires > nis_server_cache[i]->expires)) + loc = &nis_server_cache[i]; + old = *loc; + *loc = new; + + __libc_lock_unlock (nis_server_cache_lock); + free (old); +} + nis_error -__nisfind_server (const_nis_name name, directory_obj **dir) +__nisfind_server (const_nis_name name, int search_parent, + directory_obj **dir, dir_binding *dbp, unsigned int flags) { + nis_error result = NIS_SUCCESS; + nis_error status; + directory_obj *obj; + struct timeval now; + unsigned int server_used = ~0; + unsigned int current_ep = ~0; + if (name == NULL) return NIS_BADNAME; -#if 0 - /* Search in local cache. In the moment, we ignore the fastest server */ - if (!(flags & NO_CACHE)) - dir = __nis_cache_search (name, flags, &cinfo); -#endif + if (*dir != NULL) + return NIS_SUCCESS; - if (*dir == NULL) - { - nis_error status; - directory_obj *obj; + (void) gettimeofday (&now, NULL); - *dir = readColdStartFile (); - if (*dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */ - return NIS_UNAVAIL; + if ((flags & NO_CACHE) == 0) + *dir = nis_server_cache_search (name, search_parent, &server_used, + ¤t_ep, &now); + if (*dir != NULL) + { + unsigned int server_len = (*dir)->do_servers.do_servers_len; + if (flags & MASTER_ONLY) + { + server_len = 1; + if (server_used != 0) + { + server_used = ~0; + current_ep = ~0; + } + } + result = __nisbind_create (dbp, (*dir)->do_servers.do_servers_val, + server_len, server_used, current_ep, flags); + if (result != NIS_SUCCESS) + { + nis_free_directory (*dir); + *dir = NULL; + } + return result; + } - /* Try at first, if servers in "dir" know our object */ - obj = first_shoot (name, *dir); + *dir = readColdStartFile (); + if (*dir == NULL) + /* No /var/nis/NIS_COLD_START->no NIS+ installed. */ + return NIS_UNAVAIL; + + /* Try at first, if servers in "dir" know our object */ + const char *search_name = name; + if (search_parent) + search_name = __nis_domain_of (name); + obj = first_shoot (search_name, *dir); + if (obj == NULL) + { + obj = rec_dirsearch (search_name, *dir, &status); if (obj == NULL) + result = status; + } + + if (result == NIS_SUCCESS) + { + unsigned int server_len = obj->do_servers.do_servers_len; + if (flags & MASTER_ONLY) + server_len = 1; + result = __nisbind_create (dbp, obj->do_servers.do_servers_val, + server_len, ~0, ~0, flags); + if (result == NIS_SUCCESS) { - *dir = rec_dirsearch (name, *dir, &status); - if (*dir == NULL) - return status; + if ((flags & MASTER_ONLY) == 0 + || obj->do_servers.do_servers_len == 1) + { + server_used = dbp->server_used; + current_ep = dbp->current_ep; + } + if ((flags & NO_CACHE) == 0) + nis_server_cache_add (name, search_parent, obj, + server_used, current_ep, &now); } else - *dir = obj; + { + nis_free_directory (obj); + obj = NULL; + } } - return NIS_SUCCESS; + *dir = obj; + + return result; } + +nis_error +__prepare_niscall (const_nis_name name, directory_obj **dirp, + dir_binding *bptrp, unsigned int flags) +{ + nis_error retcode = __nisfind_server (name, 1, dirp, bptrp, flags); + if (__builtin_expect (retcode != NIS_SUCCESS, 0)) + return retcode; + + do + if (__nisbind_connect (bptrp) == NIS_SUCCESS) + return NIS_SUCCESS; + while (__nisbind_next (bptrp) == NIS_SUCCESS); + + __nisbind_destroy (bptrp); + memset (bptrp, '\0', sizeof (*bptrp)); + + retcode = NIS_NAMEUNREACHABLE; + nis_free_directory (*dirp); + *dirp = NULL; + + return retcode; +} +libnsl_hidden_def (__prepare_niscall) + + nis_error __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp, unsigned int flags, nis_cb *cb) { - nis_error retcode; dir_binding bptr; directory_obj *dir = NULL; - nis_server *server; - u_int server_len; int saved_errno = errno; - retcode = __nisfind_server (name, &dir); - if (retcode != NIS_SUCCESS) - return retcode; - - if (flags & MASTER_ONLY) - { - server = dir->do_servers.do_servers_val; - server_len = 1; - } - else - { - server = dir->do_servers.do_servers_val; - server_len = dir->do_servers.do_servers_len; - } - - retcode = __nisbind_create (&bptr, server, server_len, flags); + nis_error retcode = __prepare_niscall (name, &dir, &bptr, flags); if (retcode == NIS_SUCCESS) { - while (__nisbind_connect (&bptr) != NIS_SUCCESS) - { - if (__nisbind_next (&bptr) != NIS_SUCCESS) - { - nis_free_directory (dir); - __nisbind_destroy (&bptr); - return NIS_NAMEUNREACHABLE; - } - } retcode = __do_niscall3 (&bptr, prog, xargs, req, xres, resp, flags, cb); __nisbind_destroy (&bptr); - } - nis_free_directory (dir); + nis_free_directory (dir); + } __set_errno (saved_errno); diff --git a/nis/nis_callback.c b/nis/nis_callback.c index b867b39ab7..e0acd9683a 100644 --- a/nis/nis_callback.c +++ b/nis/nis_callback.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1997,1998,1999,2000,2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -197,22 +197,18 @@ internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie, struct nis_cb *cb) { struct timeval TIMEOUT = {25, 0}; - bool_t cb_is_running = FALSE; + bool_t cb_is_running; data = cb; for (;;) { - struct pollfd *my_pollfd; + struct pollfd my_pollfd[svc_max_pollfd]; int i; if (svc_max_pollfd == 0 && svc_pollfd == NULL) return NIS_CBERROR; - my_pollfd = malloc (sizeof (struct pollfd) * svc_max_pollfd); - if (__builtin_expect (my_pollfd == NULL, 0)) - return NIS_NOMEMORY; - for (i = 0; i < svc_max_pollfd; ++i) { my_pollfd[i].fd = svc_pollfd[i].fd; @@ -220,20 +216,17 @@ internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie, my_pollfd[i].revents = 0; } - switch (i = __poll (my_pollfd, svc_max_pollfd, 25*1000)) + switch (i = TEMP_FAILURE_RETRY (__poll (my_pollfd, svc_max_pollfd, + 25*1000))) { case -1: - free (my_pollfd); - if (errno == EINTR) - continue; return NIS_CBERROR; case 0: - free (my_pollfd); /* See if callback 'thread' in the server is still alive. */ - memset ((char *) &cb_is_running, 0, sizeof (cb_is_running)); + cb_is_running = FALSE; if (clnt_call (bptr->clnt, NIS_CALLBACK, (xdrproc_t) xdr_netobj, (caddr_t) cookie, (xdrproc_t) xdr_bool, - (caddr_t) & cb_is_running, TIMEOUT) != RPC_SUCCESS) + (caddr_t) &cb_is_running, TIMEOUT) != RPC_SUCCESS) cb_is_running = FALSE; if (cb_is_running == FALSE) @@ -244,7 +237,6 @@ internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie, break; default: svc_getreq_poll (my_pollfd, i); - free (my_pollfd); if (data->nomore) return data->result; } @@ -274,16 +266,15 @@ __nis_create_callback (int (*callback) (const_nis_name, const nis_object *, struct nis_cb *cb; int sock = RPC_ANYSOCK; struct sockaddr_in sin; - int len = sizeof (struct sockaddr_in); - char addr[NIS_MAXNAMELEN + 1]; + socklen_t len = sizeof (struct sockaddr_in); unsigned short port; + int nomsg = 0; - cb = (struct nis_cb *) calloc (1, sizeof (struct nis_cb)); + cb = (struct nis_cb *) calloc (1, + sizeof (struct nis_cb) + sizeof (nis_server)); if (__builtin_expect (cb == NULL, 0)) goto failed; - cb->serv = (nis_server *) calloc (1, sizeof (nis_server)); - if (__builtin_expect (cb->serv == NULL, 0)) - goto failed; + cb->serv = (nis_server *) (cb + 1); cb->serv->name = strdup (nis_local_principal ()); if (__builtin_expect (cb->serv->name == NULL, 0)) goto failed; @@ -326,15 +317,20 @@ __nis_create_callback (int (*callback) (const_nis_name, const nis_object *, cb->serv->ep.ep_val[0].proto = strdup ((flags & USE_DGRAM) ? "udp" : "tcp"); if (__builtin_expect (cb->serv->ep.ep_val[0].proto == NULL, 0)) goto failed; - cb->xprt = (flags & USE_DGRAM) ? svcudp_bufcreate (sock, 100, 8192) : - svctcp_create (sock, 100, 8192); + cb->xprt = ((flags & USE_DGRAM) + ? svcudp_bufcreate (sock, 100, 8192) + : svctcp_create (sock, 100, 8192)); + if (cb->xprt == NULL) + { + nomsg = 1; + goto failed; + } cb->sock = cb->xprt->xp_sock; if (!svc_register (cb->xprt, CB_PROG, CB_VERS, cb_prog_1, 0)) { xprt_unregister (cb->xprt); svc_destroy (cb->xprt); xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); - free (cb->serv); free (cb); syslog (LOG_ERR, "NIS+: failed to register callback dispatcher"); return NULL; @@ -345,30 +341,30 @@ __nis_create_callback (int (*callback) (const_nis_name, const nis_object *, xprt_unregister (cb->xprt); svc_destroy (cb->xprt); xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); - free (cb->serv); free (cb); syslog (LOG_ERR, "NIS+: failed to read local socket info"); return NULL; } port = ntohs (sin.sin_port); get_myaddress (&sin); - snprintf (addr, sizeof (addr), "%s.%d.%d", inet_ntoa (sin.sin_addr), - (port & 0xFF00) >> 8, port & 0x00FF); - cb->serv->ep.ep_val[0].uaddr = strdup (addr); + + if (asprintf (&cb->serv->ep.ep_val[0].uaddr, "%s.%d.%d", + inet_ntoa (sin.sin_addr), (port & 0xFF00) >> 8, port & 0x00FF) + < 0) + goto failed; return cb; failed: if (cb) { - if (cb->serv) - { - xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); - free (cb->serv); - } + if (cb->xprt) + svc_destroy (cb->xprt); + xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); free (cb); } - syslog (LOG_ERR, "NIS+: out of memory allocating callback"); + if (!nomsg) + syslog (LOG_ERR, "NIS+: out of memory allocating callback"); return NULL; } @@ -379,7 +375,6 @@ __nis_destroy_callback (struct nis_cb *cb) svc_destroy (cb->xprt); close (cb->sock); xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv); - free (cb->serv); free (cb); return NIS_SUCCESS; diff --git a/nis/nis_checkpoint.c b/nis/nis_checkpoint.c index 0146d53054..23c4707b6f 100644 --- a/nis/nis_checkpoint.c +++ b/nis/nis_checkpoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -24,7 +24,7 @@ #include "nis_intern.h" nis_result * -nis_checkpoint(const_nis_name dirname) +nis_checkpoint (const_nis_name dirname) { nis_result *res; @@ -48,7 +48,6 @@ nis_checkpoint(const_nis_name dirname) if (__type_of (NIS_RES_OBJECT (res2)) != NIS_DIRECTORY_OBJ) { nis_freeresult (res2); - nis_freeresult (res); NIS_RES_STATUS (res) = NIS_INVALIDOBJ; return res; } diff --git a/nis/nis_clone_dir.c b/nis/nis_clone_dir.c index 0271db1790..f94a1eeb74 100644 --- a/nis/nis_clone_dir.c +++ b/nis/nis_clone_dir.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 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. @@ -26,18 +26,27 @@ directory_obj * nis_clone_directory (const directory_obj *src, directory_obj *dest) { - unsigned char *addr; + char *addr; unsigned int size; XDR xdrs; - directory_obj *res; if (src == NULL) - return (NULL); + return NULL; size = xdr_sizeof ((xdrproc_t)_xdr_directory_obj, (char *)src); if ((addr = calloc(1, size)) == NULL) return NULL; + xdrmem_create(&xdrs, addr, size, XDR_ENCODE); + if (!_xdr_directory_obj (&xdrs, (directory_obj *)src)) + { + xdr_destroy (&xdrs); + free (addr); + return NULL; + } + xdr_destroy (&xdrs); + + directory_obj *res; if (dest == NULL) { if ((res = calloc (1, sizeof (directory_obj))) == NULL) @@ -49,18 +58,12 @@ nis_clone_directory (const directory_obj *src, directory_obj *dest) else res = dest; - xdrmem_create(&xdrs, addr, size, XDR_ENCODE); - if (!_xdr_directory_obj (&xdrs, (directory_obj *)src)) - { - xdr_destroy (&xdrs); - free (addr); - return NULL; - } - xdr_destroy (&xdrs); xdrmem_create (&xdrs, addr, size, XDR_DECODE); if (!_xdr_directory_obj (&xdrs, res)) { xdr_destroy (&xdrs); + if (res != dest) + free (res); free (addr); return NULL; } diff --git a/nis/nis_clone_obj.c b/nis/nis_clone_obj.c index 0b163fe662..4d88200284 100644 --- a/nis/nis_clone_obj.c +++ b/nis/nis_clone_obj.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -26,8 +26,8 @@ nis_object * nis_clone_object (const nis_object *src, nis_object *dest) { - unsigned char *addr; - unsigned long size; + char *addr; + unsigned int size; XDR xdrs; nis_object *res = NULL; diff --git a/nis/nis_clone_res.c b/nis/nis_clone_res.c index 135f397911..021f7cb4f4 100644 --- a/nis/nis_clone_res.c +++ b/nis/nis_clone_res.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 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. @@ -26,10 +26,9 @@ nis_result * nis_clone_result (const nis_result *src, nis_result *dest) { - unsigned char *addr; + char *addr; unsigned int size; XDR xdrs; - nis_result *res; if (src == NULL) return (NULL); @@ -38,6 +37,16 @@ nis_clone_result (const nis_result *src, nis_result *dest) if ((addr = calloc(1, size)) == NULL) return NULL; + xdrmem_create (&xdrs, addr, size, XDR_ENCODE); + if (!_xdr_nis_result (&xdrs, (nis_result *)src)) + { + xdr_destroy (&xdrs); + free (addr); + return NULL; + } + xdr_destroy (&xdrs); + + nis_result *res; if (dest == NULL) { if ((res = calloc (1, sizeof (nis_result))) == NULL) @@ -49,18 +58,12 @@ nis_clone_result (const nis_result *src, nis_result *dest) else res = dest; - xdrmem_create(&xdrs, addr, size, XDR_ENCODE); - if (!_xdr_nis_result (&xdrs, (nis_result *)src)) - { - xdr_destroy (&xdrs); - free (addr); - return NULL; - } - xdr_destroy (&xdrs); - xdrmem_create(&xdrs, addr, size, XDR_DECODE); - if (!_xdr_nis_result(&xdrs, res)) + xdrmem_create (&xdrs, addr, size, XDR_DECODE); + if (!_xdr_nis_result (&xdrs, res)) { xdr_destroy (&xdrs); + if (res != dest) + free (res); free (addr); return NULL; } diff --git a/nis/nis_creategroup.c b/nis/nis_creategroup.c index 3786461d64..0e9e13d5e5 100644 --- a/nis/nis_creategroup.c +++ b/nis/nis_creategroup.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999, 2000 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 1999, 2000, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -46,18 +46,24 @@ nis_creategroup (const_nis_name group, unsigned int flags) else return NIS_BADNAME; - obj = malloc (sizeof (nis_object)); + obj = calloc (1, sizeof (nis_object)); if (__builtin_expect (obj == NULL, 0)) return NIS_NOMEMORY; obj->zo_oid.ctime = obj->zo_oid.mtime = time (NULL); obj->zo_name = strdup (leafbuf); - obj->zo_owner = strdup (__nis_default_owner (NULL)); - obj->zo_group = strdup (__nis_default_group (NULL)); + obj->zo_owner = __nis_default_owner (NULL); + obj->zo_group = __nis_default_group (NULL); obj->zo_domain = strdup (domainbuf); if (obj->zo_name == NULL || obj->zo_owner == NULL || obj->zo_group == NULL || obj->zo_domain == NULL) - return NIS_NOMEMORY; + { + free (obj->zo_group); + free (obj->zo_owner); + free (obj->zo_name); + free (obj); + return NIS_NOMEMORY; + } obj->zo_access = __nis_default_access (NULL, 0); obj->zo_ttl = 60 * 60; obj->zo_data.zo_type = NIS_GROUP_OBJ; @@ -66,11 +72,11 @@ nis_creategroup (const_nis_name group, unsigned int flags) obj->zo_data.objdata_u.gr_data.gr_members.gr_members_val = NULL; res = nis_add (buf, obj); + nis_free_object (obj); if (res == NULL) return NIS_NOMEMORY; status = NIS_RES_STATUS (res); nis_freeresult (res); - nis_free_object (obj); return status; } diff --git a/nis/nis_defaults.c b/nis/nis_defaults.c index f13578635a..ed79b59ec6 100644 --- a/nis/nis_defaults.c +++ b/nis/nis_defaults.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 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. @@ -17,6 +17,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -30,45 +31,36 @@ ** Some functions for parsing the -D param and NIS_DEFAULTS Environ */ static nis_name -searchgroup (char *str) +searchXYX (char *str, const char *what) { - char *cptr; - int i; + assert (strlen (what) == 6); + assert (strncmp (str, what, 6) == 0); + str += 6; /* Points to the begin of the parameters. */ + + int i = 0; + while (str[i] != '\0' && str[i] != ':') + ++i; + if (i == 0) /* only "<WHAT>=" ? */ + return strdup (""); - cptr = strstr (str, "group="); - if (cptr == NULL) - return NULL; + return strndup (str, i); +} - cptr += 6; /* points to the begin of the group string */ - i = 0; - while (cptr[i] != '\0' && cptr[i] != ':') - i++; - if (i == 0) /* only "group=" ? */ - return (nis_name) ""; - return strndup (cptr, i); +static nis_name +searchgroup (char *str) +{ + return searchXYX (str, "group="); } + static nis_name searchowner (char *str) { - char *cptr; - int i; - - cptr = strstr (str, "owner="); - if (cptr == NULL) - return NULL; - - cptr += 6; /* points to the begin of the owner string */ - i = 0; - while (cptr[i] != '\0' && cptr[i] != ':') - i++; - if (i == 0) /* only "owner=" ? */ - return strdup (""); - - return strndup (cptr, i); + return searchXYX (str, "owner="); } + static uint32_t searchttl (char *str) { @@ -358,86 +350,61 @@ searchaccess (char *str, unsigned int access) return result; } + nis_name __nis_default_owner (char *defaults) { - char default_owner[NIS_MAXNAMELEN + 1]; - char *cptr, *dptr; + char *default_owner = NULL; - strcpy (default_owner, nis_local_principal ()); + char *cptr = defaults; + if (cptr == NULL) + cptr = getenv ("NIS_DEFAULTS"); - if (defaults != NULL) + if (cptr != NULL) { - dptr = strstr (defaults, "owner="); + char *dptr = strstr (cptr, "owner="); if (dptr != NULL) { - char *p = searchowner (defaults); - if (strlen (p) <= NIS_MAXNAMELEN) - strcpy (default_owner, p); + char *p = searchowner (dptr); + if (p == NULL) + return NULL; + default_owner = strdupa (p); free (p); } } - else - { - cptr = getenv ("NIS_DEFAULTS"); - if (cptr != NULL) - { - dptr = strstr (cptr, "owner="); - if (dptr != NULL) - { - char *p = searchowner (cptr); - if (strlen (p) <= NIS_MAXNAMELEN) - strcpy (default_owner, p); - free (p); - } - } - } - return strdup (default_owner); + return strdup (default_owner ?: nis_local_principal ()); } libnsl_hidden_def (__nis_default_owner) + nis_name __nis_default_group (char *defaults) { - char default_group[NIS_MAXNAMELEN + 1]; - char *cptr, *dptr; + char *default_group = NULL; - strcpy (default_group, nis_local_group ()); + char *cptr = defaults; + if (cptr == NULL) + cptr = getenv ("NIS_DEFAULTS"); - if (defaults != NULL) + if (cptr != NULL) { - dptr = strstr (defaults, "group="); + char *dptr = strstr (cptr, "group="); if (dptr != NULL) { - char *p = searchgroup (defaults); - - if (strlen (p) <= NIS_MAXNAMELEN) - strcpy (default_group, p); + char *p = searchgroup (dptr); + if (p == NULL) + return NULL; + default_group = strdupa (p); free (p); } } - else - { - cptr = getenv ("NIS_DEFAULTS"); - if (cptr != NULL) - { - dptr = strstr (cptr, "group="); - if (dptr != NULL) - { - char *p = searchgroup (cptr); - - if (strlen (p) <= NIS_MAXNAMELEN) - strcpy (default_group, p); - free (p); - } - } - } - return strdup (default_group); + return strdup (default_group ?: nis_local_group ()); } libnsl_hidden_def (__nis_default_group) + uint32_t __nis_default_ttl (char *defaults) { @@ -480,7 +447,7 @@ __nis_default_access (char *param, unsigned int defaults) { cptr = getenv ("NIS_DEFAULTS"); if (cptr != NULL && strstr (cptr, "access=") != NULL) - result = searchaccess (getenv ("NIS_DEFAULTS"), result); + result = searchaccess (cptr, result); } return result; diff --git a/nis/nis_domain_of.c b/nis/nis_domain_of.c index eca2066aa3..4d6b48640e 100644 --- a/nis/nis_domain_of.c +++ b/nis/nis_domain_of.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997 Free Software Foundation, Inc. +/* Copyright (c) 1997, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -26,3 +26,17 @@ nis_domain_of (const_nis_name name) return nis_domain_of_r (name, result, NIS_MAXNAMELEN); } + +const_nis_name +__nis_domain_of (const_nis_name name) +{ + const_nis_name cptr = strchr (name, '.'); + + if (cptr++ == NULL) + return ""; + + if (*cptr == '\0') + return "."; + + return cptr; +} diff --git a/nis/nis_domain_of_r.c b/nis/nis_domain_of_r.c index 1fedcfe074..e2db146038 100644 --- a/nis/nis_domain_of_r.c +++ b/nis/nis_domain_of_r.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -29,6 +29,7 @@ nis_domain_of_r (const_nis_name name, char *buffer, size_t buflen) if (buffer == NULL) { + erange: __set_errno (ERANGE); return NULL; } @@ -44,7 +45,11 @@ nis_domain_of_r (const_nis_name name, char *buffer, size_t buflen) cptr_len = strlen (cptr); if (cptr_len == 0) - return strcpy (buffer, "."); + { + if (buflen < 2) + goto erange; + return strcpy (buffer, "."); + } if (__builtin_expect (cptr_len >= buflen, 0)) { diff --git a/nis/nis_error.c b/nis/nis_error.c index 147f88ce15..d92ad03604 100644 --- a/nis/nis_error.c +++ b/nis/nis_error.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997,1998,1999,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. @@ -24,65 +24,41 @@ #include <rpcsvc/nis.h> -static const char *nis_errlist[] = +#define MF(line) MF1 (line) +#define MF1(line) str##line +static const union msgstr_t { - N_("Success"), - N_("Probable success"), - N_("Not found"), - N_("Probably not found"), - N_("Cache expired"), - N_("NIS+ servers unreachable"), - N_("Unknown object"), - N_("Server busy, try again"), - N_("Generic system error"), - N_("First/next chain broken"), - N_("Permission denied"), - N_("Not owner"), - N_("Name not served by this server"), - N_("Server out of memory"), - N_("Object with same name exists"), - N_("Not master server for this domain"), - N_("Invalid object for operation"), - N_("Malformed name, or illegal name"), - N_("Unable to create callback"), - N_("Results sent to callback proc"), - N_("Not found, no such name"), - N_("Name/entry isn't unique"), - N_("Modification failed"), - N_("Database for table does not exist"), - N_("Entry/table type mismatch"), - N_("Link points to illegal name"), - N_("Partial success"), - N_("Too many attributes"), - N_("Error in RPC subsystem"), - N_("Missing or malformed attribute"), - N_("Named object is not searchable"), - N_("Error while talking to callback proc"), - N_("Non NIS+ namespace encountered"), - N_("Illegal object type for operation"), - N_("Passed object is not the same object on server"), - N_("Modify operation failed"), - N_("Query illegal for named table"), - N_("Attempt to remove a non-empty table"), - N_("Error in accessing NIS+ cold start file. Is NIS+ installed?"), - N_("Full resync required for directory"), - N_("NIS+ operation failed"), - N_("NIS+ service is unavailable or not installed"), - N_("Yes, 42 is the meaning of life"), - N_("Unable to authenticate NIS+ server"), - N_("Unable to authenticate NIS+ client"), - N_("No file space on server"), - N_("Unable to create process on server"), - N_("Master server busy, full dump rescheduled.") -}; + struct + { +#define S(s) char MF(__LINE__)[sizeof (s)]; +#include "nis_error.h" +#undef S + }; + char str[0]; +} msgstr = + { + { +#define S(s) s, +#include "nis_error.h" +#undef S + } + }; + +static const unsigned short int msgidx[] = + { +#define S(s) offsetof (union msgstr_t, MF (__LINE__)), +#include "nis_error.h" +#undef S + }; + const char * nis_sperrno (const nis_error status) { - if (status >= (sizeof (nis_errlist) / sizeof (nis_errlist[0]))) + if (status >= sizeof (msgidx) / sizeof (msgidx[0])) return "???"; else - return gettext (nis_errlist[status]); + return gettext (msgstr.str + msgidx[status]); } libnsl_hidden_def (nis_sperrno) @@ -102,26 +78,21 @@ char * nis_sperror_r (const nis_error status, const char *label, char *buffer, size_t buflen) { - const char *cptr; - - cptr = nis_sperrno (status); - - if ((strlen (cptr) + strlen (label) + 3) > buflen) + if (snprintf (buffer, buflen, "%s: %s", label, nis_sperrno (status)) + >= buflen) { - errno = ERANGE; + __set_errno (ERANGE); return NULL; } - sprintf (buffer, "%s: %s", label, cptr); - - return buffer; + return buffer; } libnsl_hidden_def (nis_sperror_r) char * nis_sperror (const nis_error status, const char *label) { - static char buffer[NIS_MAXNAMELEN +1]; + static char buffer[NIS_MAXNAMELEN + 1]; return nis_sperror_r (status, label, buffer, sizeof (buffer)); } diff --git a/nis/nis_error.h b/nis/nis_error.h new file mode 100644 index 0000000000..add1316d9f --- /dev/null +++ b/nis/nis_error.h @@ -0,0 +1,48 @@ +S(N_("Success")) +S(N_("Probable success")) +S(N_("Not found")) +S(N_("Probably not found")) +S(N_("Cache expired")) +S(N_("NIS+ servers unreachable")) +S(N_("Unknown object")) +S(N_("Server busy, try again")) +S(N_("Generic system error")) +S(N_("First/next chain broken")) +S(N_("Permission denied")) +S(N_("Not owner")) +S(N_("Name not served by this server")) +S(N_("Server out of memory")) +S(N_("Object with same name exists")) +S(N_("Not master server for this domain")) +S(N_("Invalid object for operation")) +S(N_("Malformed name, or illegal name")) +S(N_("Unable to create callback")) +S(N_("Results sent to callback proc")) +S(N_("Not found, no such name")) +S(N_("Name/entry isn't unique")) +S(N_("Modification failed")) +S(N_("Database for table does not exist")) +S(N_("Entry/table type mismatch")) +S(N_("Link points to illegal name")) +S(N_("Partial success")) +S(N_("Too many attributes")) +S(N_("Error in RPC subsystem")) +S(N_("Missing or malformed attribute")) +S(N_("Named object is not searchable")) +S(N_("Error while talking to callback proc")) +S(N_("Non NIS+ namespace encountered")) +S(N_("Illegal object type for operation")) +S(N_("Passed object is not the same object on server")) +S(N_("Modify operation failed")) +S(N_("Query illegal for named table")) +S(N_("Attempt to remove a non-empty table")) +S(N_("Error in accessing NIS+ cold start file. Is NIS+ installed?")) +S(N_("Full resync required for directory")) +S(N_("NIS+ operation failed")) +S(N_("NIS+ service is unavailable or not installed")) +S(N_("Yes, 42 is the meaning of life")) +S(N_("Unable to authenticate NIS+ server")) +S(N_("Unable to authenticate NIS+ client")) +S(N_("No file space on server")) +S(N_("Unable to create process on server")) +S(N_("Master server busy, full dump rescheduled.")) diff --git a/nis/nis_file.c b/nis/nis_file.c index 1f2295787c..566f30c48c 100644 --- a/nis/nis_file.c +++ b/nis/nis_file.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 1999, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -23,27 +23,30 @@ #include <rpcsvc/nis.h> #include "nis_xdr.h" -static const char cold_start_file[] = "/var/nis/NIS_COLD_START"; +typedef bool_t (*iofct_t) (XDR *, void *); +typedef void (*freefct_t) (void *); -directory_obj * -readColdStartFile (void) + +static void * +read_nis_obj (const char *name, iofct_t readfct, freefct_t freefct, + size_t objsize) { - FILE *in = fopen (cold_start_file, "rc"); + FILE *in = fopen (name, "rc"); if (in == NULL) return NULL; - directory_obj *obj = calloc (1, sizeof (directory_obj)); + void *obj = calloc (1, objsize); if (obj != NULL) { XDR xdrs; xdrstdio_create (&xdrs, in, XDR_DECODE); - bool_t status = _xdr_directory_obj (&xdrs, obj); + bool_t status = readfct (&xdrs, obj); xdr_destroy (&xdrs); if (!status) { - nis_free_directory (obj); + freefct (obj); obj = NULL; } } @@ -52,75 +55,49 @@ readColdStartFile (void) return obj; } -libnsl_hidden_def (readColdStartFile) -bool_t -writeColdStartFile (const directory_obj *obj) +static bool_t +write_nis_obj (const char *name, const void *obj, iofct_t writefct) { - XDR xdrs; - FILE *out; - bool_t status; - - out = fopen (cold_start_file, "wb"); + FILE *out = fopen (name, "w"); if (out == NULL) return FALSE; + XDR xdrs; xdrstdio_create (&xdrs, out, XDR_ENCODE); - status = _xdr_directory_obj (&xdrs, (directory_obj *) obj); + bool_t status = writefct (&xdrs, (void *) obj); xdr_destroy (&xdrs); fclose (out); return status; } -nis_object * -nis_read_obj (const char *name) -{ - XDR xdrs; - FILE *in; - bool_t status; - nis_object *obj; - in = fopen (name, "rb"); - if (in == NULL) - return NULL; +static const char cold_start_file[] = "/var/nis/NIS_COLD_START"; - obj = calloc (1, sizeof (nis_object)); - if (obj == NULL) - { - fclose (in); - return NULL; - } +directory_obj * +readColdStartFile (void) +{ + return read_nis_obj (cold_start_file, (iofct_t) _xdr_directory_obj, + (freefct_t) nis_free_directory, sizeof (directory_obj)); +} +libnsl_hidden_def (readColdStartFile) - xdrstdio_create (&xdrs, in, XDR_DECODE); - status =_xdr_nis_object (&xdrs, obj); - xdr_destroy (&xdrs); - fclose (in); +bool_t +writeColdStartFile (const directory_obj *obj) +{ + return write_nis_obj (cold_start_file, obj, (iofct_t) _xdr_directory_obj); +} - if (status) - return obj; - else - { - nis_free_object (obj); - return NULL; - } +nis_object * +nis_read_obj (const char *name) +{ + return read_nis_obj (name, (iofct_t) _xdr_nis_object, + (freefct_t) nis_free_object, sizeof (nis_object)); } bool_t nis_write_obj (const char *name, const nis_object *obj) { - XDR xdrs; - FILE *out; - bool_t status; - - out = fopen (name, "wb"); - if (out == NULL) - return FALSE; - - xdrstdio_create (&xdrs, out, XDR_ENCODE); - status = _xdr_nis_object (&xdrs, (nis_object *) obj); - xdr_destroy (&xdrs); - fclose (out); - - return status; + return write_nis_obj (name, obj, (iofct_t) _xdr_nis_object); } diff --git a/nis/nis_getservlist.c b/nis/nis_getservlist.c index 315960c8e8..e57649d526 100644 --- a/nis/nis_getservlist.c +++ b/nis/nis_getservlist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999, 2000 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 1999, 2000, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -40,7 +40,10 @@ nis_getservlist (const_nis_name dir) malloc (sizeof (nis_server *) * (NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len + 1)); if (__builtin_expect (serv == NULL, 0)) - return NULL; + { + nis_freeresult (res); + return NULL; + } for (i = 0; i < NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len; ++i) @@ -49,13 +52,41 @@ nis_getservlist (const_nis_name dir) &NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val[i]; serv[i] = calloc (1, sizeof (nis_server)); if (__builtin_expect (serv[i] == NULL, 0)) - return NULL; + { + free_all: + while (i-- > 0) + { + free (serv[i]->pkey.n_bytes); + if (serv[i]->ep.ep_val != NULL) + { + unsigned long int j; + for (j = 0; j < serv[i]->ep.ep_len; ++j) + { + free (serv[i]->ep.ep_val[j].proto); + free (serv[i]->ep.ep_val[j].family); + free (serv[i]->ep.ep_val[j].uaddr); + } + free (serv[i]->ep.ep_val); + } + free (serv[i]->name); + free (serv[i]); + } + + free (serv); + + nis_freeresult (res); + + return NULL; + } if (server->name != NULL) { serv[i]->name = strdup (server->name); if (__builtin_expect (serv[i]->name == NULL, 0)) - return NULL; + { + ++i; + goto free_all; + } } serv[i]->ep.ep_len = server->ep.ep_len; @@ -66,7 +97,10 @@ nis_getservlist (const_nis_name dir) serv[i]->ep.ep_val = malloc (server->ep.ep_len * sizeof (endpoint)); if (__builtin_expect (serv[i]->ep.ep_val == NULL, 0)) - return NULL; + { + ++i; + goto free_all; + } for (j = 0; j < serv[i]->ep.ep_len; ++j) { @@ -87,20 +121,20 @@ nis_getservlist (const_nis_name dir) serv[i]->ep.ep_val[j].proto = NULL; } } - else - serv[i]->ep.ep_val = NULL; + serv[i]->key_type = server->key_type; serv[i]->pkey.n_len = server->pkey.n_len; if (server->pkey.n_len > 0) { serv[i]->pkey.n_bytes = malloc (server->pkey.n_len); if (__builtin_expect (serv[i]->pkey.n_bytes == NULL, 0)) - return NULL; + { + ++i; + goto free_all; + } memcpy (serv[i]->pkey.n_bytes, server->pkey.n_bytes, server->pkey.n_len); } - else - serv[i]->pkey.n_bytes = NULL; } serv[i] = NULL; } @@ -111,8 +145,7 @@ nis_getservlist (const_nis_name dir) serv[0] = NULL; } - if (res != NULL) - nis_freeresult (res); + nis_freeresult (res); return serv; } diff --git a/nis/nis_intern.h b/nis/nis_intern.h index 29a80a9188..c805920aec 100644 --- a/nis/nis_intern.h +++ b/nis/nis_intern.h @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. +/* Copyright (c) 1997,1998,1999,2000,2001,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -66,6 +66,7 @@ extern nis_error __do_niscall3 (dir_binding *dbp, u_long prog, xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp, unsigned int flags, nis_cb *cb); +libnsl_hidden_proto (__do_niscall3) extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program, u_long version, u_int protocol); diff --git a/nis/nis_ismember.c b/nis/nis_ismember.c index f3f9bc9540..178b4890ef 100644 --- a/nis/nis_ismember.c +++ b/nis/nis_ismember.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -47,8 +47,7 @@ internal_ismember (const_nis_name principal, const_nis_name group) res = nis_lookup (buf, EXPAND_NAME|FOLLOW_LINKS); if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS) { - if (res) - nis_freeresult (res); + nis_freeresult (res); return 0; } diff --git a/nis/nis_local_names.c b/nis/nis_local_names.c index 30fd208b75..e9aea12a86 100644 --- a/nis/nis_local_names.c +++ b/nis/nis_local_names.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 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. @@ -63,7 +63,7 @@ nis_local_directory (void) __nisdomainname[0] = '\0'; else { - char *cp = strchr (__nisdomainname, '\0'); + char *cp = rawmemchr (__nisdomainname, '\0'); /* Missing trailing dot? */ if (cp[-1] != '.') @@ -154,7 +154,7 @@ nis_local_host (void) __nishostname[0] = '\0'; else { - char *cp = strchr (__nishostname, '\0'); + char *cp = rawmemchr (__nishostname, '\0'); int len = cp - __nishostname; /* Hostname already fully qualified? */ diff --git a/nis/nis_lookup.c b/nis/nis_lookup.c index 0b97e67a61..9677b4d3d1 100644 --- a/nis/nis_lookup.c +++ b/nis/nis_lookup.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1997, 1998, 1999, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1997-1999, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. @@ -21,6 +22,8 @@ #include <rpcsvc/nis.h> #include "nis_xdr.h" #include "nis_intern.h" +#include <libnsl.h> + nis_result * nis_lookup (const_nis_name name, const unsigned int flags) @@ -61,36 +64,16 @@ nis_lookup (const_nis_name name, const unsigned int flags) req.ns_object.ns_object_len = 0; req.ns_object.ns_object_val = NULL; - status = __nisfind_server (req.ns_name, &dir); - if (status != NIS_SUCCESS) + status = __prepare_niscall (req.ns_name, &dir, &bptr, flags); + if (__builtin_expect (status != NIS_SUCCESS, 0)) { NIS_RES_STATUS (res) = status; - return res; - } - - status = __nisbind_create (&bptr, dir->do_servers.do_servers_val, - dir->do_servers.do_servers_len, flags); - if (status != NIS_SUCCESS) - { - NIS_RES_STATUS (res) = status; - nis_free_directory (dir); - return res; - } - - while (__nisbind_connect (&bptr) != NIS_SUCCESS) - { - if (__nisbind_next (&bptr) != NIS_SUCCESS) - { - __nisbind_destroy (&bptr); - nis_free_directory (dir); - NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; - return res; - } + goto out; } do { - static struct timeval RPCTIMEOUT = {10, 0}; + static const struct timeval RPCTIMEOUT = {10, 0}; enum clnt_stat result; again: @@ -107,11 +90,9 @@ nis_lookup (const_nis_name name, const unsigned int flags) if (NIS_RES_STATUS (res) == NIS_SUCCESS) { - if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ && - flags & FOLLOW_LINKS) /* We are following links */ + if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ + && (flags & FOLLOW_LINKS)) /* We are following links */ { - if (count_links) - free (req.ns_name); /* if we hit the link limit, bail */ if (count_links > NIS_MAXLINKS) { @@ -120,55 +101,68 @@ nis_lookup (const_nis_name name, const unsigned int flags) } ++count_links; req.ns_name = - strdup (NIS_RES_OBJECT (res)->LI_data.li_name); - if (req.ns_name == NULL) - return NULL; + strdupa (NIS_RES_OBJECT (res)->LI_data.li_name); - nis_freeresult (res); - res = calloc (1, sizeof (nis_result)); - if (res == NULL) - { - __nisbind_destroy (&bptr); - return NULL; - } + /* The following is a non-obvious optimization. A + nis_freeresult call would call xdr_free as the + following code. But it also would unnecessarily + free the result structure. We avoid this here + along with the necessary tests. */ + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); + memset (res, '\0', sizeof (*res)); link_first_try = 1; /* Try at first the old binding */ goto again; } } else - if ((NIS_RES_STATUS (res) == NIS_SYSTEMERROR) || - (NIS_RES_STATUS (res) == NIS_NOSUCHNAME) || - (NIS_RES_STATUS (res) == NIS_NOT_ME)) + if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR + || NIS_RES_STATUS (res) == NIS_NOSUCHNAME + || NIS_RES_STATUS (res) == NIS_NOT_ME) { if (link_first_try) { __nisbind_destroy (&bptr); nis_free_directory (dir); + /* Otherwise __nisfind_server will not do anything. */ + dir = NULL; - if (__nisfind_server (req.ns_name, &dir) != NIS_SUCCESS) - return res; - - if (__nisbind_create (&bptr, - dir->do_servers.do_servers_val, - dir->do_servers.do_servers_len, - flags) != NIS_SUCCESS) - { - nis_free_directory (dir); - return res; - } + if (__nisfind_server (req.ns_name, 1, &dir, &bptr, + flags & ~MASTER_ONLY) + != NIS_SUCCESS) + goto out; } else if (__nisbind_next (&bptr) != NIS_SUCCESS) - break; /* No more servers to search */ + { + /* No more servers to search. Try parent. */ + const char *ndomain = __nis_domain_of (req.ns_name); + req.ns_name = strdupa (ndomain); + if (strcmp (req.ns_name, ".") == 0) + { + NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; + goto out; + } + + __nisbind_destroy (&bptr); + nis_free_directory (dir); + dir = NULL; + status = __prepare_niscall (req.ns_name, &dir, + &bptr, flags); + if (__builtin_expect (status != NIS_SUCCESS, 0)) + { + NIS_RES_STATUS (res) = status; + goto out; + } + goto again; + } while (__nisbind_connect (&bptr) != NIS_SUCCESS) { if (__nisbind_next (&bptr) != NIS_SUCCESS) { - __nisbind_destroy (&bptr); nis_free_directory (dir); - return res; + goto out; } } goto again; @@ -185,7 +179,7 @@ nis_lookup (const_nis_name name, const unsigned int flags) if (status != NIS_SUCCESS) { NIS_RES_STATUS (res) = status; - return res; + goto out; } switch (NIS_RES_STATUS (res)) @@ -217,6 +211,7 @@ nis_lookup (const_nis_name name, const unsigned int flags) } } + out: if (names != namebuf) nis_freenames (names); diff --git a/nis/nis_ping.c b/nis/nis_ping.c index d9924f9279..81afc5e8e3 100644 --- a/nis/nis_ping.c +++ b/nis/nis_ping.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -39,8 +39,7 @@ nis_ping (const_nis_name dirname, unsigned int utime, res = nis_lookup (dirname, MASTER_ONLY); if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS) { - if (res) - nis_freeresult (res); + nis_freeresult (res); return; } obj = res->objects.objects_val; @@ -51,8 +50,7 @@ nis_ping (const_nis_name dirname, unsigned int utime, /* Check if obj is really a diryectory object */ if (__type_of (obj) != NIS_DIRECTORY_OBJ) { - if (res != NULL) - nis_freeresult (res); + nis_freeresult (res); return; } @@ -68,6 +66,5 @@ nis_ping (const_nis_name dirname, unsigned int utime, NIS_PING, (xdrproc_t) _xdr_ping_args, (caddr_t) &args, (xdrproc_t) xdr_void, (caddr_t) NULL, 0, NULL); - if (res) - nis_freeresult (res); + nis_freeresult (res); } diff --git a/nis/nis_print_group_entry.c b/nis/nis_print_group_entry.c index 6f0ba8fbd4..91e6399b90 100644 --- a/nis/nis_print_group_entry.c +++ b/nis/nis_print_group_entry.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 2000, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 2000, 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. @@ -45,12 +45,16 @@ nis_print_group_entry (const_nis_name group) } res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME); - if (NIS_RES_STATUS(res) != NIS_SUCCESS) + if (res == NULL) return; - if ((NIS_RES_NUMOBJ (res) != 1) || - (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)) - return; + if (NIS_RES_STATUS (res) != NIS_SUCCESS + || NIS_RES_NUMOBJ (res) != 1 + || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ) + { + nis_freeresult (res); + return; + } char *mem_exp[NIS_RES_NUMOBJ (res)]; char *mem_imp[NIS_RES_NUMOBJ (res)]; diff --git a/nis/nis_removemember.c b/nis/nis_removemember.c index b9e27ab48c..2e45b4fb79 100644 --- a/nis/nis_removemember.c +++ b/nis/nis_removemember.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998, 1999, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997,1998,1999,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. @@ -28,15 +28,12 @@ nis_removemember (const_nis_name member, const_nis_name group) { size_t grouplen = strlen (group); char buf[grouplen + 14 + NIS_MAXNAMELEN]; - char leafbuf[grouplen + 2]; char domainbuf[grouplen + 2]; - nis_name *newmem; nis_result *res, *res2; nis_error status; char *cp, *cp2; - unsigned long int i, j, k; - cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1)); + cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0'); cp = stpcpy (cp, ".groups_dir"); cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1); if (cp2 != NULL && cp2[0] != '\0') @@ -44,60 +41,41 @@ nis_removemember (const_nis_name member, const_nis_name group) cp = stpcpy (cp, "."); stpcpy (cp, cp2); } - res = nis_lookup (buf, FOLLOW_LINKS|EXPAND_NAME); - if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS) + res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME); + if (res == NULL) + return NIS_NOMEMORY; + if (NIS_RES_STATUS (res) != NIS_SUCCESS) { - if (res) - { - status = NIS_RES_STATUS (res); - nis_freeresult (res); - } - else - return NIS_NOMEMORY; + status = NIS_RES_STATUS (res); + nis_freeresult (res); return status; } - if ((res->objects.objects_len != 1) || - (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)) + if (NIS_RES_NUMOBJ (res) != 1 + || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ) { nis_freeresult (res); return NIS_INVALIDOBJ; } - newmem = - calloc (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len, - sizeof (char *)); - if (newmem == NULL) - return NIS_NOMEMORY; + nis_name *gr_members_val + = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val; + u_int gr_members_len + = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len; - k = NIS_RES_OBJECT (res)[0].GR_data.gr_members.gr_members_len; - j = 0; - for (i = 0; i < NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len; - ++i) - { - if (strcmp (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i], - member) != 0) - { - newmem[j] = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i]; - ++j; - } - else - { - free (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i]); - --k; - } - } - free (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val); - assert (k <= NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len); - /* This realloc() call always decreases the size. This cannot - fail. We still have the test but do not recover memory - (i.e., we overwrite the input pointer). */ - newmem = realloc (newmem, k * sizeof (char*)); - if (newmem == NULL) - return NIS_NOMEMORY; + u_int j = 0; + for (u_int i = 0; i < gr_members_len; ++i) + if (strcmp (gr_members_val[i], member) != 0) + gr_members_val[j++] = gr_members_val[i]; + else + free (gr_members_val[i]); - NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val = newmem; - NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len = k; + /* There is no need to reallocate the gr_members_val array. We + just adjust the size to match the number of strings still in + it. Yes, xdr_array will use mem_free with a size parameter + but this is mapped to a simple free call which determines the + size of the block by itself. */ + NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len = j; cp = stpcpy (buf, NIS_RES_OBJECT (res)->zo_name); *cp++ = '.'; diff --git a/nis/nis_subr.c b/nis/nis_subr.c index 4c4ef8b5b4..c68189e541 100644 --- a/nis/nis_subr.c +++ b/nis/nis_subr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1999, 2000, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997,1999,2000,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. @@ -39,22 +39,13 @@ nis_leaf_of_r (const_nis_name name, char *buffer, size_t buflen) while (name[i] != '.' && name[i] != '\0') i++; - if (i > buflen - 1) + if (__builtin_expect (i >= buflen, 0)) { __set_errno (ERANGE); return NULL; } - if (i > 0) - { - if ((size_t)i >= buflen) - { - __set_errno (ERANGE); - return NULL; - } - - *((char *) __mempcpy (buffer, name, i)) = '\0'; - } + *((char *) __mempcpy (buffer, name, i)) = '\0'; return buffer; } @@ -98,13 +89,12 @@ nis_name_of_r (const_nis_name name, char *buffer, size_t buflen) } libnsl_hidden_def (nis_name_of_r) -static int +static int __always_inline count_dots (const_nis_name str) { int count = 0; - size_t l = strlen (str); - for (size_t i = 0; i < l; ++i) + for (size_t i = 0; str[i] != '\0'; ++i) if (str[i] == '.') ++count; @@ -117,25 +107,23 @@ count_dots (const_nis_name str) nis_name * nis_getnames (const_nis_name name) { - nis_name *getnames = NULL; - char local_domain[NIS_MAXNAMELEN + 1]; + const char *local_domain = nis_local_directory (); + size_t local_domain_len = strlen (local_domain); + size_t name_len = strlen (name); char *path; - char *cp; - int count; int pos = 0; - int have_point; char *saveptr; + int have_point; + const char *cp; + const char *cp2; - strncpy (local_domain, nis_local_directory (), NIS_MAXNAMELEN); - local_domain[NIS_MAXNAMELEN] = '\0'; - - count = 1; - getnames = malloc ((count + 1) * sizeof (char *)); + int count = 2; + nis_name *getnames = malloc ((count + 1) * sizeof (char *)); if (__builtin_expect (getnames == NULL, 0)) return NULL; /* Do we have a fully qualified NIS+ name ? If yes, give it back */ - if (name[strlen (name) - 1] == '.') + if (name[name_len - 1] == '.') { if ((getnames[0] = strdup (name)) == NULL) { @@ -151,6 +139,44 @@ nis_getnames (const_nis_name name) return getnames; } + /* If the passed NAME is shared a suffix (the latter of course with + a final dot) with each other we pass back NAME with a final + dot. */ + if (local_domain_len > 2) + { + have_point = 0; + cp = &local_domain[local_domain_len - 2]; + cp2 = &name[name_len - 1]; + + while (*cp == *cp2) + { + if (*cp == '.') + have_point = 1; + --cp; + --cp2; + if (cp < local_domain) + { + have_point = cp2 < name || *cp2 == '.'; + break; + } + if (cp2 < name) + { + have_point = *cp == '.'; + break; + } + } + + if (have_point) + { + getnames[0] = malloc (name_len + 2); + if (getnames[0] == NULL) + goto free_null; + + strcpy (stpcpy (getnames[0], name), "."); + ++pos; + } + } + /* Get the search path, where we have to search "name" */ path = getenv ("NIS_PATH"); if (path == NULL) @@ -158,17 +184,17 @@ nis_getnames (const_nis_name name) else path = strdupa (path); - have_point = (strchr (name, '.') != NULL); + have_point = strchr (name, '.') != NULL; cp = __strtok_r (path, ":", &saveptr); while (cp) { if (strcmp (cp, "$") == 0) { - char *cptr = local_domain; + const char *cptr = local_domain; char *tmp; - while ((have_point && *cptr != '\0') || (count_dots (cptr) >= 2)) + while (*cptr != '\0' && count_dots (cptr) >= 2) { if (pos >= count) { @@ -179,8 +205,7 @@ nis_getnames (const_nis_name name) goto free_null; getnames = newp; } - tmp = malloc (strlen (cptr) + strlen (local_domain) + - strlen (name) + 2); + tmp = malloc (strlen (cptr) + local_domain_len + name_len + 2); if (__builtin_expect (tmp == NULL, 0)) goto free_null; @@ -210,7 +235,7 @@ nis_getnames (const_nis_name name) { char *p; - tmp = malloc (cplen + strlen (local_domain) + strlen (name) + 2); + tmp = malloc (cplen + local_domain_len + name_len + 2); if (__builtin_expect (tmp == NULL, 0)) goto free_null; @@ -226,13 +251,16 @@ nis_getnames (const_nis_name name) { char *p; - tmp = malloc (cplen + strlen (name) + 2); + tmp = malloc (cplen + name_len + 3); if (__builtin_expect (tmp == NULL, 0)) goto free_null; - p = __stpcpy (tmp, name); + p = __mempcpy (tmp, name, name_len); *p++ = '.'; - memcpy (p, cp, cplen + 1); + p = __mempcpy (p, cp, cplen); + if (p[-1] != '.') + *p++ = '.'; + *p = '\0'; } if (pos >= count) @@ -250,6 +278,13 @@ nis_getnames (const_nis_name name) cp = __strtok_r (NULL, ":", &saveptr); } + if (pos == 0 + && __asprintf (&getnames[pos++], "%s%s%s%s", + name, name[name_len - 1] == '.' ? "" : ".", + local_domain, + local_domain[local_domain_len - 1] == '.' ? "" : ".") < 0) + goto free_null; + getnames[pos] = NULL; return getnames; diff --git a/nis/nis_table.c b/nis/nis_table.c index 13acdfdf50..70b4701419 100644 --- a/nis/nis_table.c +++ b/nis/nis_table.c @@ -1,4 +1,5 @@ -/* Copyright (c) 1997, 1998, 1999, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (c) 1997-1999, 2003, 2004, 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,21 +18,21 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <assert.h> #include <string.h> #include <rpcsvc/nis.h> #include "nis_xdr.h" #include "nis_intern.h" +#include "libnsl.h" -static struct ib_request * +struct ib_request * __create_ib_request (const_nis_name name, unsigned int flags) { - struct ib_request *ibreq = calloc (1, sizeof (ib_request)); - char buf[strlen (name) + 1]; + struct ib_request *ibreq = calloc (1, sizeof (struct ib_request)); nis_attr *search_val = NULL; size_t search_len = 0; - char *cptr; size_t size = 0; if (ibreq == NULL) @@ -39,18 +40,26 @@ __create_ib_request (const_nis_name name, unsigned int flags) ibreq->ibr_flags = flags; - cptr = strcpy (buf, name); + char *cptr = strdupa (name); /* Not of "[key=value,key=value,...],foo.." format? */ if (cptr[0] != '[') - return (ibreq->ibr_name = strdup (cptr)) == NULL ? NULL : ibreq; + { + ibreq->ibr_name = strdup (cptr); + if (ibreq->ibr_name == NULL) + { + free (ibreq); + return NULL; + } + return ibreq; + } /* "[key=value,...],foo" format */ ibreq->ibr_name = strchr (cptr, ']'); if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',') { - ibreq->ibr_name = NULL; /* Or the xdr_* functions will dump */ - nis_free_request (ibreq); + /* The object has not really been built yet so we use free. */ + free (ibreq); return NULL; } @@ -85,21 +94,22 @@ __create_ib_request (const_nis_name name, unsigned int flags) if (cptr != NULL) *cptr++ = '\0'; - if (!val) + if (__builtin_expect (val == NULL, 0)) { nis_free_request (ibreq); return NULL; } *val++ = '\0'; - if ((search_len + 1) >= size) + if (search_len + 1 >= size) { size += 1; - search_val = realloc (search_val, size * sizeof (nis_attr)); - if (search_val == NULL) + nis_attr *newp = realloc (search_val, size * sizeof (nis_attr)); + if (newp == NULL) goto free_null; + search_val = newp; } search_val[search_len].zattr_ndx = strdup (key); - if ((search_val[search_len].zattr_ndx) == NULL) + if (search_val[search_len].zattr_ndx == NULL) goto free_null; search_val[search_len].zattr_val.zattr_val_len = strlen (val) + 1; @@ -118,18 +128,18 @@ __create_ib_request (const_nis_name name, unsigned int flags) return ibreq; } +libnsl_hidden_def (__create_ib_request) -static struct timeval RPCTIMEOUT = {10, 0}; +static const struct timeval RPCTIMEOUT = {10, 0}; static char * -__get_tablepath (char *name, dir_binding *bptr) +get_tablepath (char *name, dir_binding *bptr) { enum clnt_stat result; - nis_result *res = calloc (1, sizeof (nis_result)); + nis_result res; struct ns_request req; - if (res == NULL) - return NULL; + memset (&res, '\0', sizeof (res)); req.ns_name = name; req.ns_object.ns_object_len = 0; @@ -137,21 +147,54 @@ __get_tablepath (char *name, dir_binding *bptr) result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request, (caddr_t) &req, (xdrproc_t) _xdr_nis_result, - (caddr_t) res, RPCTIMEOUT); + (caddr_t) &res, RPCTIMEOUT); - if (result == RPC_SUCCESS && NIS_RES_STATUS (res) == NIS_SUCCESS && - __type_of (NIS_RES_OBJECT (res)) == NIS_TABLE_OBJ) - { - char *cptr = strdup (NIS_RES_OBJECT (res)->TA_data.ta_path); - nis_freeresult (res); - return cptr; - } + const char *cptr; + if (result == RPC_SUCCESS && NIS_RES_STATUS (&res) == NIS_SUCCESS + && __type_of (NIS_RES_OBJECT (&res)) == NIS_TABLE_OBJ) + cptr = NIS_RES_OBJECT (&res)->TA_data.ta_path; else + cptr = ""; + + char *str = strdup (cptr); + + if (result == RPC_SUCCESS) + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &res); + + return str; +} + + +nis_error +__follow_path (char **tablepath, char **tableptr, struct ib_request *ibreq, + dir_binding *bptr) +{ + if (*tablepath == NULL) { - nis_freeresult (res); - return strdup (""); + *tablepath = get_tablepath (ibreq->ibr_name, bptr); + if (*tablepath == NULL) + return NIS_NOMEMORY; + + *tableptr = *tablepath; } + if (*tableptr == NULL) + return NIS_NOTFOUND; + + char *newname = strsep (tableptr, ":"); + if (newname[0] == '\0') + return NIS_NOTFOUND; + + newname = strdup (newname); + if (newname == NULL) + return NIS_NOMEMORY; + + free (ibreq->ibr_name); + ibreq->ibr_name = newname; + + return NIS_SUCCESS; } +libnsl_hidden_def (__follow_path) + nis_result * nis_list (const_nis_name name, unsigned int flags, @@ -160,7 +203,7 @@ nis_list (const_nis_name name, unsigned int flags, const void *userdata), const void *userdata) { - nis_result *res = calloc (1, sizeof (nis_result)); + nis_result *res = malloc (sizeof (nis_result)); ib_request *ibreq; int status; enum clnt_stat clnt_status; @@ -170,23 +213,29 @@ nis_list (const_nis_name name, unsigned int flags, nis_name namebuf[2] = {NULL, NULL}; int name_nr = 0; nis_cb *cb = NULL; - char *tableptr, *tablepath = NULL; - int have_tablepath = 0; + char *tableptr; + char *tablepath = NULL; int first_try = 0; /* Do we try the old binding at first ? */ + nis_result *allres = NULL; if (res == NULL) return NULL; if (name == NULL) { - NIS_RES_STATUS (res) = NIS_BADNAME; + status = NIS_BADNAME; + err_out: + nis_freeresult (allres); + memset (res, '\0', sizeof (nis_result)); + NIS_RES_STATUS (res) = status; return res; } - if ((ibreq = __create_ib_request (name, flags)) == NULL) + ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) { - NIS_RES_STATUS (res) = NIS_BADNAME; - return res; + status = NIS_BADNAME; + goto err_out; } if ((flags & EXPAND_NAME) @@ -198,15 +247,16 @@ nis_list (const_nis_name name, unsigned int flags, if (names == NULL) { nis_free_request (ibreq); - NIS_RES_STATUS (res) = NIS_BADNAME; - return res; + status = NIS_BADNAME; + goto err_out; } ibreq->ibr_name = strdup (names[name_nr]); if (ibreq->ibr_name == NULL) { + nis_freenames (names); nis_free_request (ibreq); - NIS_RES_STATUS (res) = NIS_NOMEMORY; - return res; + status = NIS_NOMEMORY; + goto err_out; } } else @@ -224,36 +274,25 @@ nis_list (const_nis_name name, unsigned int flags, memset (res, '\0', sizeof (nis_result)); - status = __nisfind_server (ibreq->ibr_name, &dir); + status = __nisfind_server (ibreq->ibr_name, + ibreq->ibr_srch.ibr_srch_val != NULL, + &dir, &bptr, flags & ~MASTER_ONLY); if (status != NIS_SUCCESS) - { - nis_free_request (ibreq); - NIS_RES_STATUS (res) = status; - return res; - } - - status = __nisbind_create (&bptr, dir->do_servers.do_servers_val, - dir->do_servers.do_servers_len, flags); - if (status != NIS_SUCCESS) - { - nis_free_request (ibreq); + { NIS_RES_STATUS (res) = status; - nis_free_directory (dir); - return res; - } + goto fail3; + } while (__nisbind_connect (&bptr) != NIS_SUCCESS) - if (__nisbind_next (&bptr) != NIS_SUCCESS) + if (__builtin_expect (__nisbind_next (&bptr) != NIS_SUCCESS, 0)) { - __nisbind_destroy (&bptr); - nis_free_directory (dir); - nis_free_request (ibreq); NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; - return res; + goto fail; } if (callback != NULL) { + assert (cb == NULL); cb = __nis_create_callback (callback, userdata, flags); ibreq->ibr_cbhost.ibr_cbhost_len = 1; ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv; @@ -265,7 +304,7 @@ nis_list (const_nis_name name, unsigned int flags, (xdrproc_t) _xdr_nis_result, (caddr_t) res, RPCTIMEOUT); - if (clnt_status != RPC_SUCCESS) + if (__builtin_expect (clnt_status != RPC_SUCCESS, 0)) NIS_RES_STATUS (res) = NIS_RPCERROR; else switch (NIS_RES_STATUS (res)) @@ -273,13 +312,13 @@ nis_list (const_nis_name name, unsigned int flags, case NIS_PARTIAL: case NIS_SUCCESS: case NIS_S_SUCCESS: - if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ && - flags & FOLLOW_LINKS) /* We are following links. */ + if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ + && (flags & FOLLOW_LINKS)) /* We are following links. */ { free (ibreq->ibr_name); ibreq->ibr_name = NULL; /* If we hit the link limit, bail. */ - if (count_links > NIS_MAXLINKS) + if (__builtin_expect (count_links > NIS_MAXLINKS, 0)) { NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; ++done; @@ -290,8 +329,22 @@ nis_list (const_nis_name name, unsigned int flags, strdup (NIS_RES_OBJECT (res)->LI_data.li_name); if (ibreq->ibr_name == NULL) { - nis_free_request (ibreq); NIS_RES_STATUS (res) = NIS_NOMEMORY; + fail: + __nisbind_destroy (&bptr); + nis_free_directory (dir); + fail3: + free (tablepath); + if (cb) + { + __nis_destroy_callback (cb); + ibreq->ibr_cbhost.ibr_cbhost_len = 0; + ibreq->ibr_cbhost.ibr_cbhost_val = NULL; + } + if (names != namebuf) + nis_freenames (names); + nis_free_request (ibreq); + nis_freeresult (allres); return res; } if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len) @@ -302,63 +355,88 @@ nis_list (const_nis_name name, unsigned int flags, ibreq->ibr_srch.ibr_srch_val = NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val; } - nis_freeresult (res); - res = calloc (1, sizeof (nis_result)); - if (res == NULL) - { - if (have_tablepath) - free (tablepath); - __nisbind_destroy (&bptr); - nis_free_directory (dir); - return NULL; - } + /* The following is a non-obvious optimization. A + nis_freeresult call would call xdr_free as the + following code. But it also would unnecessarily + free the result structure. We avoid this here + along with the necessary tests. */ + xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res); + memset (res, '\0', sizeof (*res)); first_try = 1; /* Try at first the old binding */ goto again; } - else if ((flags & FOLLOW_PATH) && - NIS_RES_STATUS (res) == NIS_PARTIAL) + else if ((flags & FOLLOW_PATH) + && NIS_RES_STATUS (res) == NIS_PARTIAL) { - if (!have_tablepath) + clnt_status = __follow_path (&tablepath, &tableptr, ibreq, + &bptr); + if (clnt_status != NIS_SUCCESS) { - tablepath = __get_tablepath (ibreq->ibr_name, &bptr); - tableptr = tablepath; - have_tablepath = 1; + NIS_RES_STATUS (res) = clnt_status; + ++done; } - if (tableptr == NULL) + else { - ++done; - break; + /* The following is a non-obvious optimization. A + nis_freeresult call would call xdr_free as the + following code. But it also would unnecessarily + free the result structure. We avoid this here + along with the necessary tests. */ + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); + memset (res, '\0', sizeof (*res)); + first_try = 1; + goto again; } - free (ibreq->ibr_name); - ibreq->ibr_name = strsep (&tableptr, ":"); - if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0') + } + else if ((flags & (FOLLOW_PATH | ALL_RESULTS)) + == (FOLLOW_PATH | ALL_RESULTS)) + { + if (allres == NULL) { - ibreq->ibr_name = strdup (""); - if (ibreq->ibr_name == NULL) + allres = res; + res = malloc (sizeof (nis_result)); + if (res == NULL) { - nis_free_request (ibreq); + res = allres; + allres = NULL; NIS_RES_STATUS (res) = NIS_NOMEMORY; - return res; + goto fail; } - ++done; + NIS_RES_STATUS (res) = NIS_RES_STATUS (allres); } else { - ibreq->ibr_name = strdup (ibreq->ibr_name); - nis_freeresult (res); - res = calloc (1, sizeof (nis_result)); - if (res == NULL || ibreq->ibr_name == NULL) + nis_object *objects_val + = realloc (NIS_RES_OBJECT (allres), + (NIS_RES_NUMOBJ (allres) + + NIS_RES_NUMOBJ (res)) + * sizeof (nis_object)); + if (objects_val == NULL) { - free (res); - nis_free_request (ibreq); - if (have_tablepath) - free (tablepath); - __nisbind_destroy (&bptr); - nis_free_directory (dir); - return NULL; + NIS_RES_STATUS (res) = NIS_NOMEMORY; + goto fail; } - first_try = 1; - goto again; + NIS_RES_OBJECT (allres) = objects_val; + memcpy (NIS_RES_OBJECT (allres) + NIS_RES_NUMOBJ (allres), + NIS_RES_OBJECT (res), + NIS_RES_NUMOBJ (res) * sizeof (nis_object)); + NIS_RES_NUMOBJ (allres) += NIS_RES_NUMOBJ (res); + NIS_RES_NUMOBJ (res) = 0; + free (NIS_RES_OBJECT (res)); + NIS_RES_OBJECT (res) = NULL; + NIS_RES_STATUS (allres) = NIS_RES_STATUS (res); + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); + } + clnt_status = __follow_path (&tablepath, &tableptr, ibreq, + &bptr); + if (clnt_status != NIS_SUCCESS) + { + /* Prepare for the nis_freeresult call. */ + memset (res, '\0', sizeof (*res)); + + if (clnt_status == NIS_NOMEMORY) + NIS_RES_STATUS (allres) = clnt_status; + ++done; } } else @@ -374,32 +452,10 @@ nis_list (const_nis_name name, unsigned int flags, ++done; else { - if (!have_tablepath) - { - tablepath = __get_tablepath (ibreq->ibr_name, &bptr); - tableptr = tablepath; - have_tablepath = 1; - } - if (tableptr == NULL) - { - ++done; - break; - } - free (ibreq->ibr_name); - ibreq->ibr_name = strsep (&tableptr, ":"); - if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0') - { - ibreq->ibr_name = strdup (""); - ++done; - } - else - ibreq->ibr_name = strdup (ibreq->ibr_name); - if (ibreq->ibr_name == NULL) - { - nis_free_request (ibreq); - NIS_RES_STATUS (res) = NIS_NOMEMORY; - return res; - } + NIS_RES_STATUS (res) + = __follow_path (&tablepath, &tableptr, ibreq, &bptr); + if (NIS_RES_STATUS (res) != NIS_SUCCESS) + ++done; } } break; @@ -432,7 +488,7 @@ nis_list (const_nis_name name, unsigned int flags, /* Try the next domainname if we don't follow a link. */ free (ibreq->ibr_name); ibreq->ibr_name = NULL; - if (count_links) + if (__builtin_expect (count_links, 0)) { NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; ++done; @@ -447,9 +503,8 @@ nis_list (const_nis_name name, unsigned int flags, ibreq->ibr_name = strdup (names[name_nr]); if (ibreq->ibr_name == NULL) { - nis_free_request (ibreq); NIS_RES_STATUS (res) = NIS_NOMEMORY; - return res; + goto fail; } first_try = 1; /* Try old binding at first */ goto again; @@ -463,17 +518,26 @@ nis_list (const_nis_name name, unsigned int flags, __nis_destroy_callback (cb); ibreq->ibr_cbhost.ibr_cbhost_len = 0; ibreq->ibr_cbhost.ibr_cbhost_val = NULL; + cb = NULL; } __nisbind_destroy (&bptr); nis_free_directory (dir); } + free (tablepath); + if (names != namebuf) nis_freenames (names); nis_free_request (ibreq); + if (allres) + { + nis_freeresult (res); + return allres; + } + return res; } libnsl_hidden_def (nis_list) @@ -481,15 +545,7 @@ libnsl_hidden_def (nis_list) nis_result * nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags) { - nis_object obj; - nis_result *res; - nis_error status; - ib_request *ibreq; - size_t namelen = strlen (name); - char buf1[namelen + 20]; - char buf4[namelen + 20]; - - res = calloc (1, sizeof (nis_result)); + nis_result *res = calloc (1, sizeof (nis_result)); if (res == NULL) return NULL; @@ -499,14 +555,20 @@ nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags) return res; } - if ((ibreq = __create_ib_request (name, flags)) == NULL) + ib_request *ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) { NIS_RES_STATUS (res) = NIS_BADNAME; return res; } + nis_object obj; memcpy (&obj, obj2, sizeof (nis_object)); + size_t namelen = strlen (name); + char buf1[namelen + 20]; + char buf4[namelen + 20]; + if (obj.zo_name == NULL || strlen (obj.zo_name) == 0) obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1)); @@ -527,11 +589,12 @@ nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags) } ibreq->ibr_obj.ibr_obj_len = 1; - if ((status = __do_niscall (ibreq->ibr_name, NIS_IBADD, - (xdrproc_t) _xdr_ib_request, - (caddr_t) ibreq, - (xdrproc_t) _xdr_nis_result, - (caddr_t) res, 0, NULL)) != NIS_SUCCESS) + nis_error status = __do_niscall (ibreq->ibr_name, NIS_IBADD, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, + (xdrproc_t) _xdr_nis_result, + (caddr_t) res, 0, NULL); + if (__builtin_expect (status != NIS_SUCCESS, 0)) NIS_RES_STATUS (res) = status; nis_free_request (ibreq); @@ -555,7 +618,8 @@ nis_modify_entry (const_nis_name name, const nis_object *obj2, if (res == NULL) return NULL; - if (( ibreq =__create_ib_request (name, flags)) == NULL) + ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) { NIS_RES_STATUS (res) = NIS_BADNAME; return res; @@ -583,10 +647,11 @@ nis_modify_entry (const_nis_name name, const nis_object *obj2, } ibreq->ibr_obj.ibr_obj_len = 1; - if ((status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY, - (xdrproc_t) _xdr_ib_request, - (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, - (caddr_t) res, 0, NULL)) != NIS_SUCCESS) + status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY, + (xdrproc_t) _xdr_ib_request, + (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, 0, NULL); + if (__builtin_expect (status != NIS_SUCCESS, 0)) NIS_RES_STATUS (res) = status; nis_free_request (ibreq); @@ -612,7 +677,8 @@ nis_remove_entry (const_nis_name name, const nis_object *obj, return res; } - if ((ibreq =__create_ib_request (name, flags)) == NULL) + ibreq = __create_ib_request (name, flags); + if (ibreq == NULL) { NIS_RES_STATUS (res) = NIS_BADNAME; return res; @@ -670,7 +736,7 @@ nis_first_entry (const_nis_name name) (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, (caddr_t) res, 0, NULL); - if (status != NIS_SUCCESS) + if (__builtin_expect (status != NIS_SUCCESS, 0)) NIS_RES_STATUS (res) = status; nis_free_request (ibreq); @@ -713,7 +779,7 @@ nis_next_entry (const_nis_name name, const netobj *cookie) (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, (caddr_t) res, 0, NULL); - if (status != NIS_SUCCESS) + if (__builtin_expect (status != NIS_SUCCESS, 0)) NIS_RES_STATUS (res) = status; if (cookie != NULL) diff --git a/nis/nis_xdr.c b/nis/nis_xdr.c index 2a75505b31..0c6452a6a7 100644 --- a/nis/nis_xdr.c +++ b/nis/nis_xdr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 1997, 1998 Free Software Foundation, Inc. +/* Copyright (c) 1997, 1998, 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. @@ -28,383 +28,415 @@ static bool_t xdr_nis_attr (XDR *xdrs, nis_attr *objp) { - if (!xdr_string (xdrs, &objp->zattr_ndx, ~0)) - return FALSE; - if (!xdr_bytes (xdrs, (char **) &objp->zattr_val.zattr_val_val, - (u_int *) & objp->zattr_val.zattr_val_len, ~0)) - return FALSE; - return TRUE; + bool_t res = xdr_string (xdrs, &objp->zattr_ndx, ~0); + if (__builtin_expect (res, TRUE)) + res = xdr_bytes (xdrs, (char **) &objp->zattr_val.zattr_val_val, + &objp->zattr_val.zattr_val_len, ~0); + return res; +} + +static __always_inline bool_t +xdr_nis_name (XDR *xdrs, nis_name *objp) +{ + return xdr_string (xdrs, objp, ~0); } bool_t _xdr_nis_name (XDR *xdrs, nis_name *objp) { - if (!xdr_string (xdrs, objp, ~0)) - return FALSE; - return TRUE; + return xdr_nis_name (xdrs, objp); } -static bool_t +static __always_inline bool_t xdr_zotypes (XDR *xdrs, zotypes *objp) { - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; + return xdr_enum (xdrs, (enum_t *) objp); } -static bool_t +static __always_inline bool_t xdr_nstype (XDR *xdrs, nstype *objp) { - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; + return xdr_enum (xdrs, (enum_t *) objp); } static bool_t xdr_oar_mask (XDR *xdrs, oar_mask *objp) { - if (!xdr_u_int (xdrs, &objp->oa_rights)) - return FALSE; - if (!xdr_zotypes (xdrs, &objp->oa_otype)) - return FALSE; - return TRUE; + bool_t res = xdr_u_int (xdrs, &objp->oa_rights); + if (__builtin_expect (res, TRUE)) + res = xdr_zotypes (xdrs, &objp->oa_otype); + return res; } static bool_t xdr_endpoint (XDR *xdrs, endpoint *objp) { - if (!xdr_string (xdrs, &objp->uaddr, ~0)) - return FALSE; - if (!xdr_string (xdrs, &objp->family, ~0)) - return FALSE; - if (!xdr_string (xdrs, &objp->proto, ~0)) - return FALSE; - return TRUE; + bool_t res = xdr_string (xdrs, &objp->uaddr, ~0); + if (__builtin_expect (res, TRUE)) + { + res = xdr_string (xdrs, &objp->family, ~0); + if (__builtin_expect (res, 1)) + res = xdr_string (xdrs, &objp->proto, ~0); + } + return res; } bool_t _xdr_nis_server (XDR *xdrs, nis_server *objp) { - if (!_xdr_nis_name (xdrs, &objp->name)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->ep.ep_val, (u_int *) &objp->ep.ep_len, - ~0, sizeof (endpoint), (xdrproc_t) xdr_endpoint)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->key_type)) - return FALSE; - if (!xdr_netobj (xdrs, &objp->pkey)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_name (xdrs, &objp->name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (char **) &objp->ep.ep_val, &objp->ep.ep_len, + ~0, sizeof (endpoint), (xdrproc_t) xdr_endpoint); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->key_type); + if (__builtin_expect (res, TRUE)) + res = xdr_netobj (xdrs, &objp->pkey); + } + } + return res; } bool_t _xdr_directory_obj (XDR *xdrs, directory_obj *objp) { - if (!_xdr_nis_name (xdrs, &objp->do_name)) - return FALSE; - if (!xdr_nstype (xdrs, &objp->do_type)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->do_servers.do_servers_val, - (u_int *) & objp->do_servers.do_servers_len, ~0, - sizeof (nis_server), (xdrproc_t) _xdr_nis_server)) - return FALSE; - - if (!xdr_uint32_t (xdrs, &objp->do_ttl)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->do_armask.do_armask_val, - (u_int *) & objp->do_armask.do_armask_len, ~0, - sizeof (oar_mask), (xdrproc_t) xdr_oar_mask)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_name (xdrs, &objp->do_name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nstype (xdrs, &objp->do_type); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (char **) &objp->do_servers.do_servers_val, + &objp->do_servers.do_servers_len, ~0, + sizeof (nis_server), (xdrproc_t) _xdr_nis_server); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->do_ttl); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, + (char **) &objp->do_armask.do_armask_val, + &objp->do_armask.do_armask_len, ~0, + sizeof (oar_mask), (xdrproc_t) xdr_oar_mask); + } + } + } + return res; } static bool_t xdr_entry_col (XDR *xdrs, entry_col *objp) { - if (!xdr_u_int (xdrs, &objp->ec_flags)) - return FALSE; - if (!xdr_bytes (xdrs, (char **) &objp->ec_value.ec_value_val, - (u_int *) &objp->ec_value.ec_value_len, ~0)) - return FALSE; - return TRUE; + bool_t res = xdr_u_int (xdrs, &objp->ec_flags); + if (__builtin_expect (res, TRUE)) + res = xdr_bytes (xdrs, (char **) &objp->ec_value.ec_value_val, + &objp->ec_value.ec_value_len, ~0); + return res; } static bool_t xdr_entry_obj (XDR *xdrs, entry_obj *objp) { - if (!xdr_string (xdrs, &objp->en_type, ~0)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->en_cols.en_cols_val, - (u_int *) &objp->en_cols.en_cols_len, ~0, - sizeof (entry_col), (xdrproc_t) xdr_entry_col)) - return FALSE; - return TRUE; + bool_t res = xdr_string (xdrs, &objp->en_type, ~0); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, (char **) &objp->en_cols.en_cols_val, + &objp->en_cols.en_cols_len, ~0, + sizeof (entry_col), (xdrproc_t) xdr_entry_col); + return res; } static bool_t xdr_group_obj (XDR *xdrs, group_obj *objp) { - if (!xdr_u_int (xdrs, &objp->gr_flags)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->gr_members.gr_members_val, - (u_int *) &objp->gr_members.gr_members_len, ~0, - sizeof (nis_name), (xdrproc_t) _xdr_nis_name)) - return FALSE; - return TRUE; + bool_t res = xdr_u_int (xdrs, &objp->gr_flags); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, (char **) &objp->gr_members.gr_members_val, + &objp->gr_members.gr_members_len, ~0, + sizeof (nis_name), (xdrproc_t) _xdr_nis_name); + return res; } static bool_t xdr_link_obj (XDR *xdrs, link_obj *objp) { - if (!xdr_zotypes (xdrs, &objp->li_rtype)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->li_attrs.li_attrs_val, - (u_int *) &objp->li_attrs.li_attrs_len, ~0, - sizeof (nis_attr), (xdrproc_t) xdr_nis_attr)) - return FALSE; - if (!_xdr_nis_name (xdrs, &objp->li_name)) - return FALSE; - return TRUE; + bool_t res = xdr_zotypes (xdrs, &objp->li_rtype); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (char **) &objp->li_attrs.li_attrs_val, + &objp->li_attrs.li_attrs_len, ~0, + sizeof (nis_attr), (xdrproc_t) xdr_nis_attr); + if (__builtin_expect (res, TRUE)) + res = xdr_nis_name (xdrs, &objp->li_name); + } + return res; } static bool_t xdr_table_col (XDR *xdrs, table_col *objp) { - if (!xdr_string (xdrs, &objp->tc_name, 64)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->tc_flags)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->tc_rights)) - return FALSE; - return TRUE; + bool_t res = xdr_string (xdrs, &objp->tc_name, 64); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->tc_flags); + if (__builtin_expect (res, TRUE)) + res = xdr_u_int (xdrs, &objp->tc_rights); + } + return res; } static bool_t xdr_table_obj (XDR *xdrs, table_obj *objp) { - if (!xdr_string (xdrs, &objp->ta_type, 64)) - return FALSE; - if (!xdr_int (xdrs, &objp->ta_maxcol)) - return FALSE; - if (!xdr_u_char (xdrs, &objp->ta_sep)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->ta_cols.ta_cols_val, - (u_int *) &objp->ta_cols.ta_cols_len, ~0, - sizeof (table_col), (xdrproc_t) xdr_table_col)) - return FALSE; - if (!xdr_string (xdrs, &objp->ta_path, ~0)) - return FALSE; - return TRUE; + bool_t res = xdr_string (xdrs, &objp->ta_type, 64); + if (__builtin_expect (res, TRUE)) + { + res = xdr_int (xdrs, &objp->ta_maxcol); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_char (xdrs, &objp->ta_sep); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (char **) &objp->ta_cols.ta_cols_val, + &objp->ta_cols.ta_cols_len, ~0, + sizeof (table_col), (xdrproc_t) xdr_table_col); + if (__builtin_expect (res, TRUE)) + res = xdr_string (xdrs, &objp->ta_path, ~0); + } + } + } + return res; } static bool_t xdr_objdata (XDR *xdrs, objdata *objp) { - if (!xdr_zotypes (xdrs, &objp->zo_type)) - return FALSE; + bool_t res = xdr_zotypes (xdrs, &objp->zo_type); + if (!__builtin_expect (res, TRUE)) + return res; switch (objp->zo_type) { case NIS_DIRECTORY_OBJ: - if (!_xdr_directory_obj (xdrs, &objp->objdata_u.di_data)) - return FALSE; - break; + return _xdr_directory_obj (xdrs, &objp->objdata_u.di_data); case NIS_GROUP_OBJ: - if (!xdr_group_obj (xdrs, &objp->objdata_u.gr_data)) - return FALSE; - break; + return xdr_group_obj (xdrs, &objp->objdata_u.gr_data); case NIS_TABLE_OBJ: - if (!xdr_table_obj (xdrs, &objp->objdata_u.ta_data)) - return FALSE; - break; + return xdr_table_obj (xdrs, &objp->objdata_u.ta_data); case NIS_ENTRY_OBJ: - if (!xdr_entry_obj (xdrs, &objp->objdata_u.en_data)) - return FALSE; - break; + return xdr_entry_obj (xdrs, &objp->objdata_u.en_data); case NIS_LINK_OBJ: - if (!xdr_link_obj (xdrs, &objp->objdata_u.li_data)) - return FALSE; - break; + return xdr_link_obj (xdrs, &objp->objdata_u.li_data); case NIS_PRIVATE_OBJ: - if (!xdr_bytes (xdrs, (char **) &objp->objdata_u.po_data.po_data_val, - (u_int *) & objp->objdata_u.po_data.po_data_len, ~0)) - return FALSE; - break; + return xdr_bytes (xdrs, &objp->objdata_u.po_data.po_data_val, + &objp->objdata_u.po_data.po_data_len, ~0); case NIS_NO_OBJ: - break; case NIS_BOGUS_OBJ: - break; default: - break; + return TRUE; } - return TRUE; } static bool_t xdr_nis_oid (XDR *xdrs, nis_oid *objp) { - if (!xdr_uint32_t (xdrs, &objp->ctime)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->mtime)) - return FALSE; - return TRUE; + bool_t res = xdr_uint32_t (xdrs, &objp->ctime); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->mtime); + return res; } bool_t _xdr_nis_object (XDR *xdrs, nis_object *objp) { - if (!xdr_nis_oid (xdrs, &objp->zo_oid)) - return FALSE; - if (!_xdr_nis_name (xdrs, &objp->zo_name)) - return FALSE; - if (!_xdr_nis_name (xdrs, &objp->zo_owner)) - return FALSE; - if (!_xdr_nis_name (xdrs, &objp->zo_group)) - return FALSE; - if (!_xdr_nis_name (xdrs, &objp->zo_domain)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->zo_access)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->zo_ttl)) - return FALSE; - if (!xdr_objdata (xdrs, &objp->zo_data)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_oid (xdrs, &objp->zo_oid); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_owner); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_group); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->zo_domain); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->zo_access); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->zo_ttl); + if (__builtin_expect (res, TRUE)) + res = xdr_objdata (xdrs, &objp->zo_data); + } + } + } + } + } + } + return res; +} + +static __always_inline bool_t +xdr_nis_error (XDR *xdrs, nis_error *objp) +{ + return xdr_enum (xdrs, (enum_t *) objp); } bool_t _xdr_nis_error (XDR *xdrs, nis_error *objp) { - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; + return xdr_nis_error (xdrs, objp); } bool_t _xdr_nis_result (XDR *xdrs, nis_result *objp) { - if (!_xdr_nis_error (xdrs, &objp->status)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->objects.objects_val, - (u_int *) &objp->objects.objects_len, ~0, - sizeof (nis_object), (xdrproc_t) _xdr_nis_object)) - return FALSE; - if (!xdr_netobj (xdrs, &objp->cookie)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->zticks)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->dticks)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->aticks)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->cticks)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_error (xdrs, &objp->status); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (char **) &objp->objects.objects_val, + &objp->objects.objects_len, ~0, + sizeof (nis_object), (xdrproc_t) _xdr_nis_object); + if (__builtin_expect (res, TRUE)) + { + res = xdr_netobj (xdrs, &objp->cookie); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->zticks); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->dticks); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->aticks); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->cticks); + } + } + } + } + } + return res; } +libnsl_hidden_def (_xdr_nis_result) bool_t _xdr_ns_request (XDR *xdrs, ns_request *objp) { - if (!_xdr_nis_name (xdrs, &objp->ns_name)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->ns_object.ns_object_val, - (u_int *) &objp->ns_object.ns_object_len, 1, - sizeof (nis_object), (xdrproc_t) _xdr_nis_object)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_name (xdrs, &objp->ns_name); + if (__builtin_expect (res, TRUE)) + res = xdr_array (xdrs, (char **) &objp->ns_object.ns_object_val, + &objp->ns_object.ns_object_len, 1, + sizeof (nis_object), (xdrproc_t) _xdr_nis_object); + return res; } bool_t _xdr_ib_request (XDR *xdrs, ib_request *objp) { - if (!_xdr_nis_name (xdrs, &objp->ibr_name)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->ibr_srch.ibr_srch_val, - (u_int *) &objp->ibr_srch.ibr_srch_len, ~0, - sizeof (nis_attr), (xdrproc_t) xdr_nis_attr)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->ibr_flags)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->ibr_obj.ibr_obj_val, - (u_int *) &objp->ibr_obj.ibr_obj_len, 1, - sizeof (nis_object), (xdrproc_t) _xdr_nis_object)) - return FALSE; - if (!xdr_array (xdrs, (char **) &objp->ibr_cbhost.ibr_cbhost_val, - (u_int *) &objp->ibr_cbhost.ibr_cbhost_len, 1, - sizeof (nis_server), (xdrproc_t) _xdr_nis_server)) - return FALSE; - if (!xdr_u_int (xdrs, &objp->ibr_bufsize)) - return FALSE; - if (!xdr_netobj (xdrs, &objp->ibr_cookie)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_name (xdrs, &objp->ibr_name); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (char **) &objp->ibr_srch.ibr_srch_val, + &objp->ibr_srch.ibr_srch_len, ~0, + sizeof (nis_attr), (xdrproc_t) xdr_nis_attr); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->ibr_flags); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, (char **) &objp->ibr_obj.ibr_obj_val, + &objp->ibr_obj.ibr_obj_len, 1, + sizeof (nis_object), + (xdrproc_t) _xdr_nis_object); + if (__builtin_expect (res, TRUE)) + { + res = xdr_array (xdrs, + (char **) &objp->ibr_cbhost.ibr_cbhost_val, + &objp->ibr_cbhost.ibr_cbhost_len, 1, + sizeof (nis_server), + (xdrproc_t) _xdr_nis_server); + if (__builtin_expect (res, TRUE)) + { + res = xdr_u_int (xdrs, &objp->ibr_bufsize); + if (__builtin_expect (res, TRUE)) + res = xdr_netobj (xdrs, &objp->ibr_cookie); + } + } + } + } + } + return res; } +libnsl_hidden_def (_xdr_ib_request) bool_t _xdr_ping_args (XDR *xdrs, ping_args *objp) { - if (!_xdr_nis_name (xdrs, &objp->dir)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->stamp)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_name (xdrs, &objp->dir); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->stamp); + return res; } bool_t _xdr_cp_result (XDR *xdrs, cp_result *objp) { - if (!_xdr_nis_error (xdrs, &objp->cp_status)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->cp_zticks)) - return FALSE; - if (!xdr_uint32_t (xdrs, &objp->cp_dticks)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_error (xdrs, &objp->cp_status); + if (__builtin_expect (res, TRUE)) + { + res = xdr_uint32_t (xdrs, &objp->cp_zticks); + if (__builtin_expect (res, TRUE)) + res = xdr_uint32_t (xdrs, &objp->cp_dticks); + } + return res; } bool_t _xdr_nis_tag (XDR *xdrs, nis_tag *objp) { - if (!xdr_u_int (xdrs, &objp->tag_type)) - return FALSE; - if (!xdr_string (xdrs, &objp->tag_val, ~0)) - return FALSE; - return TRUE; + bool_t res = xdr_u_int (xdrs, &objp->tag_type); + if (__builtin_expect (res, TRUE)) + res = xdr_string (xdrs, &objp->tag_val, ~0); + return res; } bool_t _xdr_nis_taglist (XDR *xdrs, nis_taglist *objp) { - if (!xdr_array (xdrs, (char **) &objp->tags.tags_val, - (u_int *) &objp->tags.tags_len, ~0, sizeof (nis_tag), - (xdrproc_t) _xdr_nis_tag)) - return FALSE; - return TRUE; + return xdr_array (xdrs, (char **) &objp->tags.tags_val, + &objp->tags.tags_len, ~0, sizeof (nis_tag), + (xdrproc_t) _xdr_nis_tag); } bool_t _xdr_fd_args (XDR *xdrs, fd_args *objp) { - if (!_xdr_nis_name (xdrs, &objp->dir_name)) - return FALSE; - if (!_xdr_nis_name (xdrs, &objp->requester)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_name (xdrs, &objp->dir_name); + if (__builtin_expect (res, TRUE)) + res = xdr_nis_name (xdrs, &objp->requester); + return res; } bool_t _xdr_fd_result (XDR *xdrs, fd_result *objp) { - if (!_xdr_nis_error (xdrs, &objp->status)) - return FALSE; - if (!_xdr_nis_name (xdrs, &objp->source)) - return FALSE; - if (!xdr_bytes (xdrs, (char **) &objp->dir_data.dir_data_val, - (u_int *) &objp->dir_data.dir_data_len, ~0)) - return FALSE; - if (!xdr_bytes (xdrs, (char **) &objp->signature.signature_val, - (u_int *) &objp->signature.signature_len, ~0)) - return FALSE; - return TRUE; + bool_t res = xdr_nis_error (xdrs, &objp->status); + if (__builtin_expect (res, TRUE)) + { + res = xdr_nis_name (xdrs, &objp->source); + if (__builtin_expect (res, TRUE)) + { + res = xdr_bytes (xdrs, (char **) &objp->dir_data.dir_data_val, + &objp->dir_data.dir_data_len, ~0); + if (__builtin_expect (res, TRUE)) + res = xdr_bytes (xdrs, (char **) &objp->signature.signature_val, + &objp->signature.signature_len, ~0); + } + } + return res; } /* The following functions have prototypes in nis_callback.h. So @@ -412,18 +444,16 @@ _xdr_fd_result (XDR *xdrs, fd_result *objp) bool_t xdr_obj_p (XDR *xdrs, obj_p *objp) { - if (!xdr_pointer (xdrs, (char **)objp, sizeof (nis_object), - (xdrproc_t)_xdr_nis_object)) - return FALSE; - return TRUE; + return xdr_pointer (xdrs, (char **)objp, sizeof (nis_object), + (xdrproc_t)_xdr_nis_object); } +libnsl_hidden_def (xdr_obj_p) bool_t xdr_cback_data (XDR *xdrs, cback_data *objp) { - if (!xdr_array (xdrs, (char **)&objp->entries.entries_val, - (u_int *) &objp->entries.entries_len, ~0, - sizeof (obj_p), (xdrproc_t) xdr_obj_p)) - return FALSE; - return TRUE; + return xdr_array (xdrs, (char **)&objp->entries.entries_val, + &objp->entries.entries_len, ~0, + sizeof (obj_p), (xdrproc_t) xdr_obj_p); } +libnsl_hidden_def (xdr_cback_data) diff --git a/nis/nis_xdr.h b/nis/nis_xdr.h index 2f1a179e0a..a59362c78f 100644 --- a/nis/nis_xdr.h +++ b/nis/nis_xdr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 1998, 1999 Free Software Foundation, Inc. +/* Copyright (c) 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. @@ -22,24 +22,23 @@ #include <features.h> -__BEGIN_DECLS +extern bool_t _xdr_nis_attr (XDR *, nis_attr*) attribute_hidden; +extern bool_t _xdr_nis_name (XDR *, nis_name*) attribute_hidden; +extern bool_t _xdr_nis_server (XDR *, nis_server*) attribute_hidden; +extern bool_t _xdr_directory_obj (XDR *, directory_obj*) attribute_hidden; +extern bool_t _xdr_nis_object (XDR *, nis_object*) attribute_hidden; +extern bool_t _xdr_nis_error (XDR *, nis_error*) attribute_hidden; +extern bool_t _xdr_ns_request (XDR *, ns_request*) attribute_hidden; +extern bool_t _xdr_ping_args (XDR *, ping_args*) attribute_hidden; +extern bool_t _xdr_cp_result (XDR *, cp_result*) attribute_hidden; +extern bool_t _xdr_nis_tag (XDR *, nis_tag*) attribute_hidden; +extern bool_t _xdr_nis_taglist (XDR *, nis_taglist*) attribute_hidden; +extern bool_t _xdr_fd_args (XDR *, fd_args*) attribute_hidden; +extern bool_t _xdr_fd_result (XDR *, fd_result*) attribute_hidden; -extern bool_t _xdr_nis_attr (XDR *, nis_attr*); -extern bool_t _xdr_nis_name (XDR *, nis_name*); -extern bool_t _xdr_nis_server (XDR *, nis_server*); -extern bool_t _xdr_directory_obj (XDR *, directory_obj*); -extern bool_t _xdr_nis_object (XDR *, nis_object*); -extern bool_t _xdr_nis_error (XDR *, nis_error*); -extern bool_t _xdr_nis_result (XDR *, nis_result*); -extern bool_t _xdr_ns_request (XDR *, ns_request*); extern bool_t _xdr_ib_request (XDR *, ib_request*); -extern bool_t _xdr_ping_args (XDR *, ping_args*); -extern bool_t _xdr_cp_result (XDR *, cp_result*); -extern bool_t _xdr_nis_tag (XDR *, nis_tag*); -extern bool_t _xdr_nis_taglist (XDR *, nis_taglist*); -extern bool_t _xdr_fd_args (XDR *, fd_args*); -extern bool_t _xdr_fd_result (XDR *, fd_result*); - -__END_DECLS +libnsl_hidden_proto (_xdr_ib_request) +extern bool_t _xdr_nis_result (XDR *, nis_result*); +libnsl_hidden_proto (_xdr_nis_result) #endif diff --git a/nis/nisplus-parser.h b/nis/nisplus-parser.h index f4b8d49596..4dc8db8c9f 100644 --- a/nis/nisplus-parser.h +++ b/nis/nisplus-parser.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1997, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997. @@ -24,15 +24,13 @@ #include <grp.h> #include <shadow.h> -extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *, - char *, size_t, int *); -extern int _nss_nisplus_parse_grent (nis_result *, u_long, struct group *, - char *, size_t, int *); -extern int _nss_nisplus_parse_spent (nis_result *, struct spwd *, - char *, size_t, int *); +extern int _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw, + char *buffer, size_t buflen, int *errnop); -libnss_nisplus_hidden_proto (_nss_nisplus_parse_pwent) -libnss_nisplus_hidden_proto (_nss_nisplus_parse_grent) -libnss_nisplus_hidden_proto (_nss_nisplus_parse_spent) +extern int _nss_nisplus_parse_grent (nis_result *result, struct group *gr, + char *buffer, size_t buflen, int *errnop); + +extern int _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp, + char *buffer, size_t buflen, int *errnop); #endif @@ -1,7 +1,7 @@ # /etc/default/nss # This file can theoretically contain a bunch of customization variables -# for Name Service Switch in the GNU C library. For now there are only two -# variables: +# for Name Service Switch in the GNU C library. For now there are only +# three variables: # # NETID_AUTHORITATIVE # If set to TRUE, the initgroups() function will accept the information @@ -18,3 +18,11 @@ # primary service names and service aliases. The system administrator # has to make sure it is correctly generated. #SERVICES_AUTHORITATIVE=TRUE +# +# SETENT_BATCH_READ +# If set to TRUE, various setXXent() functions will read the entire +# database at once and then hand out the requests one by one from +# memory with every getXXent() call. Otherwise each getXXent() call +# might result into a network communication with the server to get +# the next entry. +SETENT_BATCH_READ=TRUE diff --git a/nis/nss-default.c b/nis/nss-default.c new file mode 100644 index 0000000000..046ddfee8d --- /dev/null +++ b/nis/nss-default.c @@ -0,0 +1,127 @@ +/* Copyright (C) 1996, 2001, 2004, 2006, 2007 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 <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <bits/libc-lock.h> + +#include <libnsl.h> + + +/* Path of the file. */ +static const char default_nss[] = "/etc/default/nss"; + +/* Flags once read from the file. */ +static int default_nss_flags; + +/* Code to make sure we call 'init' once. */ +__libc_once_define (static, once); + +/* Table of the recognized variables. */ +static const struct +{ + char name[23]; + unsigned int len; + int flag; +} vars[] = + { +#define STRNLEN(s) s, sizeof (s) - 1 + { STRNLEN ("NETID_AUTHORITATIVE"), NSS_FLAG_NETID_AUTHORITATIVE }, + { STRNLEN ("SERVICES_AUTHORITATIVE"), NSS_FLAG_SERVICES_AUTHORITATIVE }, + { STRNLEN ("SETENT_BATCH_READ"), NSS_FLAG_SETENT_BATCH_READ } + }; +#define nvars (sizeof (vars) / sizeof (vars[0])) + + +static void +init (void) +{ + int saved_errno = errno; + FILE *fp = fopen (default_nss, "rc"); + if (fp != NULL) + { + char *line = NULL; + size_t linelen = 0; + + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + while (!feof_unlocked (fp)) + { + ssize_t n = getline (&line, &linelen, fp); + if (n <= 0) + break; + + /* Recognize only + + <THE-VARIABLE> = TRUE + + with arbitrary white spaces. */ + char *cp = line; + while (isspace (*cp)) + ++cp; + + /* Recognize comment lines. */ + if (*cp == '#') + continue; + + int idx; + for (idx = 0; idx < nvars; ++idx) + if (strncmp (cp, vars[idx].name, vars[idx].len) == 0) + break; + if (idx == nvars) + continue; + + cp += vars[idx].len; + while (isspace (*cp)) + ++cp; + if (*cp++ != '=') + continue; + while (isspace (*cp)) + ++cp; + + if (strncmp (cp, "TRUE", 4) != 0) + continue; + cp += 4; + + while (isspace (*cp)) + ++cp; + + if (*cp == '\0') + default_nss_flags |= vars[idx].flag; + } + + free (line); + + fclose (fp); + } + __set_errno (saved_errno); +} + + +int +_nsl_default_nss (void) +{ + /* If we have not yet read the file yet do it now. */ + __libc_once (once, init); + + return default_nss_flags; +} diff --git a/nis/nss-nis.c b/nis/nss-nis.c index 40370bae3b..cff1e765bb 100644 --- a/nis/nss-nis.c +++ b/nis/nss-nis.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 2001, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996, 2001, 2004, 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 @@ -16,13 +16,6 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <ctype.h> -#include <stdio.h> -#include <stdio_ext.h> -#include <stdlib.h> -#include <string.h> -#include <rpcsvc/ypclnt.h> - #include "nss-nis.h" #include "nsswitch.h" @@ -50,81 +43,3 @@ const enum nss_status __yperr2nss_tab[] = }; const unsigned int __yperr2nss_count = (sizeof (__yperr2nss_tab) / sizeof (__yperr2nss_tab[0])); - -int _nis_default_nss_flags; - -static const char default_nss[] = "/etc/default/nss"; - -int -_nis_check_default_nss (void) -{ - FILE *fp = fopen (default_nss, "rc"); - int flags = NSS_FLAG_SET; - if (fp != NULL) - { - char *line = NULL; - size_t linelen = 0; - - __fsetlocking (fp, FSETLOCKING_BYCALLER); - - while (!feof_unlocked (fp)) - { - ssize_t n = getline (&line, &linelen, fp); - if (n <= 0) - break; - - /* There currently are only two variables we expect, so - simplify the parsing. Recognize only - - NETID_AUTHORITATIVE = TRUE - SERVICES_AUTHORITATIVE = TRUE - - with arbitrary white spaces. */ - char *cp = line; - while (isspace (*cp)) - ++cp; - - /* Recognize comment lines. */ - if (*cp == '#') - continue; - - static const char netid_authoritative[] = "NETID_AUTHORITATIVE"; - static const char services_authoritative[] - = "SERVICES_AUTHORITATIVE"; - size_t flag_len; - if (strncmp (cp, netid_authoritative, - flag_len = sizeof (netid_authoritative) - 1) != 0 - && strncmp (cp, services_authoritative, - flag_len = sizeof (services_authoritative) - 1) - != 0) - continue; - - cp += flag_len; - while (isspace (*cp)) - ++cp; - if (*cp++ != '=') - continue; - while (isspace (*cp)) - ++cp; - - if (strncmp (cp, "TRUE", 4) != 0) - continue; - cp += 4; - - while (isspace (*cp)) - ++cp; - - if (*cp == '\0') - flags |= flag_len == sizeof (netid_authoritative) - 1 - ? NSS_FLAG_NETID_AUTHORITATIVE - : NSS_FLAG_SERVICES_AUTHORITATIVE; - } - - free (line); - - fclose (fp); - } - - _nis_default_nss_flags = flags; - return flags; -} diff --git a/nis/nss-nis.h b/nis/nss-nis.h index 659b3a14aa..a02583d14c 100644 --- a/nis/nss-nis.h +++ b/nis/nss-nis.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1996, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996, 2004, 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 @@ -25,8 +25,8 @@ /* Convert YP error number to NSS error number. */ -extern const enum nss_status __yperr2nss_tab[]; -extern const unsigned int __yperr2nss_count; +extern const enum nss_status __yperr2nss_tab[] attribute_hidden; +extern const unsigned int __yperr2nss_count attribute_hidden; static inline enum nss_status yperr2nss (int errval) @@ -36,16 +36,24 @@ yperr2nss (int errval) return __yperr2nss_tab[(unsigned int) errval]; } -#define NSS_FLAG_SET 1 -#define NSS_FLAG_NETID_AUTHORITATIVE 2 -#define NSS_FLAG_SERVICES_AUTHORITATIVE 4 -extern int _nis_default_nss_flags attribute_hidden; -extern int _nis_check_default_nss (void) attribute_hidden; -extern inline __attribute__((always_inline)) int -_nis_default_nss (void) +struct response_t { - return _nis_default_nss_flags ?: _nis_check_default_nss (); -} + struct response_t *next; + size_t size; + char mem[0]; +}; + +typedef struct intern_t +{ + struct response_t *start; + struct response_t *next; + size_t offset; +} intern_t; + + +extern int _nis_saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) attribute_hidden; + #endif /* nis/nss-nis.h */ diff --git a/nis/nss-nisplus.h b/nis/nss-nisplus.h index 7235c355b0..ad7f444440 100644 --- a/nis/nss-nisplus.h +++ b/nis/nss-nisplus.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1997 Free Software Foundation, Inc. +/* Copyright (C) 1997, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. @@ -26,8 +26,8 @@ /* Convert NIS+ error number to NSS error number. */ -extern const enum nss_status __niserr2nss_tab[]; -extern const unsigned int __niserr2nss_count; +extern const enum nss_status __niserr2nss_tab[] attribute_hidden; +extern const unsigned int __niserr2nss_count attribute_hidden; static inline enum nss_status niserr2nss (int errval) diff --git a/nis/nss_compat/compat-grp.c b/nis/nss_compat/compat-grp.c index 08bf5d2f80..236c84a20f 100644 --- a/nis/nss_compat/compat-grp.c +++ b/nis/nss_compat/compat-grp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999,2001,2002,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999,2001-2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -59,12 +59,13 @@ struct blacklist_t struct ent_t { bool_t files; + enum nss_status setent_status; FILE *stream; struct blacklist_t blacklist; }; typedef struct ent_t ent_t; -static ent_t ext_ent = {TRUE, NULL, {NULL, 0, 0}}; +static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; /* Protect global state against multiple changers. */ __libc_lock_define_initialized (static, lock) @@ -89,7 +90,7 @@ init_nss_interface (void) } static enum nss_status -internal_setgrent (ent_t *ent, int stayopen) +internal_setgrent (ent_t *ent, int stayopen, int needent) { enum nss_status status = NSS_STATUS_SUCCESS; @@ -137,8 +138,8 @@ internal_setgrent (ent_t *ent, int stayopen) else rewind (ent->stream); - if (status == NSS_STATUS_SUCCESS && nss_setgrent) - return nss_setgrent (stayopen); + if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent) + ent->setent_status = nss_setgrent (stayopen); return status; } @@ -154,7 +155,7 @@ _nss_compat_setgrent (int stayopen) if (ni == NULL) init_nss_interface (); - result = internal_setgrent (&ext_ent, stayopen); + result = internal_setgrent (&ext_ent, stayopen, 1); __libc_lock_unlock (lock); @@ -208,6 +209,10 @@ getgrent_next_nss (struct group *result, ent_t *ent, char *buffer, if (!nss_getgrent_r) return NSS_STATUS_UNAVAIL; + /* If the setgrent call failed, say so. */ + if (ent->setent_status != NSS_STATUS_SUCCESS) + return ent->setent_status; + do { enum nss_status status; @@ -229,9 +234,10 @@ getgrnam_plusgroup (const char *name, struct group *result, ent_t *ent, if (!nss_getgrnam_r) return NSS_STATUS_UNAVAIL; - if (nss_getgrnam_r (name, result, buffer, buflen, errnop) != - NSS_STATUS_SUCCESS) - return NSS_STATUS_NOTFOUND; + enum nss_status status = nss_getgrnam_r (name, result, buffer, buflen, + errnop); + if (status != NSS_STATUS_SUCCESS) + return status; if (in_blacklist (result->gr_name, strlen (result->gr_name), ent)) return NSS_STATUS_NOTFOUND; @@ -358,7 +364,7 @@ _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen, init_nss_interface (); if (ext_ent.stream == NULL) - result = internal_setgrent (&ext_ent, 1); + result = internal_setgrent (&ext_ent, 1, 1); if (result == NSS_STATUS_SUCCESS) { @@ -480,7 +486,7 @@ enum nss_status _nss_compat_getgrnam_r (const char *name, struct group *grp, char *buffer, size_t buflen, int *errnop) { - ent_t ent = {TRUE, NULL, {NULL, 0, 0}}; + ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; enum nss_status result; if (name[0] == '-' || name[0] == '+') @@ -493,7 +499,7 @@ _nss_compat_getgrnam_r (const char *name, struct group *grp, __libc_lock_unlock (lock); - result = internal_setgrent (&ent, 0); + result = internal_setgrent (&ent, 0, 0); if (result == NSS_STATUS_SUCCESS) result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop); @@ -551,7 +557,7 @@ internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, !(parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop))); - if (parse_res == -1) + if (__builtin_expect (parse_res == -1, 0)) /* The parser ran out of space. */ goto erange_reset; @@ -574,13 +580,17 @@ internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, /* +group */ if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') { + /* Yes, no +1, see the memcpy call below. */ + size_t len = strlen (result->gr_name); + char buf[len]; enum nss_status status; /* Store the group in the blacklist for the "+" at the end of /etc/group */ - blacklist_store_name (&result->gr_name[1], ent); + memcpy (buf, &result->gr_name[1], len); status = getgrnam_plusgroup (&result->gr_name[1], result, ent, buffer, buflen, errnop); + blacklist_store_name (buf, ent); if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) break; else @@ -589,9 +599,11 @@ internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, /* +:... */ if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') { - enum nss_status status; + if (!nss_getgrgid_r) + return NSS_STATUS_UNAVAIL; - status = nss_getgrgid_r (gid, result, buffer, buflen, errnop); + enum nss_status status = nss_getgrgid_r (gid, result, buffer, buflen, + errnop); if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ return NSS_STATUS_NOTFOUND; else @@ -606,7 +618,7 @@ enum nss_status _nss_compat_getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t buflen, int *errnop) { - ent_t ent = {TRUE, NULL, {NULL, 0, 0}}; + ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; enum nss_status result; __libc_lock_lock (lock); @@ -616,7 +628,7 @@ _nss_compat_getgrgid_r (gid_t gid, struct group *grp, __libc_lock_unlock (lock); - result = internal_setgrent (&ent, 0); + result = internal_setgrent (&ent, 0, 0); if (result == NSS_STATUS_SUCCESS) result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop); diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c index 9574ea7c0b..70403a0785 100644 --- a/nis/nss_compat/compat-initgroups.c +++ b/nis/nss_compat/compat-initgroups.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1998-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1998-2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. @@ -36,7 +36,6 @@ static service_user *ni; static enum nss_status (*nss_initgroups_dyn) (const char *, gid_t, long int *, long int *, gid_t **, long int, int *); -static enum nss_status (*nss_setgrent) (int stayopen); static enum nss_status (*nss_getgrnam_r) (const char *name, struct group * grp, char *buffer, size_t buflen, int *errnop); @@ -45,7 +44,6 @@ static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, int *errnop); static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, size_t buflen, int *errnop); -static enum nss_status (*nss_endgrent) (void); /* Protect global state against multiple changers. */ __libc_lock_define_initialized (static, lock) @@ -92,11 +90,9 @@ init_nss_interface (void) && __nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) { nss_initgroups_dyn = __nss_lookup_function (ni, "initgroups_dyn"); - nss_setgrent = __nss_lookup_function (ni, "setgrent"); nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); - nss_endgrent = __nss_lookup_function (ni, "endgrent"); } __libc_lock_unlock (lock); diff --git a/nis/nss_compat/compat-pwd.c b/nis/nss_compat/compat-pwd.c index 89a6a7013e..ac132046da 100644 --- a/nis/nss_compat/compat-pwd.c +++ b/nis/nss_compat/compat-pwd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999,2001,2002,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999,2001-2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -62,9 +62,10 @@ struct blacklist_t struct ent_t { - bool_t netgroup; - bool_t first; - bool_t files; + bool netgroup; + bool first; + bool files; + enum nss_status setent_status; FILE *stream; struct blacklist_t blacklist; struct passwd pwd; @@ -72,8 +73,9 @@ struct ent_t }; typedef struct ent_t ent_t; -static ent_t ext_ent = {0, 0, TRUE, NULL, {NULL, 0, 0}, - {NULL, NULL, 0, 0, NULL, NULL, NULL}}; +static ent_t ext_ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, + { NULL, 0, 0 }, + { NULL, NULL, 0, 0, NULL, NULL, NULL }}; /* Protect global state against multiple changers. */ __libc_lock_define_initialized (static, lock) @@ -202,12 +204,13 @@ copy_pwd_changes (struct passwd *dest, struct passwd *src, } static enum nss_status -internal_setpwent (ent_t *ent, int stayopen) +internal_setpwent (ent_t *ent, int stayopen, int needent) { enum nss_status status = NSS_STATUS_SUCCESS; - ent->first = ent->netgroup = FALSE; - ent->files = TRUE; + ent->first = ent->netgroup = false; + ent->files = true; + ent->setent_status = NSS_STATUS_SUCCESS; /* If something was left over free it. */ if (ent->netgroup) @@ -257,8 +260,8 @@ internal_setpwent (ent_t *ent, int stayopen) give_pwd_free (&ent->pwd); - if (status == NSS_STATUS_SUCCESS && nss_setpwent) - return nss_setpwent (stayopen); + if (needent && status == NSS_STATUS_SUCCESS && nss_setpwent) + ent->setent_status = nss_setpwent (stayopen); return status; } @@ -274,7 +277,7 @@ _nss_compat_setpwent (int stayopen) if (ni == NULL) init_nss_interface (); - result = internal_setpwent (&ext_ent, stayopen); + result = internal_setpwent (&ext_ent, stayopen, 1); __libc_lock_unlock (lock); @@ -297,7 +300,7 @@ internal_endpwent (ent_t *ent) if (ent->netgroup) __internal_endnetgrent (&ent->netgrdata); - ent->first = ent->netgroup = FALSE; + ent->first = ent->netgroup = false; if (ent->blacklist.data != NULL) { @@ -344,17 +347,17 @@ getpwent_next_nss_netgr (const char *name, struct passwd *result, ent_t *ent, if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS) { - ent->netgroup = FALSE; - ent->first = FALSE; + ent->netgroup = false; + ent->first = false; give_pwd_free (&ent->pwd); return NSS_STATUS_UNAVAIL; } - if (ent->first == TRUE) + if (ent->first == true) { memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); __internal_setnetgrent (group, &ent->netgrdata); - ent->first = FALSE; + ent->first = false; } while (1) @@ -423,6 +426,10 @@ getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer, if (!nss_getpwent_r) return NSS_STATUS_UNAVAIL; + /* If the setpwent call failed, say so. */ + if (ent->setent_status != NSS_STATUS_SUCCESS) + return ent->setent_status; + p2len = pwd_need_buflen (&ent->pwd); if (p2len > buflen) { @@ -433,7 +440,7 @@ getpwent_next_nss (struct passwd *result, ent_t *ent, char *buffer, buflen -= p2len; if (ent->first) - ent->first = FALSE; + ent->first = false; do { @@ -453,29 +460,27 @@ static enum nss_status getpwnam_plususer (const char *name, struct passwd *result, ent_t *ent, char *buffer, size_t buflen, int *errnop) { - struct passwd pwd; - char *p; - size_t plen; - if (!nss_getpwnam_r) return NSS_STATUS_UNAVAIL; + struct passwd pwd; memset (&pwd, '\0', sizeof (struct passwd)); copy_pwd_changes (&pwd, result, NULL, 0); - plen = pwd_need_buflen (&pwd); + size_t plen = pwd_need_buflen (&pwd); if (plen > buflen) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = buffer + (buflen - plen); + char *p = buffer + (buflen - plen); buflen -= plen; - if (nss_getpwnam_r (name, result, buffer, buflen, errnop) != - NSS_STATUS_SUCCESS) - return NSS_STATUS_NOTFOUND; + enum nss_status status = nss_getpwnam_r (name, result, buffer, buflen, + errnop); + if (status != NSS_STATUS_SUCCESS) + return status; if (in_blacklist (result->pw_name, strlen (result->pw_name), ent)) return NSS_STATUS_NOTFOUND; @@ -568,8 +573,8 @@ getpwent_next_file (struct passwd *result, ent_t *ent, { enum nss_status status; - ent->netgroup = TRUE; - ent->first = TRUE; + ent->netgroup = true; + ent->first = true; copy_pwd_changes (&ent->pwd, result, NULL, 0); status = getpwent_next_nss_netgr (NULL, result, ent, @@ -624,8 +629,8 @@ getpwent_next_file (struct passwd *result, ent_t *ent, /* +:... */ if (result->pw_name[0] == '+' && result->pw_name[1] == '\0') { - ent->files = FALSE; - ent->first = TRUE; + ent->files = false; + ent->first = true; copy_pwd_changes (&ent->pwd, result, NULL, 0); return getpwent_next_nss (result, ent, buffer, buflen, errnop); @@ -673,7 +678,7 @@ _nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, init_nss_interface (); if (ext_ent.stream == NULL) - result = internal_setpwent (&ext_ent, 1); + result = internal_setpwent (&ext_ent, 1, 1); if (result == NSS_STATUS_SUCCESS) result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop); @@ -825,8 +830,8 @@ _nss_compat_getpwnam_r (const char *name, struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status result; - ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0}, - {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, + { NULL, NULL, 0, 0, NULL, NULL, NULL }}; if (name[0] == '-' || name[0] == '+') return NSS_STATUS_NOTFOUND; @@ -838,7 +843,7 @@ _nss_compat_getpwnam_r (const char *name, struct passwd *pwd, __libc_lock_unlock (lock); - result = internal_setpwent (&ent, 0); + result = internal_setpwent (&ent, 0, 0); if (result == NSS_STATUS_SUCCESS) result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop); @@ -1067,8 +1072,8 @@ _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status result; - ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0}, - {NULL, NULL, 0, 0, NULL, NULL, NULL}}; + ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }, + { NULL, NULL, 0, 0, NULL, NULL, NULL }}; __libc_lock_lock (lock); @@ -1077,7 +1082,7 @@ _nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd, __libc_lock_unlock (lock); - result = internal_setpwent (&ent, 0); + result = internal_setpwent (&ent, 0, 0); if (result == NSS_STATUS_SUCCESS) result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop); @@ -1134,7 +1139,7 @@ blacklist_store_name (const char *name, ent_t *ent) return; } -/* returns TRUE if ent->blacklist contains name, else FALSE */ +/* Returns TRUE if ent->blacklist contains name, else FALSE. */ static bool_t in_blacklist (const char *name, int namelen, ent_t *ent) { diff --git a/nis/nss_compat/compat-spwd.c b/nis/nss_compat/compat-spwd.c index 4ca6368139..d1de3f75b0 100644 --- a/nis/nss_compat/compat-spwd.c +++ b/nis/nss_compat/compat-spwd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999,2001,2002,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999,2001-2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -59,9 +59,10 @@ struct blacklist_t struct ent_t { - bool_t netgroup; - bool_t files; - bool_t first; + bool netgroup; + bool files; + bool first; + enum nss_status setent_status; FILE *stream; struct blacklist_t blacklist; struct spwd pwd; @@ -69,8 +70,9 @@ struct ent_t }; typedef struct ent_t ent_t; -static ent_t ext_ent = {0, TRUE, 0, NULL, {NULL, 0, 0}, - {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; +static ent_t ext_ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, + { NULL, 0, 0}, + { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; /* Protect global state against multiple changers. */ __libc_lock_define_initialized (static, lock) @@ -161,7 +163,7 @@ internal_setspent (ent_t *ent, int stayopen) enum nss_status status = NSS_STATUS_SUCCESS; ent->first = ent->netgroup = 0; - ent->files = TRUE; + ent->files = true; /* If something was left over free it. */ if (ent->netgroup) @@ -212,7 +214,7 @@ internal_setspent (ent_t *ent, int stayopen) give_spwd_free (&ent->pwd); if (status == NSS_STATUS_SUCCESS && nss_setspent) - return nss_setspent (stayopen); + ent->setent_status = nss_setspent (stayopen); return status; } @@ -251,8 +253,8 @@ internal_endspent (ent_t *ent) if (ent->netgroup) __internal_endnetgrent (&ent->netgrdata); - ent->first = ent->netgroup = FALSE; - ent->files = TRUE; + ent->first = ent->netgroup = false; + ent->files = true; if (ent->blacklist.data != NULL) { @@ -294,19 +296,23 @@ getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent, if (!nss_getspnam_r) return NSS_STATUS_UNAVAIL; + /* If the setpwent call failed, say so. */ + if (ent->setent_status != NSS_STATUS_SUCCESS) + return ent->setent_status; + if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS) { - ent->netgroup = FALSE; - ent->first = FALSE; + ent->netgroup = false; + ent->first = false; give_spwd_free (&ent->pwd); return NSS_STATUS_UNAVAIL; } - if (ent->first == TRUE) + if (ent->first == true) { memset (&ent->netgrdata, 0, sizeof (struct __netgrent)); __internal_setnetgrent (group, &ent->netgrdata); - ent->first = FALSE; + ent->first = false; } while (1) @@ -321,7 +327,7 @@ getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent, if (status != 1) { __internal_endnetgrent (&ent->netgrdata); - ent->netgroup = FALSE; + ent->netgroup = false; give_spwd_free (&ent->pwd); return NSS_STATUS_RETURN; } @@ -396,18 +402,16 @@ getspent_next_nss (struct spwd *result, ent_t *ent, return NSS_STATUS_SUCCESS; } + /* This function handle the +user entrys in /etc/shadow */ static enum nss_status getspnam_plususer (const char *name, struct spwd *result, ent_t *ent, char *buffer, size_t buflen, int *errnop) { - struct spwd pwd; - char *p; - size_t plen; - if (!nss_getspnam_r) return NSS_STATUS_UNAVAIL; + struct spwd pwd; memset (&pwd, '\0', sizeof (struct spwd)); pwd.sp_warn = -1; pwd.sp_inact = -1; @@ -416,18 +420,19 @@ getspnam_plususer (const char *name, struct spwd *result, ent_t *ent, copy_spwd_changes (&pwd, result, NULL, 0); - plen = spwd_need_buflen (&pwd); + size_t plen = spwd_need_buflen (&pwd); if (plen > buflen) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = buffer + (buflen - plen); + char *p = buffer + (buflen - plen); buflen -= plen; - if (nss_getspnam_r (name, result, buffer, buflen, errnop) != - NSS_STATUS_SUCCESS) - return NSS_STATUS_NOTFOUND; + enum nss_status status = nss_getspnam_r (name, result, buffer, buflen, + errnop); + if (status != NSS_STATUS_SUCCESS) + return status; if (in_blacklist (result->sp_namp, strlen (result->sp_namp), ent)) return NSS_STATUS_NOTFOUND; @@ -438,6 +443,7 @@ getspnam_plususer (const char *name, struct spwd *result, ent_t *ent, return NSS_STATUS_SUCCESS; } + static enum nss_status getspent_next_file (struct spwd *result, ent_t *ent, char *buffer, size_t buflen, int *errnop) @@ -518,8 +524,8 @@ getspent_next_file (struct spwd *result, ent_t *ent, { int status; - ent->netgroup = TRUE; - ent->first = TRUE; + ent->netgroup = true; + ent->first = true; copy_spwd_changes (&ent->pwd, result, NULL, 0); status = getspent_next_nss_netgr (NULL, result, ent, @@ -575,8 +581,8 @@ getspent_next_file (struct spwd *result, ent_t *ent, /* +:... */ if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0') { - ent->files = FALSE; - ent->first = TRUE; + ent->files = false; + ent->first = true; copy_spwd_changes (&ent->pwd, result, NULL, 0); return getspent_next_nss (result, ent, buffer, buflen, errnop); @@ -611,6 +617,7 @@ internal_getspent_r (struct spwd *pw, ent_t *ent, return getspent_next_nss (pw, ent, buffer, buflen, errnop); } + enum nss_status _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen, int *errnop) @@ -634,6 +641,7 @@ _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen, return result; } + /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */ static enum nss_status internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent, @@ -776,13 +784,14 @@ internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent, return NSS_STATUS_SUCCESS; } + enum nss_status _nss_compat_getspnam_r (const char *name, struct spwd *pwd, char *buffer, size_t buflen, int *errnop) { enum nss_status result; - ent_t ent = {0, TRUE, 0, NULL, {NULL, 0, 0}, - {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; + ent_t ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0}, + { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}}; if (name[0] == '-' || name[0] == '+') return NSS_STATUS_NOTFOUND; @@ -804,6 +813,7 @@ _nss_compat_getspnam_r (const char *name, struct spwd *pwd, return result; } + /* Support routines for remembering -@netgroup and -user entries. The names are stored in a single string with `|' as separator. */ static void @@ -850,6 +860,7 @@ blacklist_store_name (const char *name, ent_t *ent) return; } + /* Returns TRUE if ent->blacklist contains name, else FALSE. */ static bool_t in_blacklist (const char *name, int namelen, ent_t *ent) @@ -858,7 +869,7 @@ in_blacklist (const char *name, int namelen, ent_t *ent) char *cp; if (ent->blacklist.data == NULL) - return FALSE; + return false; buf[0] = '|'; cp = stpcpy (&buf[1], name); diff --git a/nis/nss_nis/nis-alias.c b/nis/nss_nis/nis-alias.c index 3b0887be04..9286e36ba6 100644 --- a/nis/nss_nis/nis-alias.c +++ b/nis/nss_nis/nis-alias.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1996-2002, 2003, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -125,52 +125,53 @@ internal_nis_getaliasent_r (struct aliasent *alias, char *buffer, size_t buflen, int *errnop) { char *domain; - char *result; - int len; - char *outkey; - int keylen; - char *p; - int parse_res; - if (yp_get_default_domain (&domain)) + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; alias->alias_local = 0; /* Get the next entry until we found a correct one. */ + int parse_res; do { - enum nss_status retval; + char *result; + int len; + char *outkey; + int keylen; + int yperr; if (new_start) - retval = yperr2nss (yp_first (domain, "mail.aliases", - &outkey, &keylen, &result, &len)); + yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result, + &len); else - retval = yperr2nss ( yp_next (domain, "mail.aliases", oldkey, - oldkeylen, &outkey, &keylen, - &result, &len)); - if (retval != NSS_STATUS_SUCCESS) + yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, buflen, - errnop); - if (parse_res == -1) + parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, + buflen, errnop); + if (__builtin_expect (parse_res == -1, 0)) { free (outkey); *errnop = ERANGE; @@ -206,56 +207,55 @@ enum nss_status _nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias, char *buffer, size_t buflen, int *errnop) { - enum nss_status retval; - int parse_res; - char *domain; - char *result; - int len; - char *p; - size_t namlen = strlen (name); - char name2[namlen + 1]; - size_t i; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + size_t namlen = strlen (name); + char name2[namlen + 1]; + + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* Convert name to lowercase. */ + size_t i; for (i = 0; i < namlen; ++i) name2[i] = _tolower (name[i]); name2[i] = '\0'; - retval = yperr2nss (yp_match (domain, "mail.aliases", name2, namlen, - &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); alias->alias_local = 0; - parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; diff --git a/nis/nss_nis/nis-ethers.c b/nis/nss_nis/nis-ethers.c index def4c22510..a3064282ab 100644 --- a/nis/nss_nis/nis-ethers.c +++ b/nis/nss_nis/nis-ethers.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -182,45 +182,46 @@ enum nss_status _nss_nis_gethostton_r (const char *name, struct etherent *eth, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, parse_res; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - retval = yperr2nss (yp_match (domain, "ethers.byname", name, - strlen (name), &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "ethers.byname", name, strlen (name), &result, + &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; @@ -234,54 +235,54 @@ enum nss_status _nss_nis_getntohost_r (const struct ether_addr *addr, struct etherent *eth, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, nlen, parse_res; - char buf[33]; - if (addr == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - nlen = sprintf (buf, "%x:%x:%x:%x:%x:%x", - (int) addr->ether_addr_octet[0], - (int) addr->ether_addr_octet[1], - (int) addr->ether_addr_octet[2], - (int) addr->ether_addr_octet[3], - (int) addr->ether_addr_octet[4], - (int) addr->ether_addr_octet[5]); - - retval = yperr2nss (yp_match (domain, "ethers.byaddr", buf, - nlen, &result, &len)); - - if (retval != NSS_STATUS_SUCCESS) + char buf[33]; + int nlen = snprintf (buf, sizeof (buf), "%x:%x:%x:%x:%x:%x", + (int) addr->ether_addr_octet[0], + (int) addr->ether_addr_octet[1], + (int) addr->ether_addr_octet[2], + (int) addr->ether_addr_octet[3], + (int) addr->ether_addr_octet[4], + (int) addr->ether_addr_octet[5]); + + char *result; + int len; + int yperr = yp_match (domain, "ethers.byaddr", buf, nlen, &result, &len); + + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; diff --git a/nis/nss_nis/nis-grp.c b/nis/nss_nis/nis-grp.c index 8be7332515..6e36cf828f 100644 --- a/nis/nss_nis/nis-grp.c +++ b/nis/nss_nis/nis-grp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999, 2001-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999, 2001-2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -17,20 +17,17 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -/* The following is an ugly trick to avoid a prototype declaration for - _nss_nis_endgrent. */ -#define _nss_nis_endgrent _nss_nis_endgrent_XXX -#include <grp.h> -#undef _nss_nis_endgrent #include <ctype.h> #include <errno.h> +#include <grp.h> +#include <nss.h> #include <string.h> #include <bits/libc-lock.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> #include "nss-nis.h" +#include <libnsl.h> /* Get the declaration of the parser function. */ #define ENTNAME grent @@ -44,12 +41,12 @@ __libc_lock_define_initialized (static, lock) static bool_t new_start = 1; static char *oldkey; static int oldkeylen; +static intern_t intern; -enum nss_status -_nss_nis_setgrent (int stayopen) -{ - __libc_lock_lock (lock); +static void +internal_nis_endgrent (void) +{ new_start = 1; if (oldkey != NULL) { @@ -58,72 +55,186 @@ _nss_nis_setgrent (int stayopen) oldkeylen = 0; } + struct response_t *curr = intern.next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endgrent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endgrent (); + __libc_lock_unlock (lock); return NSS_STATUS_SUCCESS; } -/* Make _nss_nis_endgrent an alias of _nss_nis_setgrent. We do this - even though the prototypes don't match. The argument of setgrent - is not used so this makes no difference. */ -strong_alias (_nss_nis_setgrent, _nss_nis_endgrent) + + +enum nss_status +internal_nis_setgrent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "group.byname", &ypcb)); + + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + + +enum nss_status +_nss_nis_setgrent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endgrent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setgrent (); + + __libc_lock_unlock (lock); + + return result; +} + static enum nss_status internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - char *domain, *result, *outkey; - int len, keylen, parse_res; + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; - if (yp_get_default_domain (&domain)) + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* Get the next entry until we found a correct one. */ + int parse_res; do { - enum nss_status retval; - char *p; + char *result; + char *outkey; + int len; + int keylen; - if (new_start) - retval = yperr2nss (yp_first (domain, "group.byname", - &outkey, &keylen, &result, &len)); - else - retval = yperr2nss ( yp_next (domain, "group.byname", - oldkey, oldkeylen, - &outkey, &keylen, &result, &len)); + if (batch_read) + { + struct response_t *bucket; - if (retval != NSS_STATUS_SUCCESS) - { - if (retval == NSS_STATUS_TRYAGAIN) - *errnop = errno; - return retval; - } + handle_batch_read: + bucket = intern.next; + + if (__builtin_expect (intern.offset >= bucket->size, 0)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } - if ((size_t) (len + 1) > buflen) + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } + else + { + int yperr; + + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setgrent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "group.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "group.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); + + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } + + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; - free (result); + if (!batch_read) + free (result); - parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop); - if (parse_res == -1) + parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res == -1, 0)) { - free (outkey); + if (!batch_read) + free (outkey); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - free (oldkey); - oldkey = outkey; - oldkeylen = keylen; - new_start = 0; + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } } while (parse_res < 1); @@ -149,45 +260,46 @@ enum nss_status _nss_nis_getgrnam_r (const char *name, struct group *grp, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, parse_res; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - retval = yperr2nss (yp_match (domain, "group.byname", name, - strlen (name), &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "group.byname", name, strlen (name), &result, + &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; @@ -201,42 +313,42 @@ enum nss_status _nss_nis_getgrgid_r (gid_t gid, struct group *grp, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, nlen, parse_res; - char buf[32]; - - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - nlen = sprintf (buf, "%lu", (unsigned long int) gid); + char buf[32]; + int nlen = sprintf (buf, "%lu", (unsigned long int) gid); - retval = yperr2nss (yp_match (domain, "group.bygid", buf, - nlen, &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "group.bygid", buf, nlen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; diff --git a/nis/nss_nis/nis-hosts.c b/nis/nss_nis/nis-hosts.c index 58a9064f14..bde0a3291f 100644 --- a/nis/nss_nis/nis-hosts.c +++ b/nis/nss_nis/nis-hosts.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-2000, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -131,39 +131,42 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer, int af, int flags) { char *domain; - char *result; - int len, parse_res; - char *outkey; - int keylen; - struct parser_data *data = (void *) buffer; - size_t linebuflen = buffer + buflen - data->linebuffer; - - if (yp_get_default_domain (&domain)) + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - if (buflen < sizeof *data + 1) + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + if (__builtin_expect (buflen < sizeof *data + 1 + pad, 0)) { *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } + buflen -= pad; /* Get the next entry until we found a correct one. */ + const size_t linebuflen = buffer + buflen - data->linebuffer; + int parse_res; do { - enum nss_status retval; - char *p; - + char *result; + int len; + char *outkey; + int keylen; + int yperr; if (new_start) - retval = yperr2nss (yp_first (domain, "hosts.byname", - &outkey, &keylen, &result, &len)); + yperr = yp_first (domain, "hosts.byname", &outkey, &keylen, &result, + &len); else - retval = yperr2nss ( yp_next (domain, "hosts.byname", - oldkey, oldkeylen, - &outkey, &keylen, &result, &len)); + yperr = yp_next (domain, "hosts.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + switch (retval) { case NSS_STATUS_TRYAGAIN: @@ -180,7 +183,7 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer, return retval; } - if ((size_t) (len + 1) > linebuflen) + if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0)) { free (result); *h_errnop = NETDB_INTERNAL; @@ -188,14 +191,14 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer, return NSS_STATUS_TRYAGAIN; } - p = strncpy (data->linebuffer, result, len); + char *p = strncpy (data->linebuffer, result, len); data->linebuffer[len] = '\0'; while (isspace (*p)) ++p; free (result); parse_res = parse_line (p, host, data, buflen, errnop, af, flags); - if (parse_res == -1) + if (__builtin_expect (parse_res == -1, 0)) { free (outkey); *h_errnop = NETDB_INTERNAL; @@ -235,11 +238,10 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, int *h_errnop, int flags) { - enum nss_status retval; - char *domain, *result, *p; - int len, parse_res; + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + struct parser_data *data = (void *) buffer; - size_t linebuflen = buffer + buflen - data->linebuffer; if (name == NULL) { @@ -247,33 +249,35 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return NSS_STATUS_UNAVAIL; } + char *domain; if (yp_get_default_domain (&domain)) return NSS_STATUS_UNAVAIL; - if (buflen < sizeof *data + 1) + if (buflen < sizeof *data + 1 + pad) { *h_errnop = NETDB_INTERNAL; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - else - { - /* Convert name to lowercase. */ - size_t namlen = strlen (name); - char name2[namlen + 1]; - size_t i; + buflen -= pad; - for (i = 0; i < namlen; ++i) - name2[i] = tolower (name[i]); - name2[i] = '\0'; + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + char name2[namlen + 1]; + size_t i; - retval = yperr2nss (yp_match (domain, "hosts.byname", name2, - namlen, &result, &len)); + for (i = 0; i < namlen; ++i) + name2[i] = tolower (name[i]); + name2[i] = '\0'; - } + char *result; + int len; + int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) { *h_errnop = TRY_AGAIN; @@ -284,7 +288,8 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return retval; } - if ((size_t) (len + 1) > linebuflen) + const size_t linebuflen = buffer + buflen - data->linebuffer; + if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0)) { free (result); *h_errnop = NETDB_INTERNAL; @@ -292,15 +297,15 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host, return NSS_STATUS_TRYAGAIN; } - p = strncpy (data->linebuffer, result, len); + char *p = strncpy (data->linebuffer, result, len); data->linebuffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = parse_line (p, host, data, buflen, errnop, af, flags); + int parse_res = parse_line (p, host, data, buflen, errnop, af, flags); - if (parse_res < 1 || host->h_addrtype != af) + if (__builtin_expect (parse_res < 1 || host->h_addrtype != af, 0)) { if (parse_res == -1) { @@ -351,42 +356,46 @@ _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, struct hostent *host, char *buffer, size_t buflen, int *errnop, int *h_errnop) { - enum nss_status retval; - char *domain, *result, *p; - int len, parse_res; - char *buf; - struct parser_data *data = (void *) buffer; - size_t linebuflen = buffer + buflen - data->linebuffer; - - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - if (buflen < sizeof *data + 1) + uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct parser_data); + buffer += pad; + + struct parser_data *data = (void *) buffer; + if (__builtin_expect (buflen < sizeof *data + 1 + pad, 0)) { *errnop = ERANGE; *h_errnop = NETDB_INTERNAL; return NSS_STATUS_TRYAGAIN; } + buflen -= pad; - buf = inet_ntoa (*(const struct in_addr *) addr); + char *buf = inet_ntoa (*(const struct in_addr *) addr); - retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf, - strlen (buf), &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "hosts.byaddr", buf, strlen (buf), &result, + &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) { *h_errnop = TRY_AGAIN; *errnop = errno; } - if (retval == NSS_STATUS_NOTFOUND) + else if (retval == NSS_STATUS_NOTFOUND) *h_errnop = HOST_NOT_FOUND; return retval; } - if ((size_t) (len + 1) > linebuflen) + const size_t linebuflen = buffer + buflen - data->linebuffer; + if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0)) { free (result); *errnop = ERANGE; @@ -394,15 +403,16 @@ _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af, return NSS_STATUS_TRYAGAIN; } - p = strncpy (data->linebuffer, result, len); + char *p = strncpy (data->linebuffer, result, len); data->linebuffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = parse_line (p, host, data, buflen, errnop, af, - ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)); - if (parse_res < 1) + int parse_res = parse_line (p, host, data, buflen, errnop, af, + ((_res.options & RES_USE_INET6) + ? AI_V4MAPPED : 0)); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) { diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c index 33a9662b4c..a5a3ba6144 100644 --- a/nis/nss_nis/nis-initgroups.c +++ b/nis/nss_nis/nis-initgroups.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1998-2000, 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1998-2000,2002,2003,2004,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. @@ -30,6 +30,7 @@ #include <sys/param.h> #include "nss-nis.h" +#include <libnsl.h> /* Get the declaration of the parser function. */ #define ENTNAME grent @@ -37,47 +38,6 @@ #define EXTERN_PARSER #include <nss/nss_files/files-parse.c> -struct response_t -{ - struct response_t *next; - char val[0]; -}; - -struct intern_t -{ - struct response_t *start; - struct response_t *next; -}; -typedef struct intern_t intern_t; - -static int -saveit (int instatus, char *inkey, int inkeylen, char *inval, - int invallen, char *indata) -{ - intern_t *intern = (intern_t *) indata; - - if (instatus != YP_TRUE) - return 1; - - if (inkey && inkeylen > 0 && inval && invallen > 0) - { - struct response_t *newp = malloc (sizeof (struct response_t) - + invallen + 1); - if (newp == NULL) - return 1; /* We have no error code for out of memory */ - - if (intern->start == NULL) - intern->start = newp; - else - intern->next->next = newp; - intern->next = newp; - - newp->next = NULL; - *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; - } - - return 0; -} static enum nss_status internal_setgrent (char *domainname, intern_t *intern) @@ -85,41 +45,72 @@ internal_setgrent (char *domainname, intern_t *intern) struct ypall_callback ypcb; enum nss_status status; - intern->start = NULL; - - ypcb.foreach = saveit; + ypcb.foreach = _nis_saveit; ypcb.data = (char *) intern; status = yperr2nss (yp_all (domainname, "group.byname", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern->next != NULL) + intern->next->size = intern->offset; + intern->next = intern->start; + intern->offset = 0; return status; } + static enum nss_status internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, int *errnop, intern_t *intern) { - struct parser_data *data = (void *) buffer; - int parse_res; - char *p; - if (intern->start == NULL) return NSS_STATUS_NOTFOUND; /* Get the next entry until we found a correct one. */ + int parse_res; do { - if (intern->next == NULL) - return NSS_STATUS_NOTFOUND; + struct response_t *bucket = intern->next; + + if (__builtin_expect (intern->offset >= bucket->size, 0)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern->next = bucket->next; + intern->offset = 0; + } + + char *p; + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; - p = strncpy (buffer, intern->next->val, buflen); - while (isspace (*p)) - ++p; + size_t len = strlen (p) + 1; + if (__builtin_expect (len > buflen, 0)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } - parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop); - if (parse_res == -1) + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern->offset], len); + + parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res == -1, 0)) return NSS_STATUS_TRYAGAIN; - intern->next = intern->next->next; + + intern->offset += len; } while (!parse_res); @@ -166,13 +157,12 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s", (unsigned long int) uid, domainname); - enum nss_status retval; char *result; int reslen; - retval = yperr2nss (yp_match (domainname, "netid.byname", key, keylen, - &result, &reslen)); - if (retval != NSS_STATUS_SUCCESS) - return retval; + int yperr = yp_match (domainname, "netid.byname", key, keylen, &result, + &reslen); + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) + return yperr2nss (yperr); /* Parse the result: following the colon is a comma separated list of group IDs. */ @@ -207,7 +197,6 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, if (*start == *size) { /* Need a bigger buffer. */ - gid_t *newgroups; long int newsize; if (limit > 0 && *size == limit) @@ -219,7 +208,7 @@ initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, else newsize = MIN (limit, 2 * *size); - newgroups = realloc (groups, newsize * sizeof (*groups)); + gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) goto errout; *groupsp = groups = newgroups; @@ -247,7 +236,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, return NSS_STATUS_UNAVAIL; /* Check whether we are supposed to use the netid.byname map. */ - if (_nis_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) + if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) { /* We need the user ID. */ uid_t uid; @@ -262,7 +251,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); char *tmpbuf; enum nss_status status; - intern_t intern = { NULL, NULL }; + intern_t intern = { NULL, NULL, 0 }; gid_t *groups = *groupsp; status = internal_setgrent (domainname, &intern); diff --git a/nis/nss_nis/nis-netgrp.c b/nis/nss_nis/nis-netgrp.c index d339dd5097..5a88b72d9c 100644 --- a/nis/nss_nis/nis-netgrp.c +++ b/nis/nss_nis/nis-netgrp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996,1997,1999,2000,2002,2003,2004 +/* Copyright (C) 1996,1997,1999,2000,2002,2003,2004,2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -41,41 +41,37 @@ _nss_netgroup_parseline (char **cursor, struct __netgrent *netgrp, static void internal_nis_endnetgrent (struct __netgrent *netgrp) { - if (netgrp->data != NULL) - { - free (netgrp->data); - netgrp->data = NULL; - netgrp->data_size = 0; - netgrp->cursor = NULL; - } + free (netgrp->data); + netgrp->data = NULL; + netgrp->data_size = 0; + netgrp->cursor = NULL; } + enum nss_status _nss_nis_setnetgrent (const char *group, struct __netgrent *netgrp) { - char *domain; int len; enum nss_status status; status = NSS_STATUS_SUCCESS; - if (group == NULL || group[0] == '\0') + if (__builtin_expect (group == NULL || group[0] == '\0', 0)) return NSS_STATUS_UNAVAIL; - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - internal_nis_endnetgrent (netgrp); - status = yperr2nss (yp_match (domain, "netgroup", group, strlen (group), &netgrp->data, &len)); - if (status == NSS_STATUS_SUCCESS) + if (__builtin_expect (status == NSS_STATUS_SUCCESS, 1)) { /* Our implementation of yp_match already allocates a buffer which is one byte larger than the value in LEN specifies and the last byte is filled with NUL. So we can simply use that buffer. */ - assert (len > 0); + assert (len >= 0); assert (malloc_usable_size (netgrp->data) >= len + 1); assert (netgrp->data[len] == '\0'); @@ -95,13 +91,11 @@ _nss_nis_endnetgrent (struct __netgrent *netgrp) return NSS_STATUS_SUCCESS; } + enum nss_status _nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen, int *errnop) { - if (result->cursor == NULL) - return NSS_STATUS_NOTFOUND; - return _nss_netgroup_parseline (&result->cursor, result, buffer, buflen, errnop); } diff --git a/nis/nss_nis/nis-network.c b/nis/nss_nis/nis-network.c index ed8439c814..9b02302e0b 100644 --- a/nis/nss_nis/nis-network.c +++ b/nis/nss_nis/nis-network.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-2000, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1996-2003, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -73,28 +73,32 @@ internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, int *errnop, int *herrnop) { struct parser_data *data = (void *) buffer; - char *domain, *result, *outkey; - int len, keylen, parse_res; - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* Get the next entry until we found a correct one. */ + int parse_res; do { - enum nss_status retval; - char *p; + char *result; + char *outkey; + int len; + int keylen; + int yperr; if (new_start) - retval = yperr2nss (yp_first (domain, "networks.byname", - &outkey, &keylen, &result, &len)); + yperr = yp_first (domain, "networks.byname", &outkey, &keylen, &result, + &len); else - retval = yperr2nss ( yp_next (domain, "networks.byname", - oldkey, oldkeylen, - &outkey, &keylen, &result, &len)); + yperr = yp_next (domain, "networks.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) { *herrnop = NETDB_INTERNAL; @@ -103,7 +107,7 @@ internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; @@ -111,14 +115,14 @@ internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen, return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); - if (parse_res == -1) + if (__builtin_expect (parse_res == -1, 0)) { free (outkey); *herrnop = NETDB_INTERNAL; @@ -155,11 +159,6 @@ enum nss_status _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer, size_t buflen, int *errnop, int *herrnop) { - enum nss_status retval; - struct parser_data *data = (void *) buffer; - char *domain, *result, *p; - int len, parse_res; - if (name == NULL) { *errnop = EINVAL; @@ -167,33 +166,36 @@ _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer, return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; + struct parser_data *data = (void *) buffer; if (buflen < sizeof *data + 1) { *herrnop = NETDB_INTERNAL; *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - else - { - /* Convert name to lowercase. */ - size_t namlen = strlen (name); - char name2[namlen + 1]; - size_t i; - for (i = 0; i < namlen; ++i) - name2[i] = _tolower (name[i]); - name2[i] = '\0'; + /* Convert name to lowercase. */ + size_t namlen = strlen (name); + char name2[namlen + 1]; + size_t i; - retval = yperr2nss (yp_match (domain, "networks.byname", name2, - namlen, &result, &len)); - } + for (i = 0; i < namlen; ++i) + name2[i] = _tolower (name[i]); + name2[i] = '\0'; + char *result; + int len; + int yperr = yp_match (domain, "networks.byname", name2, namlen, &result, + &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) { *errnop = errno; @@ -202,7 +204,7 @@ _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer, return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; @@ -210,15 +212,15 @@ _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer, return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); + int parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); - if (parse_res < 1) + if (__builtin_expect (parse_res < 1, 0)) { *herrnop = NETDB_INTERNAL; if (parse_res == -1) @@ -235,32 +237,26 @@ _nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net, char *buffer, size_t buflen, int *errnop, int *herrnop) { - struct parser_data *data = (void *) buffer; char *domain; - char *result; - int len; - char buf[256]; - int blen; - struct in_addr in; - char *p; - - if (yp_get_default_domain (&domain)) + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - in = inet_makeaddr (addr, 0); - strcpy (buf, inet_ntoa (in)); - blen = strlen (buf); + struct in_addr in = inet_makeaddr (addr, 0); + char *buf = inet_ntoa (in); + size_t blen = strlen (buf); while (1) { - enum nss_status retval; - int parse_res; + char *result; + int len; - retval = yperr2nss (yp_match (domain, "networks.byaddr", buf, - strlen (buf), &result, &len)); + int yperr = yp_match (domain, "networks.byaddr", buf, blen, &result, + &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_NOTFOUND) { if (buf[blen - 2] == '.' && buf[blen - 1] == '0') @@ -282,7 +278,7 @@ _nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net, } } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; @@ -290,15 +286,16 @@ _nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net, return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop); + int parse_res = _nss_files_parse_netent (p, net, (void *) buffer, + buflen, errnop); - if (parse_res < 1) + if (__builtin_expect (parse_res < 1, 0)) { *herrnop = NETDB_INTERNAL; if (parse_res == -1) diff --git a/nis/nss_nis/nis-proto.c b/nis/nss_nis/nis-proto.c index f1069283ab..1480a928b5 100644 --- a/nis/nss_nis/nis-proto.c +++ b/nis/nss_nis/nis-proto.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1998, 2000-2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-1998, 2000-2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -179,45 +179,46 @@ enum nss_status _nss_nis_getprotobyname_r (const char *name, struct protoent *proto, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, parse_res; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - retval = yperr2nss (yp_match (domain, "protocols.byname", name, - strlen (name), &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "protocols.byname", name, strlen (name), + &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; @@ -231,42 +232,43 @@ enum nss_status _nss_nis_getprotobynumber_r (int number, struct protoent *proto, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, nlen, parse_res; - char buf[32]; - - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - nlen = sprintf (buf, "%d", number); + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%d", number); - retval = yperr2nss (yp_match (domain, "protocols.bynumber", buf, - nlen, &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "protocols.bynumber", buf, nlen, &result, + &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; diff --git a/nis/nss_nis/nis-publickey.c b/nis/nss_nis/nis-publickey.c index 6e92112d11..f58eb154ad 100644 --- a/nis/nss_nis/nis-publickey.c +++ b/nis/nss_nis/nis-publickey.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996,1997,1998,1999,2001,2002 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999,2001,2002,2005,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -36,10 +36,6 @@ extern int xdecrypt (char *, char *); enum nss_status _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop) { - enum nss_status retval; - char *domain, *result; - int len; - pkey[0] = 0; if (netname == NULL) @@ -48,19 +44,23 @@ _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop) return NSS_STATUS_UNAVAIL; } - domain = strchr (netname, '@'); - if (!domain) + char *domain = strchr (netname, '@'); + if (domain == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } ++domain; - retval = yperr2nss (yp_match (domain, "publickey.byname", netname, - strlen (netname), &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname), + &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; @@ -73,6 +73,7 @@ _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop) *p = 0; strncpy (pkey, result, HEXKEYBYTES + 1); pkey[HEXKEYBYTES] = '\0'; + free (result); } return NSS_STATUS_SUCCESS; } @@ -81,11 +82,6 @@ enum nss_status _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd, int *errnop) { - enum nss_status retval; - char buf[2 * (HEXKEYBYTES + 1)]; - char *domain, *result; - int len; - skey[0] = 0; if (netname == NULL || passwd == NULL) @@ -94,19 +90,23 @@ _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd, return NSS_STATUS_UNAVAIL; } - domain = strchr (netname, '@'); - if (!domain) + char *domain = strchr (netname, '@'); + if (domain == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } ++domain; - retval = yperr2nss (yp_match (domain, "publickey.byname", netname, - strlen (netname), &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname), + &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; @@ -115,20 +115,22 @@ _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd, if (result != NULL) { char *p = strchr (result, ':'); - if (p == NULL) - return NSS_STATUS_SUCCESS; - - ++p; - strncpy (buf, p, 2 * (HEXKEYBYTES + 1)); - buf[2 * (HEXKEYBYTES + 1)] = '\0'; - if (!xdecrypt (buf, passwd)) - return NSS_STATUS_SUCCESS; - - if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0) - return NSS_STATUS_SUCCESS; - - buf[HEXKEYBYTES] = '\0'; - strcpy (skey, buf); + if (p != NULL) + { + char buf[2 * (HEXKEYBYTES + 1)]; + + ++p; + strncpy (buf, p, 2 * (HEXKEYBYTES + 1)); + buf[2 * HEXKEYBYTES + 1] = '\0'; + if (xdecrypt (buf, passwd) + && memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) == 0) + { + buf[HEXKEYBYTES] = '\0'; + strcpy (skey, buf); + } + } + + free (result); } return NSS_STATUS_SUCCESS; } @@ -194,13 +196,8 @@ enum nss_status _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop) { - char *domain; - int yperr; - char *lookup; - int len; - - domain = strchr (netname, '@'); - if (!domain) + char *domain = strchr (netname, '@'); + if (domain == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; @@ -208,9 +205,10 @@ _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, /* Point past the '@' character */ ++domain; - lookup = NULL; - yperr = yp_match (domain, "netid.byname", netname, strlen (netname), - &lookup, &len); + char *lookup = NULL; + int len; + int yperr = yp_match (domain, "netid.byname", netname, strlen (netname), + &lookup, &len); switch (yperr) { case YPERR_SUCCESS: @@ -223,17 +221,15 @@ _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp, return NSS_STATUS_UNAVAIL; } - if (lookup) - { - enum nss_status err; - - lookup[len] = '\0'; - err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist); - free (lookup); - return err; - } - else + if (lookup == NULL) return NSS_STATUS_NOTFOUND; - return NSS_STATUS_SUCCESS; + + lookup[len] = '\0'; + + enum nss_status err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist); + + free (lookup); + + return err; } diff --git a/nis/nss_nis/nis-pwd.c b/nis/nss_nis/nis-pwd.c index 0f56ced014..1b5206ad6d 100644 --- a/nis/nss_nis/nis-pwd.c +++ b/nis/nss_nis/nis-pwd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1998, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1996-1998,2001,2002,2003,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -17,20 +17,18 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <nss.h> -/* The following is an ugly trick to avoid a prototype declaration for - _nss_nis_endpwent. */ -#define _nss_nis_endpwent _nss_nis_endpwent_XXX -#include <pwd.h> -#undef _nss_nis_endpwent +#include <assert.h> #include <ctype.h> #include <errno.h> +#include <nss.h> +#include <pwd.h> #include <string.h> #include <bits/libc-lock.h> #include <rpcsvc/yp.h> #include <rpcsvc/ypclnt.h> #include "nss-nis.h" +#include <libnsl.h> /* Get the declaration of the parser function. */ #define ENTNAME pwent @@ -44,12 +42,72 @@ __libc_lock_define_initialized (static, lock) static bool_t new_start = 1; static char *oldkey; static int oldkeylen; +static intern_t intern; -enum nss_status -_nss_nis_setpwent (int stayopen) + +int +_nis_saveit (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) { - __libc_lock_lock (lock); + intern_t *intern = (intern_t *) indata; + + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct response_t *bucket = intern->next; + if (__builtin_expect (bucket == NULL, 0)) + { +#define MINSIZE 4096 - 4 * sizeof (void *) + const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1)); + bucket = malloc (sizeof (struct response_t) + minsize); + if (bucket == NULL) + /* We have no error code for out of memory. */ + return 1; + + bucket->next = NULL; + bucket->size = minsize; + intern->start = intern->next = bucket; + intern->offset = 0; + } + else if (__builtin_expect (invallen + 1 > bucket->size - intern->offset, + 0)) + { + /* We need a new (larger) buffer. */ + const size_t newsize = 2 * MAX (bucket->size, invallen + 1); + struct response_t *newp = malloc (sizeof (struct response_t) + + newsize); + if (newp == NULL) + /* We have no error code for out of memory. */ + return 1; + + /* Mark the old bucket as full. */ + bucket->size = intern->offset; + + newp->next = NULL; + newp->size = newsize; + bucket = intern->next = bucket->next = newp; + intern->offset = 0; + } + + char *p = mempcpy (&bucket->mem[intern->offset], inval, invallen); + if (__builtin_expect (p[-1] != '\0', 0)) + { + *p = '\0'; + ++invallen; + } + intern->offset += invallen; + } + + return 0; +} + + +static void +internal_nis_endpwent (void) +{ new_start = 1; if (oldkey != NULL) { @@ -58,52 +116,159 @@ _nss_nis_setpwent (int stayopen) oldkeylen = 0; } + struct response_t *curr = intern.next; + + while (curr != NULL) + { + struct response_t *last = curr; + curr = curr->next; + free (last); + } + + intern.next = intern.start = NULL; +} + + +enum nss_status +_nss_nis_endpwent (void) +{ + __libc_lock_lock (lock); + + internal_nis_endpwent (); + __libc_lock_unlock (lock); return NSS_STATUS_SUCCESS; } -/* Make _nss_nis_endpwent an alias of _nss_nis_setpwent. We do this - even though the prototypes don't match. The argument of setpwent - is not used so this makes no difference. */ -strong_alias (_nss_nis_setpwent, _nss_nis_endpwent) + + +enum nss_status +internal_nis_setpwent (void) +{ + /* We have to read all the data now. */ + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) + return NSS_STATUS_UNAVAIL; + + struct ypall_callback ypcb; + + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; + enum nss_status status = yperr2nss (yp_all (domain, "passwd.byname", &ypcb)); + + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; + + return status; +} + + +enum nss_status +_nss_nis_setpwent (int stayopen) +{ + enum nss_status result = NSS_STATUS_SUCCESS; + + __libc_lock_lock (lock); + + internal_nis_endpwent (); + + if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + result = internal_nis_setpwent (); + + __libc_lock_unlock (lock); + + return result; +} + static enum nss_status internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - char *domain; - int parse_res; + /* If we read the entire database at setpwent time we just iterate + over the data we have in memory. */ + bool batch_read = intern.start != NULL; - if (yp_get_default_domain (&domain)) + char *domain = NULL; + if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* Get the next entry until we found a correct one. */ + int parse_res; do { - enum nss_status retval; - char *result, *outkey, *result2, *p; - int len, keylen, len2; - size_t namelen; + char *result; + char *outkey; + int len; + int keylen; + + if (batch_read) + { + struct response_t *bucket; + + handle_batch_read: + bucket = intern.next; - if (new_start) - retval = yperr2nss (yp_first (domain, "passwd.byname", - &outkey, &keylen, &result, &len)); + if (__builtin_expect (intern.offset >= bucket->size, 0)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (result = &bucket->mem[intern.offset]; isspace (*result); + ++result) + ++intern.offset; + + len = strlen (result); + } else - retval = yperr2nss ( yp_next (domain, "passwd.byname", - oldkey, oldkeylen, - &outkey, &keylen, &result, &len)); + { + int yperr; - if (retval != NSS_STATUS_SUCCESS) - { - if (retval == NSS_STATUS_TRYAGAIN) - *errnop = errno; - return retval; - } + if (new_start) + { + /* Maybe we should read the database in one piece. */ + if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ) + && internal_nis_setpwent () == NSS_STATUS_SUCCESS + && intern.start != NULL) + { + batch_read = true; + goto handle_batch_read; + } + + yperr = yp_first (domain, "passwd.byname", &outkey, &keylen, + &result, &len); + } + else + yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen, + &outkey, &keylen, &result, &len); + + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) + { + enum nss_status retval = yperr2nss (yperr); + + if (retval == NSS_STATUS_TRYAGAIN) + *errnop = errno; + return retval; + } + } /* Check for adjunct style secret passwords. They can be recognized by a password starting with "##". */ - p = strchr (result, ':'); + char *p = strchr (result, ':'); + size_t namelen; + char *result2; + int len2; if (p != NULL /* This better should be true in all cases. */ && p[1] == '#' && p[2] == '#' && (namelen = p - result, @@ -128,7 +293,8 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, } restlen = len - (p - result); - if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + if (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) { free (result2); free (result); @@ -136,10 +302,10 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, return NSS_STATUS_TRYAGAIN; } - __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen), - ":", 1), - encrypted, endp - encrypted), - p, restlen + 1); + mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen), + ":", 1), + encrypted, endp - encrypted), + p, restlen + 1); p = buffer; free (result2); @@ -147,33 +313,41 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen, else { non_adjunct: - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); - buffer[len] = '\0'; + p = buffer; + *((char *) mempcpy (buffer, result, len)) = '\0'; } while (isspace (*p)) ++p; - free (result); + if (!batch_read) + free (result); - parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop); - if (parse_res == -1) + parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res == -1, 0)) { - free (outkey); + if (!batch_read) + free (outkey); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - free (oldkey); - oldkey = outkey; - oldkeylen = keylen; - new_start = 0; + if (batch_read) + intern.offset += len + 1; + else + { + free (oldkey); + oldkey = outkey; + oldkeylen = keylen; + new_start = 0; + } } while (parse_res < 1); @@ -199,28 +373,26 @@ enum nss_status _nss_nis_getpwnam_r (const char *name, struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *result2, *p; - int len, len2, parse_res; - size_t namelen; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - namelen = strlen (name); + size_t namelen = strlen (name); - retval = yperr2nss (yp_match (domain, "passwd.byname", name, - namelen, &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "passwd.byname", name, namelen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; @@ -228,7 +400,9 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd, /* Check for adjunct style secret passwords. They can be recognized by a password starting with "##". */ - p = strchr (result, ':'); + char *result2; + int len2; + char *p = strchr (result, ':'); if (p != NULL /* This better should be true in all cases. */ && p[1] == '#' && p[2] == '#' && yp_match (domain, "passwd.adjunct.byname", name, namelen, @@ -238,7 +412,6 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd, therein into original result. */ char *encrypted = strchr (result2, ':'); char *endp; - size_t restlen; if (encrypted == NULL || (endp = strchr (++encrypted, ':')) == NULL @@ -251,8 +424,9 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd, goto non_adjunct; } - restlen = len - (p - result); - if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + size_t restlen = len - (p - result); + if (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) { free (result2); free (result); @@ -271,7 +445,7 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd, else { non_adjunct: - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; @@ -286,8 +460,9 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd, ++p; free (result); - parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; @@ -302,23 +477,21 @@ enum nss_status _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p, *result2; - int len, nlen, parse_res, len2; - char buf[32]; - size_t namelen; - - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - nlen = sprintf (buf, "%lu", (unsigned long int) uid); + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%lu", (unsigned long int) uid); - retval = yperr2nss (yp_match (domain, "passwd.byuid", buf, - nlen, &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "passwd.byuid", buf, nlen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; @@ -326,7 +499,10 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, /* Check for adjunct style secret passwords. They can be recognized by a password starting with "##". */ - p = strchr (result, ':'); + char *result2; + int len2; + size_t namelen; + char *p = strchr (result, ':'); if (p != NULL /* This better should be true in all cases. */ && p[1] == '#' && p[2] == '#' && (namelen = p - result, @@ -351,7 +527,8 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, } restlen = len - (p - result); - if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen) + if (__builtin_expect ((size_t) (namelen + (endp - encrypted) + + restlen + 2) > buflen, 0)) { free (result2); free (result); @@ -370,7 +547,7 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, else { non_adjunct: - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; @@ -385,8 +562,9 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd, ++p; free (result); - parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; diff --git a/nis/nss_nis/nis-rpc.c b/nis/nss_nis/nis-rpc.c index d1ab94371a..2fdb16ddde 100644 --- a/nis/nss_nis/nis-rpc.c +++ b/nis/nss_nis/nis-rpc.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1996-1998,2000,2002,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-1998,2000,2002,2003,2004,2006 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -35,59 +36,22 @@ __libc_lock_define_initialized (static, lock) -struct response_t -{ - struct response_t *next; - char val[0]; -}; - -struct intern_t -{ - struct response_t *start; - struct response_t *next; -}; -typedef struct intern_t intern_t; - -static intern_t intern = {NULL, NULL}; - -static int -saveit (int instatus, char *inkey, int inkeylen, char *inval, - int invallen, char *indata) -{ - intern_t *intern = (intern_t *)indata; - - if (instatus != YP_TRUE) - return 1; - - if (inkey && inkeylen > 0 && inval && invallen > 0) - { - struct response_t *newp = malloc (sizeof (struct response_t) - + invallen + 1); - if (newp == NULL) - return 1; /* We have no error code for out of memory */ - - if (intern->start == NULL) - intern->start = newp; - else - intern->next->next = newp; - intern->next = newp; +static intern_t intern; - newp->next = NULL; - *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; - } - - return 0; -} static void internal_nis_endrpcent (intern_t *intern) { - while (intern->start != NULL) + struct response_t *curr = intern->next; + + while (curr != NULL) { - intern->next = intern->start; - intern->start = intern->start->next; - free (intern->next); + struct response_t *last = curr; + curr = curr->next; + free (last); } + + intern->next = intern->start = NULL; } static enum nss_status @@ -102,10 +66,16 @@ internal_nis_setrpcent (intern_t *intern) internal_nis_endrpcent (intern); - ypcb.foreach = saveit; - ypcb.data = (char *)intern; - status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb)); + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) intern; + status = yperr2nss (yp_all (domainname, "rpc.bynumber", &ypcb)); + + /* Mark the last buffer as full. */ + if (intern->next != NULL) + intern->next->size = intern->offset; + intern->next = intern->start; + intern->offset = 0; return status; } @@ -138,29 +108,60 @@ _nss_nis_endrpcent (void) static enum nss_status internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen, - int *errnop, intern_t *data) + int *errnop, intern_t *intern) { struct parser_data *pdata = (void *) buffer; int parse_res; char *p; - if (data->start == NULL) - internal_nis_setrpcent (data); + if (intern->start == NULL) + internal_nis_setrpcent (intern); + + if (intern->next == NULL) + /* Not one entry in the map. */ + return NSS_STATUS_NOTFOUND; /* Get the next entry until we found a correct one. */ do { - if (data->next == NULL) - return NSS_STATUS_NOTFOUND; + struct response_t *bucket = intern->next; - p = strncpy (buffer, data->next->val, buflen); - while (isspace (*p)) - ++p; + if (__builtin_expect (intern->offset >= bucket->size, 0)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern->next = bucket->next; + intern->offset = 0; + } + + for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) + ++intern->offset; + + size_t len = strlen (p) + 1; + if (__builtin_expect (len > buflen, 0)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern->offset], len); parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop); - if (parse_res == -1) + if (__builtin_expect (parse_res == -1, 0)) return NSS_STATUS_TRYAGAIN; - data->next = data->next->next; + + intern->offset += len; } while (!parse_res); @@ -186,21 +187,18 @@ enum nss_status _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc, char *buffer, size_t buflen, int *errnop) { - intern_t data = {NULL, NULL}; - enum nss_status status; - int found; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - status = internal_nis_setrpcent (&data); - if (status != NSS_STATUS_SUCCESS) + intern_t data = { NULL, NULL, 0 }; + enum nss_status status = internal_nis_setrpcent (&data); + if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0)) return status; - found = 0; + int found = 0; while (!found && ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, &data)) == NSS_STATUS_SUCCESS)) @@ -226,53 +224,52 @@ _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc, internal_nis_endrpcent (&data); - if (!found && status == NSS_STATUS_SUCCESS) + if (__builtin_expect (!found && status == NSS_STATUS_SUCCESS, 0)) return NSS_STATUS_NOTFOUND; - else - return status; + + return status; } enum nss_status _nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, nlen, parse_res; - char buf[32]; - - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - nlen = sprintf (buf, "%d", number); + char buf[32]; + int nlen = snprintf (buf, sizeof (buf), "%d", number); - retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf, - nlen, &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "rpc.bynumber", buf, nlen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_rpcent (p, rpc, data, buflen, errnop); - - if (parse_res < 1) + int parse_res = _nss_files_parse_rpcent (p, rpc, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; diff --git a/nis/nss_nis/nis-service.c b/nis/nss_nis/nis-service.c index 1e879d04e3..59a598f296 100644 --- a/nis/nss_nis/nis-service.c +++ b/nis/nss_nis/nis-service.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -27,6 +27,7 @@ #include <rpcsvc/ypclnt.h> #include "nss-nis.h" +#include <libnsl.h> /* Get the declaration of the parser function. */ @@ -36,20 +37,7 @@ __libc_lock_define_initialized (static, lock) -struct response_t -{ - struct response_t *next; - char val[0]; -}; - -struct intern_t -{ - struct response_t *start; - struct response_t *next; -}; -typedef struct intern_t intern_t; - -static intern_t intern = { NULL, NULL }; +static intern_t intern; struct search_t { @@ -64,63 +52,31 @@ struct search_t }; static int -saveit (int instatus, char *inkey, int inkeylen, char *inval, - int invallen, char *indata) -{ - intern_t *intern = (intern_t *) indata; - - if (instatus != YP_TRUE) - return 1; - - if (inkey && inkeylen > 0 && inval && invallen > 0) - { - struct response_t *newp = malloc (sizeof (struct response_t) - + invallen + 1); - if (newp == NULL) - return 1; /* We have no error code for out of memory */ - - if (intern->start == NULL) - intern->start = newp; - else - intern->next->next = newp; - intern->next = newp; - - newp->next = NULL; - *((char *) mempcpy (newp->val, inval, invallen)) = '\0'; - } - - return 0; -} - -static int dosearch (int instatus, char *inkey, int inkeylen, char *inval, int invallen, char *indata) { struct search_t *req = (struct search_t *) indata; - if (instatus != YP_TRUE) + if (__builtin_expect (instatus != YP_TRUE, 0)) return 1; if (inkey && inkeylen > 0 && inval && invallen > 0) { - struct parser_data *pdata = (void *) req->buffer; - int parse_res; - char *p; - - if ((size_t) (invallen + 1) > req->buflen) + if (__builtin_expect ((size_t) (invallen + 1) > req->buflen, 0)) { *req->errnop = ERANGE; req->status = NSS_STATUS_TRYAGAIN; return 1; } - p = strncpy (req->buffer, inval, invallen); + char *p = strncpy (req->buffer, inval, invallen); req->buffer[invallen] = '\0'; while (isspace (*p)) ++p; - parse_res = _nss_files_parse_servent (p, req->serv, pdata, req->buflen, - req->errnop); + int parse_res = _nss_files_parse_servent (p, req->serv, + (void *) req->buffer, + req->buflen, req->errnop); if (parse_res == -1) { req->status = NSS_STATUS_TRYAGAIN; @@ -154,35 +110,35 @@ dosearch (int instatus, char *inkey, int inkeylen, char *inval, return 0; } -static enum nss_status -internal_nis_endservent (intern_t * intern) +static void +internal_nis_endservent (void) { - while (intern->start != NULL) + struct response_t *curr = intern.next; + + while (curr != NULL) { - intern->next = intern->start; - intern->start = intern->start->next; - free (intern->next); + struct response_t *last = curr; + curr = curr->next; + free (last); } - return NSS_STATUS_SUCCESS; + intern.next = intern.start = NULL; } enum nss_status _nss_nis_endservent (void) { - enum nss_status status; - __libc_lock_lock (lock); - status = internal_nis_endservent (&intern); + internal_nis_endservent (); __libc_lock_unlock (lock); - return status; + return NSS_STATUS_SUCCESS; } static enum nss_status -internal_nis_setservent (intern_t *intern) +internal_nis_setservent (void) { char *domainname; struct ypall_callback ypcb; @@ -191,12 +147,18 @@ internal_nis_setservent (intern_t *intern) if (yp_get_default_domain (&domainname)) return NSS_STATUS_UNAVAIL; - (void) internal_nis_endservent (intern); + internal_nis_endservent (); - ypcb.foreach = saveit; - ypcb.data = (char *) intern; + ypcb.foreach = _nis_saveit; + ypcb.data = (char *) &intern; status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); - intern->next = intern->start; + + /* Mark the last buffer as full. */ + if (intern.next != NULL) + intern.next->size = intern.offset; + + intern.next = intern.start; + intern.offset = 0; return status; } @@ -208,7 +170,7 @@ _nss_nis_setservent (int stayopen) __libc_lock_lock (lock); - status = internal_nis_setservent (&intern); + status = internal_nis_setservent (); __libc_lock_unlock (lock); @@ -217,29 +179,60 @@ _nss_nis_setservent (int stayopen) static enum nss_status internal_nis_getservent_r (struct servent *serv, char *buffer, - size_t buflen, int *errnop, intern_t *data) + size_t buflen, int *errnop) { struct parser_data *pdata = (void *) buffer; int parse_res; char *p; - if (data->start == NULL) - internal_nis_setservent (data); + if (intern.start == NULL) + internal_nis_setservent (); - /* Get the next entry until we found a correct one. */ + if (intern.next == NULL) + /* Not one entry in the map. */ + return NSS_STATUS_NOTFOUND; + + /* Get the next entry until we found a correct one. */ do { - if (data->next == NULL) - return NSS_STATUS_NOTFOUND; + struct response_t *bucket = intern.next; - p = strncpy (buffer, data->next->val, buflen); - while (isspace (*p)) - ++p; + if (__builtin_expect (intern.offset >= bucket->size, 0)) + { + if (bucket->next == NULL) + return NSS_STATUS_NOTFOUND; + + /* We look at all the content in the current bucket. Go on + to the next. */ + bucket = intern.next = bucket->next; + intern.offset = 0; + } + + for (p = &bucket->mem[intern.offset]; isspace (*p); ++p) + ++intern.offset; + + size_t len = strlen (p) + 1; + if (__builtin_expect (len > buflen, 0)) + { + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + /* We unfortunately have to copy the data in the user-provided + buffer because that buffer might be around for a very long + time and the servent structure must remain valid. If we would + rely on the BUCKET memory the next 'setservent' or 'endservent' + call would destroy it. + + The important thing is that it is a single NUL-terminated + string. This is what the parsing routine expects. */ + p = memcpy (buffer, &bucket->mem[intern.offset], len); parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop); - if (parse_res == -1) + if (__builtin_expect (parse_res == -1, 0)) return NSS_STATUS_TRYAGAIN; - data->next = data->next->next; + + intern.offset += len; } while (!parse_res); @@ -254,7 +247,7 @@ _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen, __libc_lock_lock (lock); - status = internal_nis_getservent_r (serv, buffer, buflen, errnop, &intern); + status = internal_nis_getservent_r (serv, buffer, buflen, errnop); __libc_lock_unlock (lock); @@ -266,60 +259,55 @@ _nss_nis_getservbyname_r (const char *name, const char *protocol, struct servent *serv, char *buffer, size_t buflen, int *errnop) { - enum nss_status status; - char *domain; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* If the protocol is given, we could try if our NIS server knows about services.byservicename map. If yes, we only need one query. */ - char key[strlen (name) + (protocol ? strlen (protocol) : 0) + 2]; - char *cp, *result; - size_t keylen, len; - int int_len; + size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0); + char key[keylen + 1]; /* key is: "name/proto" */ - cp = stpcpy (key, name); - if (protocol) + char *cp = stpcpy (key, name); + if (protocol != NULL) { *cp++ = '/'; strcpy (cp, protocol); } - keylen = strlen (key); - status = yperr2nss (yp_match (domain, "services.byservicename", key, - keylen, &result, &int_len)); - len = int_len; + + char *result; + int int_len; + int status = yp_match (domain, "services.byservicename", key, + keylen, &result, &int_len); + size_t len = int_len; /* If we found the key, it's ok and parse the result. If not, fall through and parse the complete table. */ - if (status == NSS_STATUS_SUCCESS) + if (__builtin_expect (status == YPERR_SUCCESS, 1)) { - struct parser_data *pdata = (void *) buffer; - int parse_res; - char *p; - - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_servent (p, serv, pdata, - buflen, errnop); - if (parse_res < 0) + + int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, + buflen, errnop); + if (__builtin_expect (parse_res < 0, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; @@ -331,8 +319,8 @@ _nss_nis_getservbyname_r (const char *name, const char *protocol, } /* Check if it is safe to rely on services.byservicename. */ - if (_nis_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE) - return status; + if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE) + return yperr2nss (status); struct ypall_callback ypcb; struct search_t req; @@ -347,10 +335,10 @@ _nss_nis_getservbyname_r (const char *name, const char *protocol, req.buflen = buflen; req.errnop = errnop; req.status = NSS_STATUS_NOTFOUND; - status = yperr2nss (yp_all (domain, "services.byname", &ypcb)); + status = yp_all (domain, "services.byname", &ypcb); - if (status != NSS_STATUS_SUCCESS) - return status; + if (__builtin_expect (status != YPERR_SUCCESS, 0)) + return yperr2nss (status); return req.status; } @@ -360,10 +348,8 @@ _nss_nis_getservbyport_r (int port, const char *protocol, struct servent *serv, char *buffer, size_t buflen, int *errnop) { - enum nss_status status; char *domain; - - if (yp_get_default_domain (&domain)) + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* If the protocol is given, we only need one query. @@ -372,48 +358,44 @@ _nss_nis_getservbyport_r (int port, const char *protocol, const char *proto = protocol != NULL ? protocol : "tcp"; do { + /* key is: "port/proto" */ char key[sizeof (int) * 3 + strlen (proto) + 2]; + size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), + proto); + char *result; - size_t keylen, len; int int_len; - - /* key is: "port/proto" */ - keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), proto); - status = yperr2nss (yp_match (domain, "services.byname", key, - keylen, &result, &int_len)); - len = int_len; + int status = yp_match (domain, "services.byname", key, keylen, &result, + &int_len); + size_t len = int_len; /* If we found the key, it's ok and parse the result. If not, fall through and parse the complete table. */ - if (status == NSS_STATUS_SUCCESS) + if (__builtin_expect (status == YPERR_SUCCESS, 1)) { - struct parser_data *pdata = (void *) buffer; - int parse_res; - char *p; - - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_servent (p, serv, pdata, - buflen, errnop); - if (parse_res < 0) + int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, + buflen, errnop); + if (__builtin_expect (parse_res < 0, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; else return NSS_STATUS_NOTFOUND; } - else - return NSS_STATUS_SUCCESS; + + return NSS_STATUS_SUCCESS; } } while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL)); @@ -434,10 +416,10 @@ _nss_nis_getservbyport_r (int port, const char *protocol, req.buflen = buflen; req.errnop = errnop; req.status = NSS_STATUS_NOTFOUND; - status = yperr2nss (yp_all (domain, "services.byname", &ypcb)); + int status = yp_all (domain, "services.byname", &ypcb); - if (status != NSS_STATUS_SUCCESS) - return status; + if (__builtin_expect (status != YPERR_SUCCESS, 0)) + return yperr2nss (status); return req.status; } diff --git a/nis/nss_nis/nis-spwd.c b/nis/nss_nis/nis-spwd.c index 99a9ed5f48..0fc4e17c42 100644 --- a/nis/nss_nis/nis-spwd.c +++ b/nis/nss_nis/nis-spwd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1998, 2001, 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 1996-1998,2001,2002,2003,2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. @@ -68,49 +68,52 @@ static enum nss_status internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - char *domain, *result, *outkey; - int len, keylen, parse_res; - - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; /* Get the next entry until we found a correct one. */ + int parse_res; do { - enum nss_status retval; - char *p; + char *result; + char *outkey; + int len; + int keylen; + int yperr; if (new_start) - retval = yperr2nss (yp_first (domain, "shadow.byname", - &outkey, &keylen, &result, &len)); + yperr = yp_first (domain, "shadow.byname", &outkey, &keylen, &result, + &len); else - retval = yperr2nss ( yp_next (domain, "shadow.byname", - oldkey, oldkeylen, - &outkey, &keylen, &result, &len)); + yperr = yp_next (domain, "shadow.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_spent (p, sp, data, buflen, errnop); - if (parse_res == -1) + parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res == -1, 0)) { free (outkey); *errnop = ERANGE; @@ -146,45 +149,46 @@ enum nss_status _nss_nis_getspnam_r (const char *name, struct spwd *sp, char *buffer, size_t buflen, int *errnop) { - struct parser_data *data = (void *) buffer; - enum nss_status retval; - char *domain, *result, *p; - int len, parse_res; - if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } - if (yp_get_default_domain (&domain)) + char *domain; + if (__builtin_expect (yp_get_default_domain (&domain), 0)) return NSS_STATUS_UNAVAIL; - retval = yperr2nss (yp_match (domain, "shadow.byname", name, - strlen (name), &result, &len)); + char *result; + int len; + int yperr = yp_match (domain, "shadow.byname", name, strlen (name), &result, + &len); - if (retval != NSS_STATUS_SUCCESS) + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { + enum nss_status retval = yperr2nss (yperr); + if (retval == NSS_STATUS_TRYAGAIN) *errnop = errno; return retval; } - if ((size_t) (len + 1) > buflen) + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) { free (result); *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } - p = strncpy (buffer, result, len); + char *p = strncpy (buffer, result, len); buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); - parse_res = _nss_files_parse_spent (p, sp, data, buflen, errnop); - if (parse_res < 1) + int parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen, + errnop); + if (__builtin_expect (parse_res < 1, 0)) { if (parse_res == -1) return NSS_STATUS_TRYAGAIN; 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; } diff --git a/nis/rpcsvc/nislib.h b/nis/rpcsvc/nislib.h index a55de61830..c8927ece17 100644 --- a/nis/rpcsvc/nislib.h +++ b/nis/rpcsvc/nislib.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. +/* Copyright (C) 1997, 1998, 1999, 2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997. @@ -272,11 +272,13 @@ struct dir_binding typedef struct dir_binding dir_binding; extern nis_error __nisbind_create (dir_binding *, const nis_server *, - unsigned int, unsigned int) __THROW; + unsigned int, unsigned int, unsigned int, + unsigned int) __THROW; extern nis_error __nisbind_connect (dir_binding *) __THROW; extern nis_error __nisbind_next (dir_binding *) __THROW; extern void __nisbind_destroy (dir_binding *) __THROW; -extern nis_error __nisfind_server (const_nis_name, directory_obj **) __THROW; +extern nis_error __nisfind_server (const_nis_name, int, directory_obj **, + dir_binding *, unsigned int) __THROW; #endif diff --git a/nis/yp_xdr.c b/nis/yp_xdr.c index 0ee80126e8..b87ee06151 100644 --- a/nis/yp_xdr.c +++ b/nis/yp_xdr.c @@ -103,6 +103,7 @@ xdr_ypreq_key (XDR *xdrs, ypreq_key *objp) return FALSE; return xdr_keydat (xdrs, &objp->key); } +libnsl_hidden_def (xdr_ypreq_key) bool_t xdr_ypreq_nokey (XDR *xdrs, ypreq_nokey *objp) @@ -111,6 +112,7 @@ xdr_ypreq_nokey (XDR *xdrs, ypreq_nokey *objp) return FALSE; return xdr_mapname (xdrs, &objp->map); } +libnsl_hidden_def (xdr_ypreq_nokey) bool_t xdr_ypreq_xfr (XDR *xdrs, ypreq_xfr *objp) @@ -131,6 +133,7 @@ xdr_ypresp_val (XDR *xdrs, ypresp_val *objp) return FALSE; return xdr_valdat (xdrs, &objp->val); } +libnsl_hidden_def (xdr_ypresp_val) bool_t xdr_ypresp_key_val (XDR *xdrs, ypresp_key_val *objp) @@ -150,6 +153,7 @@ xdr_ypresp_master (XDR *xdrs, ypresp_master *objp) return FALSE; return xdr_peername (xdrs, &objp->peer); } +libnsl_hidden_def (xdr_ypresp_master) bool_t xdr_ypresp_order (XDR *xdrs, ypresp_order *objp) @@ -158,6 +162,7 @@ xdr_ypresp_order (XDR *xdrs, ypresp_order *objp) return FALSE; return xdr_u_int (xdrs, &objp->ordernum); } +libnsl_hidden_def (xdr_ypresp_order) bool_t xdr_ypresp_all (XDR *xdrs, ypresp_all *objp) @@ -193,6 +198,7 @@ xdr_ypmaplist (XDR *xdrs, ypmaplist *objp) return xdr_pointer (xdrs, (char **) &objp->next, sizeof (ypmaplist), (xdrproc_t) xdr_ypmaplist); } +libnsl_hidden_def (xdr_ypmaplist) bool_t xdr_ypresp_maplist (XDR *xdrs, ypresp_maplist *objp) @@ -202,6 +208,7 @@ xdr_ypresp_maplist (XDR *xdrs, ypresp_maplist *objp) return xdr_pointer (xdrs, (char **) &objp->maps, sizeof (ypmaplist), (xdrproc_t) xdr_ypmaplist); } +libnsl_hidden_def (xdr_ypresp_maplist) bool_t xdr_yppush_status (XDR *xdrs, yppush_status *objp) @@ -248,6 +255,7 @@ xdr_ypbind_resp (XDR *xdrs, ypbind_resp *objp) } return FALSE; } +libnsl_hidden_def (xdr_ypbind_resp) bool_t xdr_ypbind_setdom (XDR *xdrs, ypbind_setdom *objp) diff --git a/nis/ypclnt.c b/nis/ypclnt.c index 85292b62d9..ae04ee9212 100644 --- a/nis/ypclnt.c +++ b/nis/ypclnt.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. @@ -45,12 +46,12 @@ struct dom_binding }; typedef struct dom_binding dom_binding; -static struct timeval RPCTIMEOUT = {25, 0}; -static struct timeval UDPTIMEOUT = {5, 0}; +static const struct timeval RPCTIMEOUT = {25, 0}; +static const struct timeval UDPTIMEOUT = {5, 0}; static int const MAXTRIES = 2; -static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0"; +static char ypdomainname[NIS_MAXNAMELEN + 1]; __libc_lock_define_initialized (static, ypbindlist_lock) -static dom_binding *__ypbindlist = NULL; +static dom_binding *ypbindlist = NULL; static void @@ -110,8 +111,8 @@ yp_bind_ypbindprog (const char *domain, dom_binding *ysd) int clnt_sock; CLIENT *client; - memset (&clnt_saddr, '\0', sizeof clnt_saddr); clnt_saddr.sin_family = AF_INET; + clnt_saddr.sin_port = 0; clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); clnt_sock = RPC_ANYSOCK; client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS, @@ -141,7 +142,7 @@ yp_bind_ypbindprog (const char *domain, dom_binding *ysd) if (ypbr.ypbind_status != YPBIND_SUCC_VAL) { - fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"), + fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n", ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error)); return YPERR_DOMAIN; } @@ -224,7 +225,7 @@ yp_bind (const char *indomain) __libc_lock_lock (ypbindlist_lock); - status = __yp_bind (indomain, &__ypbindlist); + status = __yp_bind (indomain, &ypbindlist); __libc_lock_unlock (ypbindlist_lock); @@ -238,7 +239,7 @@ yp_unbind_locked (const char *indomain) dom_binding *ydbptr, *ydbptr2; ydbptr2 = NULL; - ydbptr = __ypbindlist; + ydbptr = ypbindlist; while (ydbptr != NULL) { @@ -248,7 +249,7 @@ yp_unbind_locked (const char *indomain) work = ydbptr; if (ydbptr2 == NULL) - __ypbindlist = __ypbindlist->dom_pnext; + ypbindlist = ypbindlist->dom_pnext; else ydbptr2 = ydbptr->dom_pnext; __yp_unbind (work); @@ -305,7 +306,7 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, status = YPERR_YPERR; __libc_lock_lock (ypbindlist_lock); - ydb = __ypbindlist; + ydb = ypbindlist; while (ydb != NULL) { if (strcmp (domain, ydb->dom_domain) == 0) @@ -348,7 +349,7 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, if (status != YPERR_SUCCESS) { ydb = calloc (1, sizeof (dom_binding)); - if (yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS) + if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS) { status = __ypclnt_call (domain, prog, xargs, req, xres, resp, &ydb, 1); @@ -364,6 +365,21 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, return status; } +/* Like do_ypcall, but translate the status value if necessary. */ +static int +do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs, + caddr_t req, xdrproc_t xres, caddr_t resp) +{ + int status = do_ypcall (domain, prog, xargs, req, xres, resp); + if (status == YPERR_SUCCESS) + /* We cast to ypresp_val although the pointer could also be of + type ypresp_key_val or ypresp_master or ypresp_order or + ypresp_maplist. But the stat element is in a common prefix so + this does not matter. */ + status = ypprot_err (((struct ypresp_val *) resp)->stat); + return status; +} + __libc_lock_define_initialized (static, domainname_lock) @@ -375,21 +391,21 @@ yp_get_default_domain (char **outdomain) __libc_lock_lock (domainname_lock); - if (__ypdomainname[0] == '\0') + if (ypdomainname[0] == '\0') { - if (getdomainname (__ypdomainname, NIS_MAXNAMELEN)) + if (getdomainname (ypdomainname, NIS_MAXNAMELEN)) result = YPERR_NODOM; - else if (strcmp (__ypdomainname, "(none)") == 0) + else if (strcmp (ypdomainname, "(none)") == 0) { /* If domainname is not set, some systems will return "(none)" */ - __ypdomainname[0] = '\0'; + ypdomainname[0] = '\0'; result = YPERR_NODOM; } else - *outdomain = __ypdomainname; + *outdomain = ypdomainname; } else - *outdomain = __ypdomainname; + *outdomain = ypdomainname; __libc_lock_unlock (domainname_lock); @@ -402,14 +418,14 @@ __yp_check (char **domain) { char *unused; - if (__ypdomainname[0] == '\0') + if (ypdomainname[0] == '\0') if (yp_get_default_domain (&unused)) return 0; if (domain) - *domain = __ypdomainname; + *domain = ypdomainname; - if (yp_bind (__ypdomainname) == 0) + if (yp_bind (ypdomainname) == 0) return 1; return 0; } @@ -436,25 +452,26 @@ yp_match (const char *indomain, const char *inmap, const char *inkey, *outvallen = 0; memset (&resp, '\0', sizeof (resp)); - result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key, - (caddr_t) & req, (xdrproc_t) xdr_ypresp_val, - (caddr_t) & resp); + result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_val, + (caddr_t) &resp); if (result != YPERR_SUCCESS) return result; - if (resp.stat != YP_TRUE) - return ypprot_err (resp.stat); *outvallen = resp.val.valdat_len; *outval = malloc (*outvallen + 1); - if (__builtin_expect (*outval == NULL, 0)) - return YPERR_RESRC; - memcpy (*outval, resp.val.valdat_val, *outvallen); - (*outval)[*outvallen] = '\0'; + int status = YPERR_RESRC; + if (__builtin_expect (*outval != NULL, 1)) + { + memcpy (*outval, resp.val.valdat_val, *outvallen); + (*outval)[*outvallen] = '\0'; + status = YPERR_SUCCESS; + } xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp); - return YPERR_SUCCESS; + return status; } int @@ -477,30 +494,38 @@ yp_first (const char *indomain, const char *inmap, char **outkey, memset (&resp, '\0', sizeof (resp)); result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey, - (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val, - (caddr_t) & resp); + (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val, + (caddr_t) &resp); if (result != RPC_SUCCESS) return YPERR_RPC; if (resp.stat != YP_TRUE) return ypprot_err (resp.stat); - *outkeylen = resp.key.keydat_len; - *outkey = malloc (*outkeylen + 1); - if (__builtin_expect (*outkey == NULL, 0)) - return YPERR_RESRC; - memcpy (*outkey, resp.key.keydat_val, *outkeylen); - (*outkey)[*outkeylen] = '\0'; - *outvallen = resp.val.valdat_len; - *outval = malloc (*outvallen + 1); - if (__builtin_expect (*outval == NULL, 0)) - return YPERR_RESRC; - memcpy (*outval, resp.val.valdat_val, *outvallen); - (*outval)[*outvallen] = '\0'; + int status; + if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL + && (*outval = malloc (resp.val.valdat_len + + 1)) != NULL, 1)) + { + *outkeylen = resp.key.keydat_len; + memcpy (*outkey, resp.key.keydat_val, *outkeylen); + (*outkey)[*outkeylen] = '\0'; + + *outvallen = resp.val.valdat_len; + memcpy (*outval, resp.val.valdat_val, *outvallen); + (*outval)[*outvallen] = '\0'; + + status = YPERR_SUCCESS; + } + else + { + free (*outkey); + status = YPERR_RESRC; + } xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp); - return YPERR_SUCCESS; + return status; } int @@ -526,31 +551,37 @@ yp_next (const char *indomain, const char *inmap, const char *inkey, *outkeylen = *outvallen = 0; memset (&resp, '\0', sizeof (resp)); - result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key, - (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val, - (caddr_t) & resp); + result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val, + (caddr_t) &resp); if (result != YPERR_SUCCESS) return result; - if (resp.stat != YP_TRUE) - return ypprot_err (resp.stat); - *outkeylen = resp.key.keydat_len; - *outkey = malloc (*outkeylen + 1); - if (__builtin_expect (*outkey == NULL, 0)) - return YPERR_RESRC; - memcpy (*outkey, resp.key.keydat_val, *outkeylen); - (*outkey)[*outkeylen] = '\0'; - *outvallen = resp.val.valdat_len; - *outval = malloc (*outvallen + 1); - if (__builtin_expect (*outval == NULL, 0)) - return YPERR_RESRC; - memcpy (*outval, resp.val.valdat_val, *outvallen); - (*outval)[*outvallen] = '\0'; + int status; + if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL + && (*outval = malloc (resp.val.valdat_len + + 1)) != NULL, 1)) + { + *outkeylen = resp.key.keydat_len; + memcpy (*outkey, resp.key.keydat_val, *outkeylen); + (*outkey)[*outkeylen] = '\0'; + + *outvallen = resp.val.valdat_len; + memcpy (*outval, resp.val.valdat_val, *outvallen); + (*outval)[*outvallen] = '\0'; + + status = YPERR_SUCCESS; + } + else + { + free (*outkey); + status = YPERR_RESRC; + } xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp); - return YPERR_SUCCESS; + return status; } int @@ -569,13 +600,12 @@ yp_master (const char *indomain, const char *inmap, char **outname) memset (&resp, '\0', sizeof (ypresp_master)); - result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey, - (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp); + result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_master, + (caddr_t) &resp); if (result != YPERR_SUCCESS) return result; - if (resp.stat != YP_TRUE) - return ypprot_err (resp.stat); *outname = strdup (resp.peer); xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp); @@ -592,7 +622,7 @@ yp_order (const char *indomain, const char *inmap, unsigned int *outorder) enum clnt_stat result; if (indomain == NULL || indomain[0] == '\0' || - inmap == NULL || inmap == '\0') + inmap == NULL || inmap[0] == '\0') return YPERR_BADARGS; req.domain = (char *) indomain; @@ -600,18 +630,17 @@ yp_order (const char *indomain, const char *inmap, unsigned int *outorder) memset (&resp, '\0', sizeof (resp)); - result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey, - (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp); + result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey, + (caddr_t) &req, (xdrproc_t) xdr_ypresp_order, + (caddr_t) &resp); - if (result != YPERR_SUCCESS) + if (result == YPERR_SUCCESS) return result; - if (resp.stat != YP_TRUE) - return ypprot_err (resp.stat); *outorder = resp.ordernum; xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp); - return YPERR_SUCCESS; + return result; } struct ypresp_all_data @@ -657,10 +686,10 @@ __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp) if we don't modify the length. So add an extra NUL character to avoid trouble with broken code. */ objp->status = YP_TRUE; - memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen); - key[keylen] = '\0'; - memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen); - val[vallen] = '\0'; + *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val, + keylen)) = '\0'; + *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val, + vallen)) = '\0'; xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); if ((*objp->foreach) (objp->status, key, keylen, val, vallen, objp->data)) @@ -671,7 +700,7 @@ __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp) objp->status = resp.ypresp_all_u.val.stat; xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); /* Sun says we don't need to make this call, but must return - immediatly. Since Solaris makes this call, we will call + immediately. Since Solaris makes this call, we will call the callback function, too. */ (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data); return TRUE; @@ -693,8 +722,8 @@ yp_all (const char *indomain, const char *inmap, int clnt_sock; int saved_errno = errno; - if (indomain == NULL || indomain[0] == '\0' || - inmap == NULL || inmap == '\0') + if (indomain == NULL || indomain[0] == '\0' + || inmap == NULL || inmap[0] == '\0') return YPERR_BADARGS; try = 0; @@ -732,9 +761,9 @@ yp_all (const char *indomain, const char *inmap, (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all, (caddr_t) &data, RPCTIMEOUT); - if (result != RPC_SUCCESS) + if (__builtin_expect (result != RPC_SUCCESS, 0)) { - /* Print the error message only on the last try */ + /* Print the error message only on the last try. */ if (try == MAXTRIES - 1) clnt_perror (clnt, "yp_all: clnt_call"); res = YPERR_RPC; @@ -758,6 +787,7 @@ yp_all (const char *indomain, const char *inmap, } int + yp_maplist (const char *indomain, struct ypmaplist **outmaplist) { struct ypresp_maplist resp; @@ -768,67 +798,92 @@ yp_maplist (const char *indomain, struct ypmaplist **outmaplist) memset (&resp, '\0', sizeof (resp)); - result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname, - (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp); - - if (result != YPERR_SUCCESS) - return result; - if (resp.stat != YP_TRUE) - return ypprot_err (resp.stat); + result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname, + (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist, + (caddr_t) &resp); - *outmaplist = resp.maps; - /* We give the list not free, this will be done by ypserv - xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */ + if (__builtin_expect (result == YPERR_SUCCESS, 1)) + { + *outmaplist = resp.maps; + /* We don't free the list, this will be done by ypserv + xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */ + } - return YPERR_SUCCESS; + return result; } const char * yperr_string (const int error) { + const char *str; switch (error) { case YPERR_SUCCESS: - return _("Success"); + str = N_("Success"); + break; case YPERR_BADARGS: - return _("Request arguments bad"); + str = N_("Request arguments bad"); + break; case YPERR_RPC: - return _("RPC failure on NIS operation"); + str = N_("RPC failure on NIS operation"); + break; case YPERR_DOMAIN: - return _("Can't bind to server which serves this domain"); + str = N_("Can't bind to server which serves this domain"); + break; case YPERR_MAP: - return _("No such map in server's domain"); + str = N_("No such map in server's domain"); + break; case YPERR_KEY: - return _("No such key in map"); + str = N_("No such key in map"); + break; case YPERR_YPERR: - return _("Internal NIS error"); + str = N_("Internal NIS error"); + break; case YPERR_RESRC: - return _("Local resource allocation failure"); + str = N_("Local resource allocation failure"); + break; case YPERR_NOMORE: - return _("No more records in map database"); + str = N_("No more records in map database"); + break; case YPERR_PMAP: - return _("Can't communicate with portmapper"); + str = N_("Can't communicate with portmapper"); + break; case YPERR_YPBIND: - return _("Can't communicate with ypbind"); + str = N_("Can't communicate with ypbind"); + break; case YPERR_YPSERV: - return _("Can't communicate with ypserv"); + str = N_("Can't communicate with ypserv"); + break; case YPERR_NODOM: - return _("Local domain name not set"); + str = N_("Local domain name not set"); + break; case YPERR_BADDB: - return _("NIS map database is bad"); + str = N_("NIS map database is bad"); + break; case YPERR_VERS: - return _("NIS client/server version mismatch - can't supply service"); + str = N_("NIS client/server version mismatch - can't supply service"); + break; case YPERR_ACCESS: - return _("Permission denied"); + str = N_("Permission denied"); + break; case YPERR_BUSY: - return _("Database is busy"); + str = N_("Database is busy"); + break; + default: + str = N_("Unknown NIS error code"); + break; } - return _("Unknown NIS error code"); + return _(str); } static const int8_t yp_2_yperr[] = { #define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr + YP2YPERR (TRUE, SUCCESS), + YP2YPERR (NOMORE, NOMORE), + YP2YPERR (FALSE, YPERR), + YP2YPERR (NOMAP, MAP), + YP2YPERR (NODOM, DOMAIN), YP2YPERR (NOKEY, KEY), YP2YPERR (BADOP, YPERR), YP2YPERR (BADDB, BADDB), @@ -839,7 +894,7 @@ static const int8_t yp_2_yperr[] = int ypprot_err (const int code) { - if (code < YP_VERS || code > YP_NOKEY) + if (code < YP_VERS || code > YP_NOMORE) return YPERR_YPERR; return yp_2_yperr[code - YP_VERS]; } @@ -848,19 +903,26 @@ libnsl_hidden_def (ypprot_err) const char * ypbinderr_string (const int error) { + const char *str; switch (error) { case 0: - return _("Success"); + str = N_("Success"); + break; case YPBIND_ERR_ERR: - return _("Internal ypbind error"); + str = N_("Internal ypbind error"); + break; case YPBIND_ERR_NOSERV: - return _("Domain not bound"); + str = N_("Domain not bound"); + break; case YPBIND_ERR_RESC: - return _("System resource allocation failure"); + str = N_("System resource allocation failure"); + break; default: - return _("Unknown ypbind error"); + str = N_("Unknown ypbind error"); + break; } + return _(str); } libnsl_hidden_def (ypbinderr_string) @@ -893,16 +955,22 @@ yp_update (char *domain, char *map, unsigned ypop, args.update_args.datum.yp_buf_len = datalen; args.update_args.datum.yp_buf_val = data; - if ((r = yp_master (domain, map, &master)) != 0) + if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS) return r; if (!host2netname (servername, master, domain)) { fputs (_("yp_update: cannot convert host to netname\n"), stderr); + free (master); return YPERR_YPERR; } - if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL) + clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp"); + + /* We do not need the string anymore. */ + free (master); + + if (clnt == NULL) { clnt_pcreateerror ("yp_update: clnt_create"); return YPERR_RPC; @@ -942,6 +1010,7 @@ again: { if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES) { + auth_destroy (clnt->cl_auth); clnt->cl_auth = authunix_create_default (); goto again; } diff --git a/nis/ypupdate_xdr.c b/nis/ypupdate_xdr.c index 4789e47c3e..0f5469fa23 100644 --- a/nis/ypupdate_xdr.c +++ b/nis/ypupdate_xdr.c @@ -50,6 +50,7 @@ xdr_ypupdate_args (XDR *xdrs, ypupdate_args *objp) return FALSE; return xdr_yp_buf (xdrs, &objp->datum); } +libnsl_hidden_def (xdr_ypupdate_args) bool_t xdr_ypdelete_args (XDR *xdrs, ypdelete_args *objp) @@ -58,3 +59,4 @@ xdr_ypdelete_args (XDR *xdrs, ypdelete_args *objp) return FALSE; return xdr_yp_buf (xdrs, &objp->key); } +libnsl_hidden_def (xdr_ypdelete_args) |