Use __builtin_expect.
[kopensolaris-gnu/glibc.git] / nis / ypclnt.c
1 /* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <libintl.h>
25 #include <rpc/rpc.h>
26 #include <rpcsvc/nis.h>
27 #include <rpcsvc/yp.h>
28 #include <rpcsvc/ypclnt.h>
29 #include <rpcsvc/ypupd.h>
30 #include <sys/uio.h>
31 #include <bits/libc-lock.h>
32
33 /* This should only be defined on systems with a BSD compatible ypbind */
34 #ifndef BINDINGDIR
35 # define BINDINGDIR "/var/yp/binding"
36 #endif
37
38 struct dom_binding
39   {
40     struct dom_binding *dom_pnext;
41     char dom_domain[YPMAXDOMAIN + 1];
42     struct sockaddr_in dom_server_addr;
43     int dom_socket;
44     CLIENT *dom_client;
45   };
46 typedef struct dom_binding dom_binding;
47
48 static struct timeval RPCTIMEOUT = {25, 0};
49 static struct timeval UDPTIMEOUT = {5, 0};
50 static int const MAXTRIES = 2;
51 static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
52 __libc_lock_define_initialized (static, ypbindlist_lock)
53 static dom_binding *__ypbindlist = NULL;
54
55
56 static int
57 __yp_bind (const char *domain, dom_binding **ypdb)
58 {
59   struct sockaddr_in clnt_saddr;
60   struct ypbind_resp ypbr;
61   dom_binding *ysd = NULL;
62   int clnt_sock;
63   CLIENT *client;
64   int is_new = 0;
65
66   if (domain == NULL || domain[0] == '\0')
67     return YPERR_BADARGS;
68
69   if (ypdb != NULL)
70     {
71       ysd = *ypdb;
72       while (ysd != NULL)
73         {
74           if (strcmp (domain, ysd->dom_domain) == 0)
75             break;
76           ysd = ysd->dom_pnext;
77         }
78     }
79
80   if (ysd == NULL)
81     {
82       is_new = 1;
83       ysd = (dom_binding *) calloc (1, sizeof *ysd);
84       if (__builtin_expect (ysd == NULL, 0))
85         return YPERR_RESRC;
86     }
87
88 #if USE_BINDINGDIR
89   if (ysd->dom_client == NULL)
90     {
91       /* Try binding dir at first if we have no binding */
92       char path[sizeof (BINDINGDIR) + strlen (domain) + 10];
93       struct iovec vec[2];
94       unsigned short port;
95       int fd;
96
97       sprintf (path, "%s/%s.%d", BINDINGDIR, domain, YPBINDVERS);
98       fd = open (path, O_RDONLY);
99       if (fd >= 0)
100         {
101           /* We have a binding file and could save a RPC call */
102           vec[0].iov_base = &port;
103           vec[0].iov_len = sizeof (port);
104           vec[1].iov_base = &ypbr;
105           vec[1].iov_len = sizeof (ypbr);
106
107           if (readv (fd, vec, 2) == sizeof (port) + sizeof (ypbr))
108             {
109               ysd->dom_server_addr.sin_family = AF_INET;
110               memcpy (&ysd->dom_server_addr.sin_port,
111                       ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
112                       sizeof (ysd->dom_server_addr.sin_port));
113               memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
114                       ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
115                       sizeof (ysd->dom_server_addr.sin_addr.s_addr));
116               strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
117               ysd->dom_domain[YPMAXDOMAIN] = '\0';
118
119               ysd->dom_socket = RPC_ANYSOCK;
120               ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG,
121                                                 YPVERS, UDPTIMEOUT,
122                                                 &ysd->dom_socket);
123
124               if (ysd->dom_client != NULL)
125                 /* If the program exits, close the socket */
126                 if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
127                   perror ("fcntl: F_SETFD");
128             }
129           close (fd);
130         }
131     }
132 #endif /* USE_BINDINGDIR */
133
134   if (ysd->dom_client == NULL)
135     {
136       memset (&clnt_saddr, '\0', sizeof clnt_saddr);
137       clnt_saddr.sin_family = AF_INET;
138       clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
139       clnt_sock = RPC_ANYSOCK;
140       client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
141                                &clnt_sock, 0, 0);
142       if (client == NULL)
143         {
144           if (is_new)
145             free (ysd);
146           return YPERR_YPBIND;
147         }
148       /* Check the port number -- should be < IPPORT_RESERVED.
149          If not, it's possible someone has registered a bogus
150          ypbind with the portmapper and is trying to trick us. */
151       if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
152         {
153           clnt_destroy (client);
154           if (is_new)
155             free (ysd);
156           return YPERR_YPBIND;
157         }
158
159       if (clnt_call (client, YPBINDPROC_DOMAIN,
160                      (xdrproc_t) xdr_domainname, (caddr_t) &domain,
161                      (xdrproc_t) xdr_ypbind_resp,
162                      (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
163         {
164           clnt_destroy (client);
165           if (is_new)
166             free (ysd);
167           return YPERR_YPBIND;
168         }
169
170       clnt_destroy (client);
171
172       if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
173         {
174           fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
175                    ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
176           if (is_new)
177             free (ysd);
178           return YPERR_DOMAIN;
179         }
180       memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
181       ysd->dom_server_addr.sin_family = AF_INET;
182       memcpy (&ysd->dom_server_addr.sin_port,
183               ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
184               sizeof (ysd->dom_server_addr.sin_port));
185       memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
186               ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
187               sizeof (ysd->dom_server_addr.sin_addr.s_addr));
188       strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
189       ysd->dom_domain[YPMAXDOMAIN] = '\0';
190
191       ysd->dom_socket = RPC_ANYSOCK;
192       ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
193                                         UDPTIMEOUT, &ysd->dom_socket);
194
195       if (ysd->dom_client != NULL)
196         /* If the program exits, close the socket */
197         if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
198           perror ("fcntl: F_SETFD");
199     }
200
201   if (ysd->dom_client == NULL)
202     {
203       if (is_new)
204         free (ysd);
205       return YPERR_YPSERV;
206     }
207
208   if (is_new && ypdb != NULL)
209     {
210       ysd->dom_pnext = *ypdb;
211       *ypdb = ysd;
212     }
213
214   return YPERR_SUCCESS;
215 }
216
217 static void
218 __yp_unbind (dom_binding *ydb)
219 {
220   clnt_destroy (ydb->dom_client);
221   ydb->dom_client = NULL;
222 }
223
224 int
225 yp_bind (const char *indomain)
226 {
227   int status;
228
229   __libc_lock_lock (ypbindlist_lock);
230
231   status = __yp_bind (indomain, &__ypbindlist);
232
233   __libc_lock_unlock (ypbindlist_lock);
234
235   return status;
236 }
237
238 static void
239 yp_unbind_locked (const char *indomain)
240 {
241   dom_binding *ydbptr, *ydbptr2;
242
243   ydbptr2 = NULL;
244   ydbptr = __ypbindlist;
245
246   while (ydbptr != NULL)
247     {
248       if (strcmp (ydbptr->dom_domain, indomain) == 0)
249         {
250           dom_binding *work;
251
252           work = ydbptr;
253           if (ydbptr2 == NULL)
254             __ypbindlist = __ypbindlist->dom_pnext;
255           else
256             ydbptr2 = ydbptr->dom_pnext;
257           __yp_unbind (work);
258           free (work);
259           break;
260         }
261       ydbptr2 = ydbptr;
262       ydbptr = ydbptr->dom_pnext;
263     }
264 }
265
266 void
267 yp_unbind (const char *indomain)
268 {
269   __libc_lock_lock (ypbindlist_lock);
270
271   yp_unbind_locked (indomain);
272
273   __libc_lock_unlock (ypbindlist_lock);
274
275   return;
276 }
277
278 static int
279 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
280            caddr_t req, xdrproc_t xres, caddr_t resp)
281 {
282   dom_binding *ydb = NULL;
283   bool_t use_ypbindlist = FALSE;
284   int try, status;
285   enum clnt_stat result;
286   int saved_errno = errno;
287
288   try = 0;
289   status = YPERR_YPERR;
290
291   __libc_lock_lock (ypbindlist_lock);
292   if (__ypbindlist != NULL)
293     {
294       ydb = __ypbindlist;
295       while (ydb != NULL)
296         {
297           if (strcmp (domain, ydb->dom_domain) == 0)
298             break;
299           ydb = ydb->dom_pnext;
300         }
301       if (ydb != NULL)
302         use_ypbindlist = TRUE;
303       else
304         __libc_lock_unlock (ypbindlist_lock);
305     }
306   else
307     __libc_lock_unlock (ypbindlist_lock);
308
309   while (try < MAXTRIES && status != YPERR_SUCCESS)
310     {
311       if (__yp_bind (domain, &ydb) != 0)
312         {
313           if (use_ypbindlist)
314             __libc_lock_unlock (ypbindlist_lock);
315           __set_errno (saved_errno);
316           return YPERR_DOMAIN;
317         }
318
319       result = clnt_call (ydb->dom_client, prog,
320                           xargs, req, xres, resp, RPCTIMEOUT);
321
322       if (result != RPC_SUCCESS)
323         {
324           /* Don't print the error message on the first try. It
325              could be that we use cached data which is now invalid. */
326           if (try != 0)
327             clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
328
329           if (use_ypbindlist)
330             {
331               /* We use ypbindlist, and the old cached data is
332                  invalid. unbind now and create a new binding */
333               yp_unbind_locked (domain);
334               __libc_lock_unlock (ypbindlist_lock);
335               use_ypbindlist = FALSE;
336             }
337           else
338             {
339               __yp_unbind (ydb);
340               free (ydb);
341             }
342
343           ydb = NULL;
344           status = YPERR_RPC;
345         }
346       else
347         status = YPERR_SUCCESS;
348
349       try++;
350     }
351   if (use_ypbindlist)
352     {
353       __libc_lock_unlock (ypbindlist_lock);
354       use_ypbindlist = FALSE;
355     }
356   else
357     if (ydb != NULL)
358       {
359         __yp_unbind (ydb);
360         free (ydb);
361         ydb = NULL;
362       }
363
364   __set_errno (saved_errno);
365
366   return status;
367 }
368
369
370 __libc_lock_define_initialized (static, domainname_lock)
371
372 int
373 yp_get_default_domain (char **outdomain)
374 {
375   int result = YPERR_SUCCESS;;
376   *outdomain = NULL;
377
378   __libc_lock_lock (domainname_lock);
379
380   if (__ypdomainname[0] == '\0')
381     {
382       if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
383         result = YPERR_NODOM;
384       else if (strcmp (__ypdomainname, "(none)") == 0)
385         {
386           /* If domainname is not set, some systems will return "(none)" */
387           __ypdomainname[0] = '\0';
388           result = YPERR_NODOM;
389         }
390       else
391         *outdomain = __ypdomainname;
392     }
393   else
394     *outdomain = __ypdomainname;
395
396   __libc_lock_unlock (domainname_lock);
397
398   return result;
399 }
400
401 int
402 __yp_check (char **domain)
403 {
404   char *unused;
405
406   if (__ypdomainname[0] == '\0')
407     if (yp_get_default_domain (&unused))
408       return 0;
409
410   if (domain)
411     *domain = __ypdomainname;
412
413   if (yp_bind (__ypdomainname) == 0)
414     return 1;
415   return 0;
416 }
417
418 int
419 yp_match (const char *indomain, const char *inmap, const char *inkey,
420           const int inkeylen, char **outval, int *outvallen)
421 {
422   ypreq_key req;
423   ypresp_val resp;
424   enum clnt_stat result;
425
426   if (indomain == NULL || indomain[0] == '\0' ||
427       inmap == NULL || inmap[0] == '\0' ||
428       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
429     return YPERR_BADARGS;
430
431   req.domain = (char *) indomain;
432   req.map = (char *) inmap;
433   req.key.keydat_val = (char *) inkey;
434   req.key.keydat_len = inkeylen;
435
436   *outval = NULL;
437   *outvallen = 0;
438   memset (&resp, '\0', sizeof (resp));
439
440   result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
441                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
442                       (caddr_t) & resp);
443
444   if (result != YPERR_SUCCESS)
445     return result;
446   if (resp.stat != YP_TRUE)
447     return ypprot_err (resp.stat);
448
449   *outvallen = resp.val.valdat_len;
450   *outval = malloc (*outvallen + 1);
451   if (__builtin_expect (*outval == NULL, 0))
452     return YPERR_RESRC;
453   memcpy (*outval, resp.val.valdat_val, *outvallen);
454   (*outval)[*outvallen] = '\0';
455
456   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
457
458   return YPERR_SUCCESS;
459 }
460
461 int
462 yp_first (const char *indomain, const char *inmap, char **outkey,
463           int *outkeylen, char **outval, int *outvallen)
464 {
465   ypreq_nokey req;
466   ypresp_key_val resp;
467   enum clnt_stat result;
468
469   if (indomain == NULL || indomain[0] == '\0' ||
470       inmap == NULL || inmap[0] == '\0')
471     return YPERR_BADARGS;
472
473   req.domain = (char *) indomain;
474   req.map = (char *) inmap;
475
476   *outkey = *outval = NULL;
477   *outkeylen = *outvallen = 0;
478   memset (&resp, '\0', sizeof (resp));
479
480   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
481                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
482                       (caddr_t) & resp);
483
484   if (result != RPC_SUCCESS)
485     return YPERR_RPC;
486   if (resp.stat != YP_TRUE)
487     return ypprot_err (resp.stat);
488
489   *outkeylen = resp.key.keydat_len;
490   *outkey = malloc (*outkeylen + 1);
491   if (__builtin_expect (*outkey == NULL, 0))
492     return YPERR_RESRC;
493   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
494   (*outkey)[*outkeylen] = '\0';
495   *outvallen = resp.val.valdat_len;
496   *outval = malloc (*outvallen + 1);
497   if (__builtin_expect (*outval == NULL, 0))
498     return YPERR_RESRC;
499   memcpy (*outval, resp.val.valdat_val, *outvallen);
500   (*outval)[*outvallen] = '\0';
501
502   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
503
504   return YPERR_SUCCESS;
505 }
506
507 int
508 yp_next (const char *indomain, const char *inmap, const char *inkey,
509          const int inkeylen, char **outkey, int *outkeylen, char **outval,
510          int *outvallen)
511 {
512   ypreq_key req;
513   ypresp_key_val resp;
514   enum clnt_stat result;
515
516   if (indomain == NULL || indomain[0] == '\0' ||
517       inmap == NULL || inmap[0] == '\0' ||
518       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
519     return YPERR_BADARGS;
520
521   req.domain = (char *) indomain;
522   req.map = (char *) inmap;
523   req.key.keydat_val = (char *) inkey;
524   req.key.keydat_len = inkeylen;
525
526   *outkey = *outval = NULL;
527   *outkeylen = *outvallen = 0;
528   memset (&resp, '\0', sizeof (resp));
529
530   result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
531                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
532                       (caddr_t) & resp);
533
534   if (result != YPERR_SUCCESS)
535     return result;
536   if (resp.stat != YP_TRUE)
537     return ypprot_err (resp.stat);
538
539   *outkeylen = resp.key.keydat_len;
540   *outkey = malloc (*outkeylen + 1);
541   if (__builtin_expect (*outkey == NULL, 0))
542     return YPERR_RESRC;
543   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
544   (*outkey)[*outkeylen] = '\0';
545   *outvallen = resp.val.valdat_len;
546   *outval = malloc (*outvallen + 1);
547   if (__builtin_expect (*outval == NULL, 0))
548     return YPERR_RESRC;
549   memcpy (*outval, resp.val.valdat_val, *outvallen);
550   (*outval)[*outvallen] = '\0';
551
552   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
553
554   return YPERR_SUCCESS;
555 }
556
557 int
558 yp_master (const char *indomain, const char *inmap, char **outname)
559 {
560   ypreq_nokey req;
561   ypresp_master resp;
562   enum clnt_stat result;
563
564   if (indomain == NULL || indomain[0] == '\0' ||
565       inmap == NULL || inmap[0] == '\0')
566     return YPERR_BADARGS;
567
568   req.domain = (char *) indomain;
569   req.map = (char *) inmap;
570
571   memset (&resp, '\0', sizeof (ypresp_master));
572
573   result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
574           (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
575
576   if (result != YPERR_SUCCESS)
577     return result;
578   if (resp.stat != YP_TRUE)
579     return ypprot_err (resp.stat);
580
581   *outname = strdup (resp.peer);
582   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
583
584   return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
585 }
586
587 int
588 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
589 {
590   struct ypreq_nokey req;
591   struct ypresp_order resp;
592   enum clnt_stat result;
593
594   if (indomain == NULL || indomain[0] == '\0' ||
595       inmap == NULL || inmap == '\0')
596     return YPERR_BADARGS;
597
598   req.domain = (char *) indomain;
599   req.map = (char *) inmap;
600
601   memset (&resp, '\0', sizeof (resp));
602
603   result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
604            (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
605
606   if (result != YPERR_SUCCESS)
607     return result;
608   if (resp.stat != YP_TRUE)
609     return ypprot_err (resp.stat);
610
611   *outorder = resp.ordernum;
612   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
613
614   return YPERR_SUCCESS;
615 }
616
617 static void *ypall_data;
618 static int (*ypall_foreach) (int status, char *key, int keylen,
619                              char *val, int vallen, char *data);
620
621 static bool_t
622 __xdr_ypresp_all (XDR *xdrs, u_long *objp)
623 {
624   while (1)
625     {
626       struct ypresp_all resp;
627
628       memset (&resp, '\0', sizeof (struct ypresp_all));
629       if (!xdr_ypresp_all (xdrs, &resp))
630         {
631           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
632           *objp = YP_YPERR;
633           return FALSE;
634         }
635       if (resp.more == 0)
636         {
637           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
638           *objp = YP_NOMORE;
639           return TRUE;
640         }
641
642       switch (resp.ypresp_all_u.val.stat)
643         {
644         case YP_TRUE:
645           {
646             char key[resp.ypresp_all_u.val.key.keydat_len + 1];
647             char val[resp.ypresp_all_u.val.val.valdat_len + 1];
648             int keylen = resp.ypresp_all_u.val.key.keydat_len;
649             int vallen = resp.ypresp_all_u.val.val.valdat_len;
650
651             /* We are not allowed to modify the key and val data.
652                But we are allowed to add data behind the buffer,
653                if we don't modify the length. So add an extra NUL
654                character to avoid trouble with broken code. */
655             *objp = YP_TRUE;
656             memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
657             key[keylen] = '\0';
658             memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
659             val[vallen] = '\0';
660             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
661             if ((*ypall_foreach) (*objp, key, keylen,
662                                   val, vallen, ypall_data))
663               return TRUE;
664           }
665           break;
666         default:
667           *objp = resp.ypresp_all_u.val.stat;
668           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
669           /* Sun says we don't need to make this call, but must return
670              immediatly. Since Solaris makes this call, we will call
671              the callback function, too. */
672           (*ypall_foreach) (*objp, NULL, 0, NULL, 0, ypall_data);
673           return TRUE;
674         }
675     }
676 }
677
678 int
679 yp_all (const char *indomain, const char *inmap,
680         const struct ypall_callback *incallback)
681 {
682   struct ypreq_nokey req;
683   dom_binding *ydb = NULL;
684   int try, res;
685   enum clnt_stat result;
686   struct sockaddr_in clnt_sin;
687   CLIENT *clnt;
688   unsigned long status;
689   int clnt_sock;
690   int saved_errno = errno;
691
692   if (indomain == NULL || indomain[0] == '\0' ||
693       inmap == NULL || inmap == '\0')
694     return YPERR_BADARGS;
695
696   try = 0;
697   res = YPERR_YPERR;
698
699   while (try < MAXTRIES && res != YPERR_SUCCESS)
700     {
701       if (__yp_bind (indomain, &ydb) != 0)
702         {
703           __set_errno (saved_errno);
704           return YPERR_DOMAIN;
705         }
706
707       /* YPPROC_ALL get its own TCP channel to ypserv.  Therefore we
708          close the socket opened by the __yp_bind call.  */
709       close (ydb->dom_socket);
710       clnt_sock = RPC_ANYSOCK;
711       clnt_sin = ydb->dom_server_addr;
712       clnt_sin.sin_port = 0;
713       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
714       if (clnt == NULL)
715         {
716           __yp_unbind (ydb);
717           __set_errno (saved_errno);
718           return YPERR_PMAP;
719         }
720       req.domain = (char *) indomain;
721       req.map = (char *) inmap;
722
723       ypall_foreach = incallback->foreach;
724       ypall_data = (void *) incallback->data;
725
726       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
727                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
728                           (caddr_t) &status, RPCTIMEOUT);
729
730       if (result != RPC_SUCCESS)
731         {
732           clnt_perror (clnt, "yp_all: clnt_call");
733           res = YPERR_RPC;
734         }
735       else
736         res = YPERR_SUCCESS;
737
738       __yp_unbind (ydb);
739       clnt_destroy (clnt);
740
741       if (status != YP_NOMORE)
742         {
743           __set_errno (saved_errno);
744           return ypprot_err (status);
745         }
746       ++try;
747     }
748
749   __set_errno (saved_errno);
750
751   return res;
752 }
753
754 int
755 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
756 {
757   struct ypresp_maplist resp;
758   enum clnt_stat result;
759
760   if (indomain == NULL || indomain[0] == '\0')
761     return YPERR_BADARGS;
762
763   memset (&resp, '\0', sizeof (resp));
764
765   result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
766     (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
767
768   if (result != YPERR_SUCCESS)
769     return result;
770   if (resp.stat != YP_TRUE)
771     return ypprot_err (resp.stat);
772
773   *outmaplist = resp.maps;
774   /* We give the list not free, this will be done by ypserv
775      xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
776
777   return YPERR_SUCCESS;
778 }
779
780 const char *
781 yperr_string (const int error)
782 {
783   switch (error)
784     {
785     case YPERR_SUCCESS:
786       return _("Success");
787     case YPERR_BADARGS:
788       return _("Request arguments bad");
789     case YPERR_RPC:
790       return _("RPC failure on NIS operation");
791     case YPERR_DOMAIN:
792       return _("Can't bind to server which serves this domain");
793     case YPERR_MAP:
794       return _("No such map in server's domain");
795     case YPERR_KEY:
796       return _("No such key in map");
797     case YPERR_YPERR:
798       return _("Internal NIS error");
799     case YPERR_RESRC:
800       return _("Local resource allocation failure");
801     case YPERR_NOMORE:
802       return _("No more records in map database");
803     case YPERR_PMAP:
804       return _("Can't communicate with portmapper");
805     case YPERR_YPBIND:
806       return _("Can't communicate with ypbind");
807     case YPERR_YPSERV:
808       return _("Can't communicate with ypserv");
809     case YPERR_NODOM:
810       return _("Local domain name not set");
811     case YPERR_BADDB:
812       return _("NIS map database is bad");
813     case YPERR_VERS:
814       return _("NIS client/server version mismatch - can't supply service");
815     case YPERR_ACCESS:
816       return _("Permission denied");
817     case YPERR_BUSY:
818       return _("Database is busy");
819     }
820   return _("Unknown NIS error code");
821 }
822
823 int
824 ypprot_err (const int code)
825 {
826   switch (code)
827     {
828     case YP_TRUE:
829       return YPERR_SUCCESS;
830     case YP_NOMORE:
831       return YPERR_NOMORE;
832     case YP_FALSE:
833       return YPERR_YPERR;
834     case YP_NOMAP:
835       return YPERR_MAP;
836     case YP_NODOM:
837       return YPERR_DOMAIN;
838     case YP_NOKEY:
839       return YPERR_KEY;
840     case YP_BADOP:
841       return YPERR_YPERR;
842     case YP_BADDB:
843       return YPERR_BADDB;
844     case YP_YPERR:
845       return YPERR_YPERR;
846     case YP_BADARGS:
847       return YPERR_BADARGS;
848     case YP_VERS:
849       return YPERR_VERS;
850     }
851   return YPERR_YPERR;
852 }
853
854 const char *
855 ypbinderr_string (const int error)
856 {
857   switch (error)
858     {
859     case 0:
860       return _("Success");
861     case YPBIND_ERR_ERR:
862       return _("Internal ypbind error");
863     case YPBIND_ERR_NOSERV:
864       return _("Domain not bound");
865     case YPBIND_ERR_RESC:
866       return _("System resource allocation failure");
867     default:
868       return _("Unknown ypbind error");
869     }
870 }
871
872
873 #define WINDOW 60
874
875 int
876 yp_update (char *domain, char *map, unsigned ypop,
877            char *key, int keylen, char *data, int datalen)
878 {
879   union
880     {
881       ypupdate_args update_args;
882       ypdelete_args delete_args;
883     }
884   args;
885   xdrproc_t xdr_argument;
886   unsigned res = 0;
887   CLIENT *clnt;
888   char *master;
889   struct sockaddr saddr;
890   char servername[MAXNETNAMELEN + 1];
891   int r;
892
893   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
894     return YPERR_BADARGS;
895
896   args.update_args.mapname = map;
897   args.update_args.key.yp_buf_len = keylen;
898   args.update_args.key.yp_buf_val = key;
899   args.update_args.datum.yp_buf_len = datalen;
900   args.update_args.datum.yp_buf_val = data;
901
902   if ((r = yp_master (domain, map, &master)) != 0)
903     return r;
904
905   if (!host2netname (servername, master, domain))
906     {
907       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
908       return YPERR_YPERR;
909     }
910
911   if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
912     {
913       clnt_pcreateerror ("yp_update: clnt_create");
914       return YPERR_RPC;
915     }
916
917   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
918     {
919       fputs (_("yp_update: cannot get server address\n"), stderr);
920       return YPERR_RPC;
921     }
922
923   switch (ypop)
924     {
925     case YPOP_CHANGE:
926     case YPOP_INSERT:
927     case YPOP_STORE:
928       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
929       break;
930     case YPOP_DELETE:
931       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
932       break;
933     default:
934       return YPERR_BADARGS;
935       break;
936     }
937
938   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
939
940   if (clnt->cl_auth == NULL)
941     clnt->cl_auth = authunix_create_default ();
942
943 again:
944   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
945                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
946
947   if (r == RPC_AUTHERROR)
948     {
949       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
950         {
951           clnt->cl_auth = authunix_create_default ();
952           goto again;
953         }
954       else
955         return YPERR_ACCESS;
956     }
957   if (r != RPC_SUCCESS)
958     {
959       clnt_perror (clnt, "yp_update: clnt_call");
960       return YPERR_RPC;
961     }
962   return res;
963 }