]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Correct handling of cached client handles.
authorUlrich Drepper <drepper@redhat.com>
Sun, 19 Dec 1999 00:14:23 +0000 (00:14 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 19 Dec 1999 00:14:23 +0000 (00:14 +0000)
nis/ypclnt.c

index af489fd467627ce3f6838f226b9695bc8f073e6a..74d460fb810739cbb21ad94a86ff3cd66613f405 100644 (file)
@@ -1,6 +1,6 @@
 /* Copyright (C) 1996, 1997, 1998, 1999 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
@@ -41,7 +41,6 @@ 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;
 
@@ -62,7 +61,6 @@ __yp_bind (const char *domain, dom_binding **ypdb)
   int clnt_sock;
   CLIENT *client;
   int is_new = 0;
-  int try;
 
   if (domain == NULL || domain[0] == '\0')
     return YPERR_BADARGS;
@@ -82,137 +80,127 @@ __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;
     }
 
-  try = 0;
-
-  do
-    {
-      ++try;
-      if (try > MAXTRIES)
-        {
-          if (is_new)
-            free (ysd);
-          return YPERR_YPBIND;
-        }
-
 #if USE_BINDINGDIR
-      if (ysd->dom_vers < 1 && try == 1) /* Try binding dir only first time */
+  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];
-         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))
            {
-             /* 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));
-                 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 == 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 (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);
-              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));
-          ysd->dom_vers = YPVERS;
-          strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
-         ysd->dom_domain[YPMAXDOMAIN] = '\0';
-        }
+         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);
+         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)
     {
@@ -228,7 +216,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
@@ -277,14 +318,26 @@ 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;
            }
+
+         ydb = NULL;
          status = YPERR_RPC;
        }
       else
@@ -310,52 +363,6 @@ do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
   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);
-
-  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)
 
@@ -373,7 +380,7 @@ yp_get_default_domain (char **outdomain)
        result = YPERR_NODOM;
       else if (strcmp (__ypdomainname, "(none)") == 0)
        {
-         /* If domainname is not set, some Systems will return "(none)" */
+         /* If domainname is not set, some systems will return "(none)" */
          __ypdomainname[0] = '\0';
          result = YPERR_NODOM;
        }
@@ -628,9 +635,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;
 
-           /* XXX We are not allowed to modify the key and val data.
-              But I don't know if all other code will continue to work,
-              so we will fix this for glibc 2.2 <kukuk@suse.de> */
+           /* 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';