-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
- Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+ Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ 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
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ 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 <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
+#include <libintl.h>
#include <rpc/rpc.h>
#include <rpcsvc/nis.h>
#include <rpcsvc/yp.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/ypupd.h>
+#include <sys/socket.h>
#include <sys/uio.h>
#include <bits/libc-lock.h>
struct sockaddr_in dom_server_addr;
int dom_socket;
CLIENT *dom_client;
- long int dom_vers;
};
typedef struct dom_binding dom_binding;
-static struct timeval RPCTIMEOUT = {25, 0};
-static struct timeval UDPTIMEOUT = {5, 0};
-static int const MAXTRIES = 5;
-static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\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];
__libc_lock_define_initialized (static, ypbindlist_lock)
-static dom_binding *__ypbindlist = NULL;
+static dom_binding *ypbindlist = NULL;
+static void
+yp_bind_client_create (const char *domain, dom_binding *ysd,
+ struct ypbind_resp *ypbr)
+{
+ ysd->dom_server_addr.sin_family = AF_INET;
+ memcpy (&ysd->dom_server_addr.sin_port,
+ ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
+ sizeof (ysd->dom_server_addr.sin_port));
+ memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
+ ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
+ sizeof (ysd->dom_server_addr.sin_addr.s_addr));
+ strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
+ ysd->dom_domain[YPMAXDOMAIN] = '\0';
+
+ ysd->dom_socket = RPC_ANYSOCK;
+#ifdef SOCK_CLOEXEC
+# define xflags SOCK_CLOEXEC
+#else
+# define xflags 0
+#endif
+ ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
+ YPVERS, UDPTIMEOUT,
+ &ysd->dom_socket,
+ UDPMSGSIZE, UDPMSGSIZE,
+ xflags);
+
+ if (ysd->dom_client != NULL)
+ {
+#ifndef SOCK_CLOEXEC
+ /* If the program exits, close the socket */
+ if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
+ perror ("fcntl: F_SETFD");
+#endif
+ }
+}
+
+#if USE_BINDINGDIR
+static void
+yp_bind_file (const char *domain, dom_binding *ysd)
+{
+ char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
+
+ snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
+ int fd = open (path, O_RDONLY);
+ if (fd >= 0)
+ {
+ /* We have a binding file and could save a RPC call. The file
+ contains a port number and the YPBIND_RESP record. The port
+ number (16 bits) can be ignored. */
+ struct ypbind_resp ypbr;
+
+ if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
+ yp_bind_client_create (domain, ysd, &ypbr);
+
+ close (fd);
+ }
+}
+#endif
+
static int
-__yp_bind (const char *domain, dom_binding **ypdb)
+yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
{
struct sockaddr_in clnt_saddr;
struct ypbind_resp ypbr;
- dom_binding *ysd = NULL;
int clnt_sock;
CLIENT *client;
+
+ 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,
+ &clnt_sock, 0, 0);
+ if (client == NULL)
+ return YPERR_YPBIND;
+
+ /* Check the port number -- should be < IPPORT_RESERVED.
+ If not, it's possible someone has registered a bogus
+ ypbind with the portmapper and is trying to trick us. */
+ if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
+ {
+ clnt_destroy (client);
+ return YPERR_YPBIND;
+ }
+
+ if (clnt_call (client, YPBINDPROC_DOMAIN,
+ (xdrproc_t) xdr_domainname, (caddr_t) &domain,
+ (xdrproc_t) xdr_ypbind_resp,
+ (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
+ {
+ clnt_destroy (client);
+ return YPERR_YPBIND;
+ }
+
+ clnt_destroy (client);
+
+ if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
+ {
+ fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
+ ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
+ return YPERR_DOMAIN;
+ }
+ memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
+
+ yp_bind_client_create (domain, ysd, &ypbr);
+
+ return YPERR_SUCCESS;
+}
+
+static int
+__yp_bind (const char *domain, dom_binding **ypdb)
+{
+ dom_binding *ysd = NULL;
int is_new = 0;
- int try;
- if ((domain == NULL) || (strlen (domain) == 0))
+ if (domain == NULL || domain[0] == '\0')
return YPERR_BADARGS;
- if (ypdb != NULL)
+ ysd = *ypdb;
+ while (ysd != NULL)
{
- ysd = *ypdb;
- while (ysd != NULL)
- {
- if (strcmp (domain, ysd->dom_domain) == 0)
- break;
- ysd = ysd->dom_pnext;
- }
+ if (strcmp (domain, ysd->dom_domain) == 0)
+ break;
+ ysd = ysd->dom_pnext;
}
if (ysd == NULL)
{
is_new = 1;
ysd = (dom_binding *) calloc (1, sizeof *ysd);
- ysd->dom_socket = -1;
- ysd->dom_vers = -1;
+ if (__builtin_expect (ysd == NULL, 0))
+ return YPERR_RESRC;
}
- try = 0;
-
- do
- {
- try++;
- if (try > MAXTRIES)
- {
- if (is_new)
- free (ysd);
- return YPERR_YPBIND;
- }
-
#if USE_BINDINGDIR
- if (ysd->dom_vers < 1 && try < 3)
- {
- char path[sizeof (BINDINGDIR) - 1 + strlen (domain) + 10];
- struct iovec vec[2];
- u_short port;
- int fd;
-
- sprintf (path, "%s/%s.%ld", BINDINGDIR, domain, YPBINDVERS);
- fd = open (path, O_RDONLY);
- if (fd >= 0)
- {
- /* We have a binding file and could save a RPC call */
- vec[0].iov_base = &port;
- vec[0].iov_len = sizeof (port);
- vec[1].iov_base = &ypbr;
- vec[1].iov_len = sizeof (ypbr);
-
- if (readv (fd, vec, 2) == vec[0].iov_len + vec[1].iov_len)
- {
- memset (&ysd->dom_server_addr, '\0',
- sizeof ysd->dom_server_addr);
- ysd->dom_server_addr.sin_family = AF_INET;
- memcpy (&ysd->dom_server_addr.sin_port,
- ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
- sizeof (ysd->dom_server_addr.sin_port));
- memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
- ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
- sizeof (ysd->dom_server_addr.sin_addr.s_addr));
- ysd->dom_vers = YPVERS;
- strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
- ysd->dom_domain[YPMAXDOMAIN] = '\0';
- }
- close (fd);
- }
- }
+ /* Try binding dir at first if we have no binding */
+ if (ysd->dom_client == NULL)
+ yp_bind_file (domain, ysd);
#endif /* USE_BINDINGDIR */
- if (ysd->dom_vers == -1)
- {
- if(ysd->dom_client)
- {
- clnt_destroy(ysd->dom_client);
- ysd->dom_client = NULL;
- ysd->dom_socket = -1;
- }
- memset (&clnt_saddr, '\0', sizeof clnt_saddr);
- clnt_saddr.sin_family = AF_INET;
- clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- clnt_sock = RPC_ANYSOCK;
- client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
- &clnt_sock, 0, 0);
- if (client == NULL)
- {
- if (is_new)
- free (ysd);
- return YPERR_YPBIND;
- }
- /*
- ** Check the port number -- should be < IPPORT_RESERVED.
- ** If not, it's possible someone has registered a bogus
- ** ypbind with the portmapper and is trying to trick us.
- */
- if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
- {
- clnt_destroy (client);
- if (is_new)
- free (ysd);
- return YPERR_YPBIND;
- }
-
- if (clnt_call (client, YPBINDPROC_DOMAIN,
- (xdrproc_t) xdr_domainname, (caddr_t) &domain,
- (xdrproc_t) xdr_ypbind_resp,
- (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
- {
- clnt_destroy (client);
- close (clnt_sock);
- if (is_new)
- free (ysd);
- return YPERR_YPBIND;
- }
-
- clnt_destroy (client);
- close (clnt_sock);
-
- if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
- {
- fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
- ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
- if (is_new)
- free (ysd);
- return YPERR_DOMAIN;
- }
- memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
- ysd->dom_server_addr.sin_family = AF_INET;
- memcpy (&ysd->dom_server_addr.sin_port,
- ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
- sizeof (ysd->dom_server_addr.sin_port));
- memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
- ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
- sizeof (ysd->dom_server_addr.sin_addr.s_addr));
- ysd->dom_vers = YPVERS;
- strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
- ysd->dom_domain[YPMAXDOMAIN] = '\0';
- }
-
- if (ysd->dom_client)
+ if (ysd->dom_client == NULL)
+ {
+ int retval = yp_bind_ypbindprog (domain, ysd);
+ if (retval != YPERR_SUCCESS)
{
- clnt_destroy (ysd->dom_client);
- close (ysd->dom_socket);
+ if (is_new)
+ free (ysd);
+ return retval;
}
- ysd->dom_socket = RPC_ANYSOCK;
- ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
- UDPTIMEOUT, &ysd->dom_socket);
- if (ysd->dom_client == NULL)
- ysd->dom_vers = -1;
-
}
- while (ysd->dom_client == NULL);
- /* If the program exists, close the socket */
- if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
- perror ("fcntl: F_SETFD");
+ if (ysd->dom_client == NULL)
+ {
+ if (is_new)
+ free (ysd);
+ return YPERR_YPSERV;
+ }
- if (is_new && ypdb != NULL)
+ if (is_new)
{
ysd->dom_pnext = *ypdb;
*ypdb = ysd;
__yp_unbind (dom_binding *ydb)
{
clnt_destroy (ydb->dom_client);
- ydb->dom_client = NULL;
- ydb->dom_socket = -1;
-}
-
-static int
-do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
- caddr_t req, xdrproc_t xres, caddr_t resp)
-{
- dom_binding *ydb = NULL;
- bool_t use_ypbindlist = FALSE;
- int try, status;
- enum clnt_stat result;
- int saved_errno = errno;
-
- try = 0;
- status = YPERR_YPERR;
-
- __libc_lock_lock (ypbindlist_lock);
- if (__ypbindlist != NULL)
- {
- ydb = __ypbindlist;
- while (ydb != NULL)
- {
- if (strcmp (domain, ydb->dom_domain) == 0)
- break;
- ydb = ydb->dom_pnext;
- }
- if (ydb != NULL)
- use_ypbindlist = TRUE;
- else
- __libc_lock_unlock (ypbindlist_lock);
- }
- else
- __libc_lock_unlock (ypbindlist_lock);
-
- while (try < MAXTRIES && status != YPERR_SUCCESS)
- {
- if (__yp_bind (domain, &ydb) != 0)
- {
- if (use_ypbindlist)
- __libc_lock_unlock (ypbindlist_lock);
- __set_errno (saved_errno);
- return YPERR_DOMAIN;
- }
-
- result = clnt_call (ydb->dom_client, prog,
- xargs, req, xres, resp, RPCTIMEOUT);
-
- if (result != RPC_SUCCESS)
- {
- clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
- ydb->dom_vers = -1;
- if (!use_ypbindlist)
- {
- __yp_unbind (ydb);
- free (ydb);
- ydb = NULL;
- }
- status = YPERR_RPC;;
- }
- else
- status = YPERR_SUCCESS;
-
- try++;
- }
- if (use_ypbindlist)
- {
- __libc_lock_unlock (ypbindlist_lock);
- use_ypbindlist = FALSE;
- }
- else
- if (ydb != NULL)
- {
- __yp_unbind (ydb);
- free (ydb);
- ydb = NULL;
- }
-
- __set_errno (saved_errno);
-
- return status;
+ free (ydb);
}
int
__libc_lock_lock (ypbindlist_lock);
- status = __yp_bind (indomain, &__ypbindlist);
+ status = __yp_bind (indomain, &ypbindlist);
__libc_lock_unlock (ypbindlist_lock);
return status;
}
+libnsl_hidden_def (yp_bind)
-void
-yp_unbind (const char *indomain)
+static void
+yp_unbind_locked (const char *indomain)
{
dom_binding *ydbptr, *ydbptr2;
- __libc_lock_lock (ypbindlist_lock);
-
ydbptr2 = NULL;
- ydbptr = __ypbindlist;
+ ydbptr = ypbindlist;
+
while (ydbptr != NULL)
{
if (strcmp (ydbptr->dom_domain, indomain) == 0)
work = ydbptr;
if (ydbptr2 == NULL)
- __ypbindlist = __ypbindlist->dom_pnext;
+ ypbindlist = ypbindlist->dom_pnext;
else
ydbptr2 = ydbptr->dom_pnext;
__yp_unbind (work);
- free (work);
break;
}
ydbptr2 = ydbptr;
ydbptr = ydbptr->dom_pnext;
}
+}
+
+void
+yp_unbind (const char *indomain)
+{
+ __libc_lock_lock (ypbindlist_lock);
+
+ yp_unbind_locked (indomain);
__libc_lock_unlock (ypbindlist_lock);
return;
}
+static int
+__ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
+ caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
+ int print_error)
+{
+ enum clnt_stat result;
+
+ result = clnt_call ((*ydb)->dom_client, prog,
+ xargs, req, xres, resp, RPCTIMEOUT);
+
+ if (result != RPC_SUCCESS)
+ {
+ /* We don't print an error message, if we try our old,
+ cached data. Only print this for data, which should work. */
+ if (print_error)
+ clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
+
+ return YPERR_RPC;
+ }
+
+ return YPERR_SUCCESS;
+}
+
+static int
+do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
+ caddr_t req, xdrproc_t xres, caddr_t resp)
+{
+ dom_binding *ydb;
+ int status;
+ int saved_errno = errno;
+
+ status = YPERR_YPERR;
+
+ __libc_lock_lock (ypbindlist_lock);
+ ydb = ypbindlist;
+ while (ydb != NULL)
+ {
+ if (strcmp (domain, ydb->dom_domain) == 0)
+ {
+ if (__yp_bind (domain, &ydb) == 0)
+ {
+ /* Call server, print no error message, do not unbind. */
+ status = __ypclnt_call (domain, prog, xargs, req, xres,
+ resp, &ydb, 0);
+ if (status == YPERR_SUCCESS)
+ {
+ __libc_lock_unlock (ypbindlist_lock);
+ __set_errno (saved_errno);
+ return status;
+ }
+ }
+ /* We use ypbindlist, and the old cached data is
+ invalid. unbind now and create a new binding */
+ yp_unbind_locked (domain);
+
+ break;
+ }
+ ydb = ydb->dom_pnext;
+ }
+ __libc_lock_unlock (ypbindlist_lock);
+
+ /* First try with cached data failed. Now try to get
+ current data from the system. */
+ ydb = NULL;
+ if (__yp_bind (domain, &ydb) == 0)
+ {
+ status = __ypclnt_call (domain, prog, xargs, req, xres,
+ resp, &ydb, 1);
+ __yp_unbind (ydb);
+ }
+
+#if USE_BINDINGDIR
+ /* If we support binding dir data, we have a third chance:
+ Ask ypbind. */
+ if (status != YPERR_SUCCESS)
+ {
+ ydb = calloc (1, sizeof (dom_binding));
+ if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
+ {
+ status = __ypclnt_call (domain, prog, xargs, req, xres,
+ resp, &ydb, 1);
+ __yp_unbind (ydb);
+ }
+ else
+ free (ydb);
+ }
+#endif
+
+ __set_errno (saved_errno);
+
+ 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)
int
__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)
+ {
+ /* If domainname is not set, some systems will return "(none)" */
+ ypdomainname[0] = '\0';
+ result = YPERR_NODOM;
+ }
else
- *outdomain = __ypdomainname;
+ *outdomain = ypdomainname;
}
else
- *outdomain = __ypdomainname;
+ *outdomain = ypdomainname;
__libc_lock_unlock (domainname_lock);
return result;
}
+libnsl_hidden_def (yp_get_default_domain)
int
__yp_check (char **domain)
{
char *unused;
- if (__ypdomainname[0] == '\0')
+ if (ypdomainname[0] == '\0')
if (yp_get_default_domain (&unused))
return 0;
- else if (strcmp (__ypdomainname, "(none)") == 0)
- return 0;
if (domain)
- *domain = __ypdomainname;
+ *domain = ypdomainname;
- if (yp_bind (__ypdomainname) == 0)
+ if (yp_bind (ypdomainname) == 0)
return 1;
return 0;
}
*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);
- 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
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);
- memcpy (*outkey, resp.key.keydat_val, *outkeylen);
- (*outkey)[*outkeylen] = '\0';
- *outvallen = resp.val.valdat_len;
- *outval = malloc (*outvallen + 1);
- 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
*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);
- memcpy (*outkey, resp.key.keydat_val, *outkeylen);
- (*outkey)[*outkeylen] = '\0';
- *outvallen = resp.val.valdat_len;
- *outval = malloc (*outvallen + 1);
- 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
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);
return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
}
+libnsl_hidden_def (yp_master)
int
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;
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)
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;
}
-static void *ypall_data;
-static int (*ypall_foreach) __P ((int status, char *key, int keylen,
- char *val, int vallen, char *data));
+struct ypresp_all_data
+{
+ unsigned long status;
+ void *data;
+ int (*foreach) (int status, char *key, int keylen,
+ char *val, int vallen, char *data);
+};
static bool_t
-__xdr_ypresp_all (XDR * xdrs, u_long * objp)
+__xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
{
while (1)
{
if (!xdr_ypresp_all (xdrs, &resp))
{
xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
- *objp = YP_YPERR;
+ objp->status = YP_YPERR;
return FALSE;
}
if (resp.more == 0)
{
xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
- *objp = YP_NOMORE;
+ objp->status = YP_NOMORE;
return TRUE;
}
int keylen = resp.ypresp_all_u.val.key.keydat_len;
int vallen = resp.ypresp_all_u.val.val.valdat_len;
- *objp = 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';
+ /* We are not allowed to modify the key and val data.
+ But we are allowed to add data behind the buffer,
+ if we don't modify the length. So add an extra NUL
+ character to avoid trouble with broken code. */
+ objp->status = YP_TRUE;
+ *((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 ((*ypall_foreach) (*objp, key, keylen,
- val, vallen, ypall_data))
+ if ((*objp->foreach) (objp->status, key, keylen,
+ val, vallen, objp->data))
return TRUE;
}
break;
- case YP_NOMORE:
- *objp = YP_NOMORE;
- xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
- return TRUE;
- break;
default:
- *objp = resp.ypresp_all_u.val.stat;
+ 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
+ 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;
}
}
enum clnt_stat result;
struct sockaddr_in clnt_sin;
CLIENT *clnt;
- unsigned long status;
+ struct ypresp_all_data data;
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;
return YPERR_DOMAIN;
}
- /* YPPROC_ALL get its own TCP channel to ypserv */
clnt_sock = RPC_ANYSOCK;
clnt_sin = ydb->dom_server_addr;
clnt_sin.sin_port = 0;
+
+ /* We don't need the UDP connection anymore. */
+ __yp_unbind (ydb);
+ ydb = NULL;
+
clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
if (clnt == NULL)
{
req.domain = (char *) indomain;
req.map = (char *) inmap;
- ypall_foreach = incallback->foreach;
- ypall_data = (void *) incallback->data;
+ data.foreach = incallback->foreach;
+ data.data = (void *) incallback->data;
result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
(caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
- (caddr_t) &status, RPCTIMEOUT);
+ (caddr_t) &data, RPCTIMEOUT);
- if (result != RPC_SUCCESS)
+ if (__builtin_expect (result != RPC_SUCCESS, 0))
{
- clnt_perror (clnt, "yp_all: clnt_call");
+ /* Print the error message only on the last try. */
+ if (try == MAXTRIES - 1)
+ clnt_perror (clnt, "yp_all: clnt_call");
res = YPERR_RPC;
}
else
res = YPERR_SUCCESS;
clnt_destroy (clnt);
- close (clnt_sock);
- if (status != YP_NOMORE)
+ if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
{
__set_errno (saved_errno);
- return ypprot_err (status);
+ return ypprot_err (data.status);
}
++try;
}
}
int
+
yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
{
struct ypresp_maplist resp;
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),
+ YP2YPERR (YPERR, YPERR),
+ YP2YPERR (BADARGS, BADARGS),
+ YP2YPERR (VERS, VERS)
+ };
int
ypprot_err (const int code)
{
- switch (code)
- {
- case YP_TRUE:
- return YPERR_SUCCESS;
- case YP_NOMORE:
- return YPERR_NOMORE;
- case YP_FALSE:
- return YPERR_YPERR;
- case YP_NOMAP:
- return YPERR_MAP;
- case YP_NODOM:
- return YPERR_DOMAIN;
- case YP_NOKEY:
- return YPERR_KEY;
- case YP_BADOP:
- return YPERR_YPERR;
- case YP_BADDB:
- return YPERR_BADDB;
- case YP_YPERR:
- return YPERR_YPERR;
- case YP_BADARGS:
- return YPERR_BADARGS;
- case YP_VERS:
- return YPERR_VERS;
- }
- return YPERR_YPERR;
+ if (code < YP_VERS || code > YP_NOMORE)
+ return YPERR_YPERR;
+ return yp_2_yperr[code - YP_VERS];
}
+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)
#define WINDOW 60
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;
{
if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
{
+ auth_destroy (clnt->cl_auth);
clnt->cl_auth = authunix_create_default ();
goto again;
}