X-Git-Url: https://sourceware.org/git/?a=blobdiff_plain;f=nis%2Fypclnt.c;h=67ac42597b33fbbbd99a110781aa7737258e2bf2;hb=e2008c38b4561c8423a8984825666d690d7941fa;hp=9b936457a548dea779c3025ea3eff694c6e8603d;hpb=a588b67da48d54f30ae101cf5d2e9fb0778f95a4;p=glibc.git diff --git a/nis/ypclnt.c b/nis/ypclnt.c index 9b936457a5..67ac42597b 100644 --- a/nis/ypclnt.c +++ b/nis/ypclnt.c @@ -1,6 +1,6 @@ -/* 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 , 1996. + Contributed by Thorsten Kukuk , 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 @@ -17,9 +17,11 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include #include #include #include +#include #include #include #include @@ -40,13 +42,12 @@ struct dom_binding 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; @@ -61,9 +62,8 @@ __yp_bind (const char *domain, dom_binding **ypdb) 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) @@ -81,146 +81,129 @@ __yp_bind (const char *domain, dom_binding **ypdb) { 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) { @@ -236,7 +219,60 @@ __yp_unbind (dom_binding *ydb) { 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 @@ -247,6 +283,7 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, bool_t use_ypbindlist = FALSE; int try, status; enum clnt_stat result; + int saved_errno = errno; try = 0; status = YPERR_YPERR; @@ -275,6 +312,7 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, { if (use_ypbindlist) __libc_lock_unlock (ypbindlist_lock); + __set_errno (saved_errno); return YPERR_DOMAIN; } @@ -283,15 +321,27 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, 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; @@ -311,55 +361,11 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, 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) @@ -375,6 +381,12 @@ yp_get_default_domain (char **outdomain) { 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; } @@ -394,8 +406,6 @@ __yp_check (char **domain) if (__ypdomainname[0] == '\0') if (yp_get_default_domain (&unused)) return 0; - else if (strcmp (__ypdomainname, "(none)") == 0) - return 0; if (domain) *domain = __ypdomainname; @@ -431,13 +441,15 @@ yp_match (const char *indomain, const char *inmap, const char *inkey, (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'; @@ -476,10 +488,14 @@ yp_first (const char *indomain, const char *inmap, char **outkey, *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'; @@ -515,17 +531,21 @@ yp_next (const char *indomain, const char *inmap, const char *inkey, (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'; @@ -553,8 +573,8 @@ yp_master (const char *indomain, const char *inmap, char **outname) 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); @@ -583,8 +603,8 @@ yp_order (const char *indomain, const char *inmap, unsigned int *outorder) 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); @@ -595,11 +615,11 @@ yp_order (const char *indomain, const char *inmap, unsigned int *outorder) } 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) { @@ -628,6 +648,10 @@ __xdr_ypresp_all (XDR * xdrs, u_long * objp) 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'; @@ -639,14 +663,13 @@ __xdr_ypresp_all (XDR * xdrs, u_long * objp) 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; } } @@ -664,6 +687,7 @@ yp_all (const char *indomain, const char *inmap, CLIENT *clnt; unsigned long status; int clnt_sock; + int saved_errno = errno; if (indomain == NULL || indomain[0] == '\0' || inmap == NULL || inmap == '\0') @@ -676,16 +700,23 @@ yp_all (const char *indomain, const char *inmap, { 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; @@ -698,20 +729,27 @@ yp_all (const char *indomain, const 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; } @@ -729,8 +767,8 @@ yp_maplist (const char *indomain, struct ypmaplist **outmaplist) 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);