Back to index

glibc  2.9
ypclnt.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #include <libintl.h>
00026 #include <rpc/rpc.h>
00027 #include <rpcsvc/nis.h>
00028 #include <rpcsvc/yp.h>
00029 #include <rpcsvc/ypclnt.h>
00030 #include <rpcsvc/ypupd.h>
00031 #include <sys/socket.h>
00032 #include <sys/uio.h>
00033 #include <bits/libc-lock.h>
00034 
00035 /* This should only be defined on systems with a BSD compatible ypbind */
00036 #ifndef BINDINGDIR
00037 # define BINDINGDIR "/var/yp/binding"
00038 #endif
00039 
00040 struct dom_binding
00041   {
00042     struct dom_binding *dom_pnext;
00043     char dom_domain[YPMAXDOMAIN + 1];
00044     struct sockaddr_in dom_server_addr;
00045     int dom_socket;
00046     CLIENT *dom_client;
00047   };
00048 typedef struct dom_binding dom_binding;
00049 
00050 static const struct timeval RPCTIMEOUT = {25, 0};
00051 static const struct timeval UDPTIMEOUT = {5, 0};
00052 static int const MAXTRIES = 2;
00053 static char ypdomainname[NIS_MAXNAMELEN + 1];
00054 __libc_lock_define_initialized (static, ypbindlist_lock)
00055 static dom_binding *ypbindlist = NULL;
00056 
00057 
00058 static void
00059 yp_bind_client_create (const char *domain, dom_binding *ysd,
00060                      struct ypbind_resp *ypbr)
00061 {
00062   ysd->dom_server_addr.sin_family = AF_INET;
00063   memcpy (&ysd->dom_server_addr.sin_port,
00064          ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
00065          sizeof (ysd->dom_server_addr.sin_port));
00066   memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
00067          ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
00068          sizeof (ysd->dom_server_addr.sin_addr.s_addr));
00069   strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
00070   ysd->dom_domain[YPMAXDOMAIN] = '\0';
00071 
00072   ysd->dom_socket = RPC_ANYSOCK;
00073 #ifdef SOCK_CLOEXEC
00074 # define xflags SOCK_CLOEXEC
00075 #else
00076 # define xflags 0
00077 #endif
00078   ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
00079                                          YPVERS, UDPTIMEOUT,
00080                                          &ysd->dom_socket,
00081                                          UDPMSGSIZE, UDPMSGSIZE,
00082                                          xflags);
00083 
00084   if (ysd->dom_client != NULL)
00085     {
00086 #ifndef SOCK_CLOEXEC
00087       /* If the program exits, close the socket */
00088       if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
00089        perror ("fcntl: F_SETFD");
00090 #endif
00091     }
00092 }
00093 
00094 #if USE_BINDINGDIR
00095 static void
00096 yp_bind_file (const char *domain, dom_binding *ysd)
00097 {
00098   char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
00099 
00100   snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
00101   int fd = open (path, O_RDONLY);
00102   if (fd >= 0)
00103     {
00104       /* We have a binding file and could save a RPC call.  The file
00105         contains a port number and the YPBIND_RESP record.  The port
00106         number (16 bits) can be ignored.  */
00107       struct ypbind_resp ypbr;
00108 
00109       if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
00110        yp_bind_client_create (domain, ysd, &ypbr);
00111 
00112       close (fd);
00113     }
00114 }
00115 #endif
00116 
00117 static int
00118 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
00119 {
00120   struct sockaddr_in clnt_saddr;
00121   struct ypbind_resp ypbr;
00122   int clnt_sock;
00123   CLIENT *client;
00124 
00125   clnt_saddr.sin_family = AF_INET;
00126   clnt_saddr.sin_port = 0;
00127   clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
00128   clnt_sock = RPC_ANYSOCK;
00129   client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
00130                         &clnt_sock, 0, 0);
00131   if (client == NULL)
00132     return YPERR_YPBIND;
00133 
00134   /* Check the port number -- should be < IPPORT_RESERVED.
00135      If not, it's possible someone has registered a bogus
00136      ypbind with the portmapper and is trying to trick us. */
00137   if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
00138     {
00139       clnt_destroy (client);
00140       return YPERR_YPBIND;
00141     }
00142 
00143   if (clnt_call (client, YPBINDPROC_DOMAIN,
00144                (xdrproc_t) xdr_domainname, (caddr_t) &domain,
00145                (xdrproc_t) xdr_ypbind_resp,
00146                (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
00147     {
00148       clnt_destroy (client);
00149       return YPERR_YPBIND;
00150     }
00151 
00152   clnt_destroy (client);
00153 
00154   if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
00155     {
00156       fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
00157               ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
00158       return YPERR_DOMAIN;
00159     }
00160   memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
00161 
00162   yp_bind_client_create (domain, ysd, &ypbr);
00163 
00164   return YPERR_SUCCESS;
00165 }
00166 
00167 static int
00168 __yp_bind (const char *domain, dom_binding **ypdb)
00169 {
00170   dom_binding *ysd = NULL;
00171   int is_new = 0;
00172 
00173   if (domain == NULL || domain[0] == '\0')
00174     return YPERR_BADARGS;
00175 
00176   ysd = *ypdb;
00177   while (ysd != NULL)
00178     {
00179       if (strcmp (domain, ysd->dom_domain) == 0)
00180        break;
00181       ysd = ysd->dom_pnext;
00182     }
00183 
00184   if (ysd == NULL)
00185     {
00186       is_new = 1;
00187       ysd = (dom_binding *) calloc (1, sizeof *ysd);
00188       if (__builtin_expect (ysd == NULL, 0))
00189        return YPERR_RESRC;
00190     }
00191 
00192 #if USE_BINDINGDIR
00193   /* Try binding dir at first if we have no binding */
00194   if (ysd->dom_client == NULL)
00195     yp_bind_file (domain, ysd);
00196 #endif /* USE_BINDINGDIR */
00197 
00198   if (ysd->dom_client == NULL)
00199     {
00200       int retval = yp_bind_ypbindprog (domain, ysd);
00201       if (retval != YPERR_SUCCESS)
00202        {
00203          if (is_new)
00204            free (ysd);
00205          return retval;
00206        }
00207     }
00208 
00209   if (ysd->dom_client == NULL)
00210     {
00211       if (is_new)
00212        free (ysd);
00213       return YPERR_YPSERV;
00214     }
00215 
00216   if (is_new)
00217     {
00218       ysd->dom_pnext = *ypdb;
00219       *ypdb = ysd;
00220     }
00221 
00222   return YPERR_SUCCESS;
00223 }
00224 
00225 static void
00226 __yp_unbind (dom_binding *ydb)
00227 {
00228   clnt_destroy (ydb->dom_client);
00229   free (ydb);
00230 }
00231 
00232 int
00233 yp_bind (const char *indomain)
00234 {
00235   int status;
00236 
00237   __libc_lock_lock (ypbindlist_lock);
00238 
00239   status = __yp_bind (indomain, &ypbindlist);
00240 
00241   __libc_lock_unlock (ypbindlist_lock);
00242 
00243   return status;
00244 }
00245 libnsl_hidden_def (yp_bind)
00246 
00247 static void
00248 yp_unbind_locked (const char *indomain)
00249 {
00250   dom_binding *ydbptr, *ydbptr2;
00251 
00252   ydbptr2 = NULL;
00253   ydbptr = ypbindlist;
00254 
00255   while (ydbptr != NULL)
00256     {
00257       if (strcmp (ydbptr->dom_domain, indomain) == 0)
00258        {
00259          dom_binding *work;
00260 
00261          work = ydbptr;
00262          if (ydbptr2 == NULL)
00263            ypbindlist = ypbindlist->dom_pnext;
00264          else
00265            ydbptr2 = ydbptr->dom_pnext;
00266          __yp_unbind (work);
00267          break;
00268        }
00269       ydbptr2 = ydbptr;
00270       ydbptr = ydbptr->dom_pnext;
00271     }
00272 }
00273 
00274 void
00275 yp_unbind (const char *indomain)
00276 {
00277   __libc_lock_lock (ypbindlist_lock);
00278 
00279   yp_unbind_locked (indomain);
00280 
00281   __libc_lock_unlock (ypbindlist_lock);
00282 
00283   return;
00284 }
00285 
00286 static int
00287 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
00288               caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
00289               int print_error)
00290 {
00291   enum clnt_stat result;
00292 
00293   result = clnt_call ((*ydb)->dom_client, prog,
00294                     xargs, req, xres, resp, RPCTIMEOUT);
00295 
00296   if (result != RPC_SUCCESS)
00297     {
00298       /* We don't print an error message, if we try our old,
00299         cached data. Only print this for data, which should work.  */
00300       if (print_error)
00301        clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
00302 
00303       return YPERR_RPC;
00304     }
00305 
00306   return YPERR_SUCCESS;
00307 }
00308 
00309 static int
00310 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
00311           caddr_t req, xdrproc_t xres, caddr_t resp)
00312 {
00313   dom_binding *ydb;
00314   int status;
00315   int saved_errno = errno;
00316 
00317   status = YPERR_YPERR;
00318 
00319   __libc_lock_lock (ypbindlist_lock);
00320   ydb = ypbindlist;
00321   while (ydb != NULL)
00322     {
00323       if (strcmp (domain, ydb->dom_domain) == 0)
00324        {
00325           if (__yp_bind (domain, &ydb) == 0)
00326            {
00327              /* Call server, print no error message, do not unbind.  */
00328              status = __ypclnt_call (domain, prog, xargs, req, xres,
00329                                   resp, &ydb, 0);
00330              if (status == YPERR_SUCCESS)
00331                {
00332                 __libc_lock_unlock (ypbindlist_lock);
00333                  __set_errno (saved_errno);
00334                  return status;
00335                }
00336            }
00337          /* We use ypbindlist, and the old cached data is
00338             invalid. unbind now and create a new binding */
00339          yp_unbind_locked (domain);
00340 
00341          break;
00342        }
00343       ydb = ydb->dom_pnext;
00344     }
00345   __libc_lock_unlock (ypbindlist_lock);
00346 
00347   /* First try with cached data failed. Now try to get
00348      current data from the system.  */
00349   ydb = NULL;
00350   if (__yp_bind (domain, &ydb) == 0)
00351     {
00352       status = __ypclnt_call (domain, prog, xargs, req, xres,
00353                            resp, &ydb, 1);
00354       __yp_unbind (ydb);
00355     }
00356 
00357 #if USE_BINDINGDIR
00358   /* If we support binding dir data, we have a third chance:
00359      Ask ypbind.  */
00360   if (status != YPERR_SUCCESS)
00361     {
00362       ydb = calloc (1, sizeof (dom_binding));
00363       if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
00364        {
00365          status = __ypclnt_call (domain, prog, xargs, req, xres,
00366                               resp, &ydb, 1);
00367          __yp_unbind (ydb);
00368        }
00369       else
00370        free (ydb);
00371     }
00372 #endif
00373 
00374   __set_errno (saved_errno);
00375 
00376   return status;
00377 }
00378 
00379 /* Like do_ypcall, but translate the status value if necessary.  */
00380 static int
00381 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
00382              caddr_t req, xdrproc_t xres, caddr_t resp)
00383 {
00384   int status = do_ypcall (domain, prog, xargs, req, xres, resp);
00385   if (status == YPERR_SUCCESS)
00386     /* We cast to ypresp_val although the pointer could also be of
00387        type ypresp_key_val or ypresp_master or ypresp_order or
00388        ypresp_maplist.  But the stat element is in a common prefix so
00389        this does not matter.  */
00390     status = ypprot_err (((struct ypresp_val *) resp)->stat);
00391   return status;
00392 }
00393 
00394 
00395 __libc_lock_define_initialized (static, domainname_lock)
00396 
00397 int
00398 yp_get_default_domain (char **outdomain)
00399 {
00400   int result = YPERR_SUCCESS;;
00401   *outdomain = NULL;
00402 
00403   __libc_lock_lock (domainname_lock);
00404 
00405   if (ypdomainname[0] == '\0')
00406     {
00407       if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
00408        result = YPERR_NODOM;
00409       else if (strcmp (ypdomainname, "(none)") == 0)
00410        {
00411          /* If domainname is not set, some systems will return "(none)" */
00412          ypdomainname[0] = '\0';
00413          result = YPERR_NODOM;
00414        }
00415       else
00416        *outdomain = ypdomainname;
00417     }
00418   else
00419     *outdomain = ypdomainname;
00420 
00421   __libc_lock_unlock (domainname_lock);
00422 
00423   return result;
00424 }
00425 libnsl_hidden_def (yp_get_default_domain)
00426 
00427 int
00428 __yp_check (char **domain)
00429 {
00430   char *unused;
00431 
00432   if (ypdomainname[0] == '\0')
00433     if (yp_get_default_domain (&unused))
00434       return 0;
00435 
00436   if (domain)
00437     *domain = ypdomainname;
00438 
00439   if (yp_bind (ypdomainname) == 0)
00440     return 1;
00441   return 0;
00442 }
00443 
00444 int
00445 yp_match (const char *indomain, const char *inmap, const char *inkey,
00446          const int inkeylen, char **outval, int *outvallen)
00447 {
00448   ypreq_key req;
00449   ypresp_val resp;
00450   enum clnt_stat result;
00451 
00452   if (indomain == NULL || indomain[0] == '\0' ||
00453       inmap == NULL || inmap[0] == '\0' ||
00454       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
00455     return YPERR_BADARGS;
00456 
00457   req.domain = (char *) indomain;
00458   req.map = (char *) inmap;
00459   req.key.keydat_val = (char *) inkey;
00460   req.key.keydat_len = inkeylen;
00461 
00462   *outval = NULL;
00463   *outvallen = 0;
00464   memset (&resp, '\0', sizeof (resp));
00465 
00466   result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
00467                       (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
00468                       (caddr_t) &resp);
00469 
00470   if (result != YPERR_SUCCESS)
00471     return result;
00472 
00473   *outvallen = resp.val.valdat_len;
00474   *outval = malloc (*outvallen + 1);
00475   int status = YPERR_RESRC;
00476   if (__builtin_expect (*outval != NULL, 1))
00477     {
00478       memcpy (*outval, resp.val.valdat_val, *outvallen);
00479       (*outval)[*outvallen] = '\0';
00480       status = YPERR_SUCCESS;
00481     }
00482 
00483   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
00484 
00485   return status;
00486 }
00487 
00488 int
00489 yp_first (const char *indomain, const char *inmap, char **outkey,
00490          int *outkeylen, char **outval, int *outvallen)
00491 {
00492   ypreq_nokey req;
00493   ypresp_key_val resp;
00494   enum clnt_stat result;
00495 
00496   if (indomain == NULL || indomain[0] == '\0' ||
00497       inmap == NULL || inmap[0] == '\0')
00498     return YPERR_BADARGS;
00499 
00500   req.domain = (char *) indomain;
00501   req.map = (char *) inmap;
00502 
00503   *outkey = *outval = NULL;
00504   *outkeylen = *outvallen = 0;
00505   memset (&resp, '\0', sizeof (resp));
00506 
00507   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
00508                     (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
00509                     (caddr_t) &resp);
00510 
00511   if (result != RPC_SUCCESS)
00512     return YPERR_RPC;
00513   if (resp.stat != YP_TRUE)
00514     return ypprot_err (resp.stat);
00515 
00516   int status;
00517   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
00518                      && (*outval = malloc (resp.val.valdat_len
00519                                          + 1)) != NULL, 1))
00520     {
00521       *outkeylen = resp.key.keydat_len;
00522       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
00523       (*outkey)[*outkeylen] = '\0';
00524 
00525       *outvallen = resp.val.valdat_len;
00526       memcpy (*outval, resp.val.valdat_val, *outvallen);
00527       (*outval)[*outvallen] = '\0';
00528 
00529       status = YPERR_SUCCESS;
00530     }
00531   else
00532     {
00533       free (*outkey);
00534       status = YPERR_RESRC;
00535     }
00536 
00537   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
00538 
00539   return status;
00540 }
00541 
00542 int
00543 yp_next (const char *indomain, const char *inmap, const char *inkey,
00544         const int inkeylen, char **outkey, int *outkeylen, char **outval,
00545         int *outvallen)
00546 {
00547   ypreq_key req;
00548   ypresp_key_val resp;
00549   enum clnt_stat result;
00550 
00551   if (indomain == NULL || indomain[0] == '\0' ||
00552       inmap == NULL || inmap[0] == '\0' ||
00553       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
00554     return YPERR_BADARGS;
00555 
00556   req.domain = (char *) indomain;
00557   req.map = (char *) inmap;
00558   req.key.keydat_val = (char *) inkey;
00559   req.key.keydat_len = inkeylen;
00560 
00561   *outkey = *outval = NULL;
00562   *outkeylen = *outvallen = 0;
00563   memset (&resp, '\0', sizeof (resp));
00564 
00565   result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
00566                       (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
00567                       (caddr_t) &resp);
00568 
00569   if (result != YPERR_SUCCESS)
00570     return result;
00571 
00572   int status;
00573   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
00574                      && (*outval = malloc (resp.val.valdat_len
00575                                          + 1)) != NULL, 1))
00576     {
00577       *outkeylen = resp.key.keydat_len;
00578       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
00579       (*outkey)[*outkeylen] = '\0';
00580 
00581       *outvallen = resp.val.valdat_len;
00582       memcpy (*outval, resp.val.valdat_val, *outvallen);
00583       (*outval)[*outvallen] = '\0';
00584 
00585       status = YPERR_SUCCESS;
00586     }
00587   else
00588     {
00589       free (*outkey);
00590       status = YPERR_RESRC;
00591     }
00592 
00593   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
00594 
00595   return status;
00596 }
00597 
00598 int
00599 yp_master (const char *indomain, const char *inmap, char **outname)
00600 {
00601   ypreq_nokey req;
00602   ypresp_master resp;
00603   enum clnt_stat result;
00604 
00605   if (indomain == NULL || indomain[0] == '\0' ||
00606       inmap == NULL || inmap[0] == '\0')
00607     return YPERR_BADARGS;
00608 
00609   req.domain = (char *) indomain;
00610   req.map = (char *) inmap;
00611 
00612   memset (&resp, '\0', sizeof (ypresp_master));
00613 
00614   result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
00615                       (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
00616                       (caddr_t) &resp);
00617 
00618   if (result != YPERR_SUCCESS)
00619     return result;
00620 
00621   *outname = strdup (resp.peer);
00622   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
00623 
00624   return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
00625 }
00626 libnsl_hidden_def (yp_master)
00627 
00628 int
00629 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
00630 {
00631   struct ypreq_nokey req;
00632   struct ypresp_order resp;
00633   enum clnt_stat result;
00634 
00635   if (indomain == NULL || indomain[0] == '\0' ||
00636       inmap == NULL || inmap[0] == '\0')
00637     return YPERR_BADARGS;
00638 
00639   req.domain = (char *) indomain;
00640   req.map = (char *) inmap;
00641 
00642   memset (&resp, '\0', sizeof (resp));
00643 
00644   result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
00645                       (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
00646                       (caddr_t) &resp);
00647 
00648   if (result != YPERR_SUCCESS)
00649     return result;
00650 
00651   *outorder = resp.ordernum;
00652   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
00653 
00654   return result;
00655 }
00656 
00657 struct ypresp_all_data
00658 {
00659   unsigned long status;
00660   void *data;
00661   int (*foreach) (int status, char *key, int keylen,
00662                 char *val, int vallen, char *data);
00663 };
00664 
00665 static bool_t
00666 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
00667 {
00668   while (1)
00669     {
00670       struct ypresp_all resp;
00671 
00672       memset (&resp, '\0', sizeof (struct ypresp_all));
00673       if (!xdr_ypresp_all (xdrs, &resp))
00674        {
00675          xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
00676          objp->status = YP_YPERR;
00677          return FALSE;
00678        }
00679       if (resp.more == 0)
00680        {
00681          xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
00682          objp->status = YP_NOMORE;
00683          return TRUE;
00684        }
00685 
00686       switch (resp.ypresp_all_u.val.stat)
00687        {
00688        case YP_TRUE:
00689          {
00690            char key[resp.ypresp_all_u.val.key.keydat_len + 1];
00691            char val[resp.ypresp_all_u.val.val.valdat_len + 1];
00692            int keylen = resp.ypresp_all_u.val.key.keydat_len;
00693            int vallen = resp.ypresp_all_u.val.val.valdat_len;
00694 
00695            /* We are not allowed to modify the key and val data.
00696               But we are allowed to add data behind the buffer,
00697               if we don't modify the length. So add an extra NUL
00698               character to avoid trouble with broken code. */
00699            objp->status = YP_TRUE;
00700            *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
00701                               keylen)) = '\0';
00702            *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
00703                               vallen)) = '\0';
00704            xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
00705            if ((*objp->foreach) (objp->status, key, keylen,
00706                               val, vallen, objp->data))
00707              return TRUE;
00708          }
00709          break;
00710        default:
00711          objp->status = resp.ypresp_all_u.val.stat;
00712          xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
00713          /* Sun says we don't need to make this call, but must return
00714             immediately. Since Solaris makes this call, we will call
00715             the callback function, too. */
00716          (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
00717          return TRUE;
00718        }
00719     }
00720 }
00721 
00722 int
00723 yp_all (const char *indomain, const char *inmap,
00724        const struct ypall_callback *incallback)
00725 {
00726   struct ypreq_nokey req;
00727   dom_binding *ydb = NULL;
00728   int try, res;
00729   enum clnt_stat result;
00730   struct sockaddr_in clnt_sin;
00731   CLIENT *clnt;
00732   struct ypresp_all_data data;
00733   int clnt_sock;
00734   int saved_errno = errno;
00735 
00736   if (indomain == NULL || indomain[0] == '\0'
00737       || inmap == NULL || inmap[0] == '\0')
00738     return YPERR_BADARGS;
00739 
00740   try = 0;
00741   res = YPERR_YPERR;
00742 
00743   while (try < MAXTRIES && res != YPERR_SUCCESS)
00744     {
00745       if (__yp_bind (indomain, &ydb) != 0)
00746        {
00747          __set_errno (saved_errno);
00748          return YPERR_DOMAIN;
00749        }
00750 
00751       clnt_sock = RPC_ANYSOCK;
00752       clnt_sin = ydb->dom_server_addr;
00753       clnt_sin.sin_port = 0;
00754 
00755       /* We don't need the UDP connection anymore.  */
00756       __yp_unbind (ydb);
00757       ydb = NULL;
00758 
00759       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
00760       if (clnt == NULL)
00761        {
00762          __set_errno (saved_errno);
00763          return YPERR_PMAP;
00764        }
00765       req.domain = (char *) indomain;
00766       req.map = (char *) inmap;
00767 
00768       data.foreach = incallback->foreach;
00769       data.data = (void *) incallback->data;
00770 
00771       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
00772                        (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
00773                        (caddr_t) &data, RPCTIMEOUT);
00774 
00775       if (__builtin_expect (result != RPC_SUCCESS, 0))
00776        {
00777          /* Print the error message only on the last try.  */
00778          if (try == MAXTRIES - 1)
00779            clnt_perror (clnt, "yp_all: clnt_call");
00780          res = YPERR_RPC;
00781        }
00782       else
00783        res = YPERR_SUCCESS;
00784 
00785       clnt_destroy (clnt);
00786 
00787       if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
00788        {
00789          __set_errno (saved_errno);
00790          return ypprot_err (data.status);
00791        }
00792       ++try;
00793     }
00794 
00795   __set_errno (saved_errno);
00796 
00797   return res;
00798 }
00799 
00800 int
00801 
00802 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
00803 {
00804   struct ypresp_maplist resp;
00805   enum clnt_stat result;
00806 
00807   if (indomain == NULL || indomain[0] == '\0')
00808     return YPERR_BADARGS;
00809 
00810   memset (&resp, '\0', sizeof (resp));
00811 
00812   result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
00813                       (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
00814                       (caddr_t) &resp);
00815 
00816   if (__builtin_expect (result == YPERR_SUCCESS, 1))
00817     {
00818       *outmaplist = resp.maps;
00819       /* We don't free the list, this will be done by ypserv
00820         xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
00821     }
00822 
00823   return result;
00824 }
00825 
00826 const char *
00827 yperr_string (const int error)
00828 {
00829   const char *str;
00830   switch (error)
00831     {
00832     case YPERR_SUCCESS:
00833       str = N_("Success");
00834       break;
00835     case YPERR_BADARGS:
00836       str = N_("Request arguments bad");
00837       break;
00838     case YPERR_RPC:
00839       str = N_("RPC failure on NIS operation");
00840       break;
00841     case YPERR_DOMAIN:
00842       str = N_("Can't bind to server which serves this domain");
00843       break;
00844     case YPERR_MAP:
00845       str = N_("No such map in server's domain");
00846       break;
00847     case YPERR_KEY:
00848       str = N_("No such key in map");
00849       break;
00850     case YPERR_YPERR:
00851       str = N_("Internal NIS error");
00852       break;
00853     case YPERR_RESRC:
00854       str = N_("Local resource allocation failure");
00855       break;
00856     case YPERR_NOMORE:
00857       str = N_("No more records in map database");
00858       break;
00859     case YPERR_PMAP:
00860       str = N_("Can't communicate with portmapper");
00861       break;
00862     case YPERR_YPBIND:
00863       str = N_("Can't communicate with ypbind");
00864       break;
00865     case YPERR_YPSERV:
00866       str = N_("Can't communicate with ypserv");
00867       break;
00868     case YPERR_NODOM:
00869       str = N_("Local domain name not set");
00870       break;
00871     case YPERR_BADDB:
00872       str = N_("NIS map database is bad");
00873       break;
00874     case YPERR_VERS:
00875       str = N_("NIS client/server version mismatch - can't supply service");
00876       break;
00877     case YPERR_ACCESS:
00878       str = N_("Permission denied");
00879       break;
00880     case YPERR_BUSY:
00881       str = N_("Database is busy");
00882       break;
00883     default:
00884       str = N_("Unknown NIS error code");
00885       break;
00886     }
00887   return _(str);
00888 }
00889 
00890 static const int8_t yp_2_yperr[] =
00891   {
00892 #define YP2YPERR(yp, yperr)  [YP_##yp - YP_VERS] = YPERR_##yperr
00893     YP2YPERR (TRUE, SUCCESS),
00894     YP2YPERR (NOMORE, NOMORE),
00895     YP2YPERR (FALSE, YPERR),
00896     YP2YPERR (NOMAP, MAP),
00897     YP2YPERR (NODOM, DOMAIN),
00898     YP2YPERR (NOKEY, KEY),
00899     YP2YPERR (BADOP, YPERR),
00900     YP2YPERR (BADDB, BADDB),
00901     YP2YPERR (YPERR, YPERR),
00902     YP2YPERR (BADARGS, BADARGS),
00903     YP2YPERR (VERS, VERS)
00904   };
00905 int
00906 ypprot_err (const int code)
00907 {
00908   if (code < YP_VERS || code > YP_NOMORE)
00909     return YPERR_YPERR;
00910   return yp_2_yperr[code - YP_VERS];
00911 }
00912 libnsl_hidden_def (ypprot_err)
00913 
00914 const char *
00915 ypbinderr_string (const int error)
00916 {
00917   const char *str;
00918   switch (error)
00919     {
00920     case 0:
00921       str = N_("Success");
00922       break;
00923     case YPBIND_ERR_ERR:
00924       str = N_("Internal ypbind error");
00925       break;
00926     case YPBIND_ERR_NOSERV:
00927       str = N_("Domain not bound");
00928       break;
00929     case YPBIND_ERR_RESC:
00930       str = N_("System resource allocation failure");
00931       break;
00932     default:
00933       str = N_("Unknown ypbind error");
00934       break;
00935     }
00936   return _(str);
00937 }
00938 libnsl_hidden_def (ypbinderr_string)
00939 
00940 #define WINDOW 60
00941 
00942 int
00943 yp_update (char *domain, char *map, unsigned ypop,
00944           char *key, int keylen, char *data, int datalen)
00945 {
00946   union
00947     {
00948       ypupdate_args update_args;
00949       ypdelete_args delete_args;
00950     }
00951   args;
00952   xdrproc_t xdr_argument;
00953   unsigned res = 0;
00954   CLIENT *clnt;
00955   char *master;
00956   struct sockaddr saddr;
00957   char servername[MAXNETNAMELEN + 1];
00958   int r;
00959 
00960   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
00961     return YPERR_BADARGS;
00962 
00963   args.update_args.mapname = map;
00964   args.update_args.key.yp_buf_len = keylen;
00965   args.update_args.key.yp_buf_val = key;
00966   args.update_args.datum.yp_buf_len = datalen;
00967   args.update_args.datum.yp_buf_val = data;
00968 
00969   if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
00970     return r;
00971 
00972   if (!host2netname (servername, master, domain))
00973     {
00974       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
00975       free (master);
00976       return YPERR_YPERR;
00977     }
00978 
00979   clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
00980 
00981   /* We do not need the string anymore.  */
00982   free (master);
00983 
00984   if (clnt == NULL)
00985     {
00986       clnt_pcreateerror ("yp_update: clnt_create");
00987       return YPERR_RPC;
00988     }
00989 
00990   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
00991     {
00992       fputs (_("yp_update: cannot get server address\n"), stderr);
00993       return YPERR_RPC;
00994     }
00995 
00996   switch (ypop)
00997     {
00998     case YPOP_CHANGE:
00999     case YPOP_INSERT:
01000     case YPOP_STORE:
01001       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
01002       break;
01003     case YPOP_DELETE:
01004       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
01005       break;
01006     default:
01007       return YPERR_BADARGS;
01008       break;
01009     }
01010 
01011   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
01012 
01013   if (clnt->cl_auth == NULL)
01014     clnt->cl_auth = authunix_create_default ();
01015 
01016 again:
01017   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
01018                (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
01019 
01020   if (r == RPC_AUTHERROR)
01021     {
01022       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
01023        {
01024          auth_destroy (clnt->cl_auth);
01025          clnt->cl_auth = authunix_create_default ();
01026          goto again;
01027        }
01028       else
01029        return YPERR_ACCESS;
01030     }
01031   if (r != RPC_SUCCESS)
01032     {
01033       clnt_perror (clnt, "yp_update: clnt_call");
01034       return YPERR_RPC;
01035     }
01036   return res;
01037 }