-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996,1997,1998,1999,2000,2001 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
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>
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 int const MAXTRIES = 2;
static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
__libc_lock_define_initialized (static, ypbindlist_lock)
static dom_binding *__ypbindlist = NULL;
int clnt_sock;
CLIENT *client;
int is_new = 0;
- int try;
- if ((domain == NULL) || (strlen (domain) == 0))
+ if (domain == NULL || domain[0] == '\0')
return YPERR_BADARGS;
if (ypdb != 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)
+ if (ysd->dom_client == NULL)
+ {
+ /* Try binding dir at first if we have no binding */
+ char path[sizeof (BINDINGDIR) + strlen (domain) + 10];
+ struct iovec vec[2];
+ unsigned short port;
+ int fd;
+
+ sprintf (path, "%s/%s.%d", BINDINGDIR, domain, YPBINDVERS);
+ fd = open (path, O_RDONLY);
+ if (fd >= 0)
{
- 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) == sizeof (port) + sizeof (ypbr))
{
- /* 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);
+ 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;
+ ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG,
+ YPVERS, UDPTIMEOUT,
+ &ysd->dom_socket);
+
+ if (ysd->dom_client != NULL)
+ /* If the program exits, close the socket */
+ if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
+ perror ("fcntl: F_SETFD");
}
+ close (fd);
}
+ }
#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 == NULL)
+ {
+ 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 (ysd->dom_client)
+ 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 (ysd->dom_client);
- close (ysd->dom_socket);
+ clnt_destroy (client);
+ if (is_new)
+ free (ysd);
+ 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));
+ 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));
+ strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
+ ysd->dom_domain[YPMAXDOMAIN] = '\0';
+
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;
+ if (ysd->dom_client != NULL)
+ /* If the program exits, close the socket */
+ if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
+ perror ("fcntl: F_SETFD");
}
- 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)
{
{
clnt_destroy (ydb->dom_client);
ydb->dom_client = NULL;
- ydb->dom_socket = -1;
+}
+
+int
+yp_bind (const char *indomain)
+{
+ int status;
+
+ __libc_lock_lock (ypbindlist_lock);
+
+ status = __yp_bind (indomain, &__ypbindlist);
+
+ __libc_lock_unlock (ypbindlist_lock);
+
+ return status;
+}
+
+static void
+yp_unbind_locked (const char *indomain)
+{
+ dom_binding *ydbptr, *ydbptr2;
+
+ ydbptr2 = NULL;
+ ydbptr = __ypbindlist;
+
+ while (ydbptr != NULL)
+ {
+ if (strcmp (ydbptr->dom_domain, indomain) == 0)
+ {
+ dom_binding *work;
+
+ work = ydbptr;
+ if (ydbptr2 == NULL)
+ __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
bool_t use_ypbindlist = FALSE;
int try, status;
enum clnt_stat result;
+ int saved_errno = errno;
try = 0;
status = YPERR_YPERR;
{
if (use_ypbindlist)
__libc_lock_unlock (ypbindlist_lock);
+ __set_errno (saved_errno);
return YPERR_DOMAIN;
}
if (result != RPC_SUCCESS)
{
- clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
- ydb->dom_vers = -1;
- if (!use_ypbindlist)
+ /* Don't print the error message on the first try. It
+ could be that we use cached data which is now invalid. */
+ if (try != 0)
+ clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
+
+ if (use_ypbindlist)
+ {
+ /* We use ypbindlist, and the old cached data is
+ invalid. unbind now and create a new binding */
+ yp_unbind_locked (domain);
+ __libc_lock_unlock (ypbindlist_lock);
+ use_ypbindlist = FALSE;
+ }
+ else
{
__yp_unbind (ydb);
free (ydb);
- ydb = NULL;
}
- status = YPERR_RPC;;
+
+ ydb = NULL;
+ status = YPERR_RPC;
}
else
status = YPERR_SUCCESS;
ydb = NULL;
}
- return status;
-}
-
-int
-yp_bind (const char *indomain)
-{
- int status;
-
- __libc_lock_lock (ypbindlist_lock);
-
- status = __yp_bind (indomain, &__ypbindlist);
-
- __libc_lock_unlock (ypbindlist_lock);
+ __set_errno (saved_errno);
return status;
}
-void
-yp_unbind (const char *indomain)
-{
- dom_binding *ydbptr, *ydbptr2;
-
- __libc_lock_lock (ypbindlist_lock);
-
- ydbptr2 = NULL;
- ydbptr = __ypbindlist;
- while (ydbptr != NULL)
- {
- if (strcmp (ydbptr->dom_domain, indomain) == 0)
- {
- dom_binding *work;
-
- work = ydbptr;
- if (ydbptr2 == NULL)
- __ypbindlist = __ypbindlist->dom_pnext;
- else
- ydbptr2 = ydbptr->dom_pnext;
- __yp_unbind (work);
- free (work);
- break;
- }
- ydbptr2 = ydbptr;
- ydbptr = ydbptr->dom_pnext;
- }
-
- __libc_lock_unlock (ypbindlist_lock);
-
- return;
-}
__libc_lock_define_initialized (static, domainname_lock)
{
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;
}
if (__ypdomainname[0] == '\0')
if (yp_get_default_domain (&unused))
return 0;
- else if (strcmp (__ypdomainname, "(none)") == 0)
- return 0;
if (domain)
*domain = __ypdomainname;
(caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
(caddr_t) & resp);
- if (result != RPC_SUCCESS)
- return YPERR_RPC;
+ 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';
*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';
(caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
(caddr_t) & resp);
- if (result != RPC_SUCCESS)
- return YPERR_RPC;
+ 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';
result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
(caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
- if (result != RPC_SUCCESS)
- return YPERR_RPC;
+ if (result != YPERR_SUCCESS)
+ return result;
if (resp.stat != YP_TRUE)
return ypprot_err (resp.stat);
result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
(caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
- if (result != RPC_SUCCESS)
- return YPERR_RPC;
+ if (result != YPERR_SUCCESS)
+ return result;
if (resp.stat != YP_TRUE)
return ypprot_err (resp.stat);
}
static void *ypall_data;
-static int (*ypall_foreach) __P ((int status, char *key, int keylen,
- char *val, int vallen, char *data));
+static int (*ypall_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, u_long *objp)
{
while (1)
{
int keylen = resp.ypresp_all_u.val.key.keydat_len;
int vallen = resp.ypresp_all_u.val.val.valdat_len;
+ /* 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 = YP_TRUE;
memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
key[keylen] = '\0';
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;
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
+ the callback function, too. */
+ (*ypall_foreach) (*objp, NULL, 0, NULL, 0, ypall_data);
return TRUE;
}
}
CLIENT *clnt;
unsigned long status;
int clnt_sock;
+ int saved_errno = errno;
if (indomain == NULL || indomain[0] == '\0' ||
inmap == NULL || inmap == '\0')
{
if (__yp_bind (indomain, &ydb) != 0)
{
+ __set_errno (saved_errno);
return YPERR_DOMAIN;
}
- /* YPPROC_ALL get its own TCP channel to ypserv */
+ /* YPPROC_ALL get its own TCP channel to ypserv. Therefore we
+ close the socket opened by the __yp_bind call. */
+ close (ydb->dom_socket);
clnt_sock = RPC_ANYSOCK;
clnt_sin = ydb->dom_server_addr;
clnt_sin.sin_port = 0;
clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
if (clnt == NULL)
- return YPERR_PMAP;
+ {
+ __yp_unbind (ydb);
+ __set_errno (saved_errno);
+ return YPERR_PMAP;
+ }
req.domain = (char *) indomain;
req.map = (char *) inmap;
if (result != RPC_SUCCESS)
{
- 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;
+ __yp_unbind (ydb);
clnt_destroy (clnt);
- close (clnt_sock);
- if (status != YP_NOMORE)
- return ypprot_err (status);
- try++;
+ if (res == YPERR_SUCCESS && status != YP_NOMORE)
+ {
+ __set_errno (saved_errno);
+ return ypprot_err (status);
+ }
+ ++try;
}
+ __set_errno (saved_errno);
+
return res;
}
result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
(caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
- if (result != RPC_SUCCESS)
- return YPERR_RPC;
+ if (result != YPERR_SUCCESS)
+ return result;
if (resp.stat != YP_TRUE)
return ypprot_err (resp.stat);