* nis/ypclnt.c (__yp_bind_client_create): New, small chunk

of duplicated code from __yp_bind.
	(__yp_bind_file): New, binding dir code from __yp_bind.
	(__yp_bind_client_create): New, ypbind code from __yp_bind.
	(__ypclnt_call): New, make NIS query.
	(do_ypcall): At first use cached data, then try data from
	binding directory, after this ask ypbind for a working ypserv.
	Based on a patch from Jeff Bastian <jmbastia@ti.com> and
	Chris Barrera <cbarrera@ti.com>
This commit is contained in:
Roland McGrath 2004-02-09 20:33:35 +00:00
parent fe54a69c1c
commit 57be8a82ed
2 changed files with 181 additions and 155 deletions

View File

@ -1,3 +1,15 @@
2004-02-03 Thorsten Kukuk <kukuk@suse.de>
* nis/ypclnt.c (__yp_bind_client_create): New, small chunk
of duplicated code from __yp_bind.
(__yp_bind_file): New, binding dir code from __yp_bind.
(__yp_bind_client_create): New, ypbind code from __yp_bind.
(__ypclnt_call): New, make NIS query.
(do_ypcall): At first use cached data, then try data from
binding directory, after this ask ypbind for a working ypserv.
Based on a patch from Jeff Bastian <jmbastia@ti.com> and
Chris Barrera <cbarrera@ti.com>
2004-01-19 Roland McGrath <roland@redhat.com> 2004-01-19 Roland McGrath <roland@redhat.com>
* configure.in: Don't set CCVERSION. * configure.in: Don't set CCVERSION.

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. /* Copyright (C) 1996-2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
@ -53,14 +53,112 @@ __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;
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");
}
}
static void
__yp_bind_file (const char *domain, dom_binding *ysd)
{
struct ypbind_resp ypbr;
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)
{
/* 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))
__yp_bind_client_create (domain, ysd, &ypbr);
close (fd);
}
}
static int 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 sockaddr_in clnt_saddr;
struct ypbind_resp ypbr; struct ypbind_resp ypbr;
dom_binding *ysd = NULL;
int clnt_sock; int clnt_sock;
CLIENT *client; CLIENT *client;
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)
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 is_new = 0;
if (domain == NULL || domain[0] == '\0') if (domain == NULL || domain[0] == '\0')
@ -83,116 +181,20 @@ __yp_bind (const char *domain, dom_binding **ypdb)
} }
#if USE_BINDINGDIR #if USE_BINDINGDIR
if (ysd->dom_client == NULL)
{
/* Try binding dir at first if we have no binding */ /* Try binding dir at first if we have no binding */
char path[sizeof (BINDINGDIR) + strlen (domain) + 10]; if (ysd->dom_client == NULL)
struct iovec vec[2]; __yp_bind_file (domain, ysd);
unsigned short port;
int fd;
sprintf (path, "%s/%s.%d", 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))
{
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 */ #endif /* USE_BINDINGDIR */
if (ysd->dom_client == NULL) if (ysd->dom_client == NULL)
{ {
memset (&clnt_saddr, '\0', sizeof clnt_saddr); int retval = __yp_bind_ypbindprog (domain, ysd);
clnt_saddr.sin_family = AF_INET; if (retval != YPERR_SUCCESS)
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) if (is_new)
free (ysd); free (ysd);
return YPERR_YPBIND; return retval;
} }
/* 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);
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)
/* If the program exits, close the socket */
if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
perror ("fcntl: F_SETFD");
} }
if (ysd->dom_client == NULL) if (ysd->dom_client == NULL)
@ -215,7 +217,6 @@ static void
__yp_unbind (dom_binding *ydb) __yp_unbind (dom_binding *ydb)
{ {
clnt_destroy (ydb->dom_client); clnt_destroy (ydb->dom_client);
ydb->dom_client = NULL;
free (ydb); free (ydb);
} }
@ -272,17 +273,37 @@ yp_unbind (const char *indomain)
return; 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 static int
do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
caddr_t req, xdrproc_t xres, caddr_t resp) caddr_t req, xdrproc_t xres, caddr_t resp)
{ {
dom_binding *ydb = NULL; dom_binding *ydb;
bool_t use_ypbindlist = FALSE; int status;
int try, status;
enum clnt_stat result;
int saved_errno = errno; int saved_errno = errno;
try = 0;
status = YPERR_YPERR; status = YPERR_YPERR;
__libc_lock_lock (ypbindlist_lock); __libc_lock_lock (ypbindlist_lock);
@ -296,60 +317,53 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
ydb = ydb->dom_pnext; ydb = ydb->dom_pnext;
} }
if (ydb != NULL) if (ydb != NULL)
use_ypbindlist = TRUE; {
else if (__yp_bind (domain, &ydb) == 0)
__libc_lock_unlock (ypbindlist_lock); {
/* Call server, print no error message, do not unbind. */
status = __ypclnt_call (domain, prog, xargs, req, xres,
resp, &ydb, 0);
if (status == YPERR_SUCCESS)
{
__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);
}
__libc_lock_unlock (ypbindlist_lock);
} }
else else
__libc_lock_unlock (ypbindlist_lock); __libc_lock_unlock (ypbindlist_lock);
while (try < MAXTRIES && status != YPERR_SUCCESS) /* First try with cached data failed. Now try to get
current data from the system. */
ydb = NULL;
if (__yp_bind (domain, &ydb) == 0)
{ {
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 (__yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
{ {
if (use_ypbindlist) status = __ypclnt_call (domain, prog, xargs, req, xres,
__libc_lock_unlock (ypbindlist_lock); resp, &ydb, 1);
__set_errno (saved_errno); __yp_unbind (ydb);
return YPERR_DOMAIN;
}
result = clnt_call (ydb->dom_client, prog,
xargs, req, xres, resp, RPCTIMEOUT);
if (result != RPC_SUCCESS)
{
/* 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);
ydb = NULL;
status = YPERR_RPC;
} }
else else
status = YPERR_SUCCESS; free (ydb);
try++;
} }
if (use_ypbindlist) #endif
{
__libc_lock_unlock (ypbindlist_lock);
use_ypbindlist = FALSE;
}
else
if (ydb != NULL)
__yp_unbind (ydb);
__set_errno (saved_errno); __set_errno (saved_errno);