(yp_all): Remove the hack introduced on 1998-09-29. Correctly close
[kopensolaris-gnu/glibc.git] / nis / ypclnt.c
1 /* Copyright (C) 1996-2001, 2002 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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    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       clnt_sock = RPC_ANYSOCK;
708       clnt_sin = ydb->dom_server_addr;
709       clnt_sin.sin_port = 0;
710
711       /* We don't need the UDP connection anymore.  */
712       __yp_unbind (ydb);
713
714       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
715       if (clnt == NULL)
716         {
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           /* Print the error message only on the last try */
733           if (try == MAXTRIES - 1)
734             clnt_perror (clnt, "yp_all: clnt_call");
735           res = YPERR_RPC;
736         }
737       else
738         res = YPERR_SUCCESS;
739
740       clnt_destroy (clnt);
741
742       if (res == YPERR_SUCCESS && status != YP_NOMORE)
743         {
744           __set_errno (saved_errno);
745           return ypprot_err (status);
746         }
747       ++try;
748     }
749
750   __set_errno (saved_errno);
751
752   return res;
753 }
754
755 int
756 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
757 {
758   struct ypresp_maplist resp;
759   enum clnt_stat result;
760
761   if (indomain == NULL || indomain[0] == '\0')
762     return YPERR_BADARGS;
763
764   memset (&resp, '\0', sizeof (resp));
765
766   result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
767     (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
768
769   if (result != YPERR_SUCCESS)
770     return result;
771   if (resp.stat != YP_TRUE)
772     return ypprot_err (resp.stat);
773
774   *outmaplist = resp.maps;
775   /* We give the list not free, this will be done by ypserv
776      xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
777
778   return YPERR_SUCCESS;
779 }
780
781 const char *
782 yperr_string (const int error)
783 {
784   switch (error)
785     {
786     case YPERR_SUCCESS:
787       return _("Success");
788     case YPERR_BADARGS:
789       return _("Request arguments bad");
790     case YPERR_RPC:
791       return _("RPC failure on NIS operation");
792     case YPERR_DOMAIN:
793       return _("Can't bind to server which serves this domain");
794     case YPERR_MAP:
795       return _("No such map in server's domain");
796     case YPERR_KEY:
797       return _("No such key in map");
798     case YPERR_YPERR:
799       return _("Internal NIS error");
800     case YPERR_RESRC:
801       return _("Local resource allocation failure");
802     case YPERR_NOMORE:
803       return _("No more records in map database");
804     case YPERR_PMAP:
805       return _("Can't communicate with portmapper");
806     case YPERR_YPBIND:
807       return _("Can't communicate with ypbind");
808     case YPERR_YPSERV:
809       return _("Can't communicate with ypserv");
810     case YPERR_NODOM:
811       return _("Local domain name not set");
812     case YPERR_BADDB:
813       return _("NIS map database is bad");
814     case YPERR_VERS:
815       return _("NIS client/server version mismatch - can't supply service");
816     case YPERR_ACCESS:
817       return _("Permission denied");
818     case YPERR_BUSY:
819       return _("Database is busy");
820     }
821   return _("Unknown NIS error code");
822 }
823
824 int
825 ypprot_err (const int code)
826 {
827   switch (code)
828     {
829     case YP_TRUE:
830       return YPERR_SUCCESS;
831     case YP_NOMORE:
832       return YPERR_NOMORE;
833     case YP_FALSE:
834       return YPERR_YPERR;
835     case YP_NOMAP:
836       return YPERR_MAP;
837     case YP_NODOM:
838       return YPERR_DOMAIN;
839     case YP_NOKEY:
840       return YPERR_KEY;
841     case YP_BADOP:
842       return YPERR_YPERR;
843     case YP_BADDB:
844       return YPERR_BADDB;
845     case YP_YPERR:
846       return YPERR_YPERR;
847     case YP_BADARGS:
848       return YPERR_BADARGS;
849     case YP_VERS:
850       return YPERR_VERS;
851     }
852   return YPERR_YPERR;
853 }
854
855 const char *
856 ypbinderr_string (const int error)
857 {
858   switch (error)
859     {
860     case 0:
861       return _("Success");
862     case YPBIND_ERR_ERR:
863       return _("Internal ypbind error");
864     case YPBIND_ERR_NOSERV:
865       return _("Domain not bound");
866     case YPBIND_ERR_RESC:
867       return _("System resource allocation failure");
868     default:
869       return _("Unknown ypbind error");
870     }
871 }
872
873
874 #define WINDOW 60
875
876 int
877 yp_update (char *domain, char *map, unsigned ypop,
878            char *key, int keylen, char *data, int datalen)
879 {
880   union
881     {
882       ypupdate_args update_args;
883       ypdelete_args delete_args;
884     }
885   args;
886   xdrproc_t xdr_argument;
887   unsigned res = 0;
888   CLIENT *clnt;
889   char *master;
890   struct sockaddr saddr;
891   char servername[MAXNETNAMELEN + 1];
892   int r;
893
894   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
895     return YPERR_BADARGS;
896
897   args.update_args.mapname = map;
898   args.update_args.key.yp_buf_len = keylen;
899   args.update_args.key.yp_buf_val = key;
900   args.update_args.datum.yp_buf_len = datalen;
901   args.update_args.datum.yp_buf_val = data;
902
903   if ((r = yp_master (domain, map, &master)) != 0)
904     return r;
905
906   if (!host2netname (servername, master, domain))
907     {
908       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
909       return YPERR_YPERR;
910     }
911
912   if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
913     {
914       clnt_pcreateerror ("yp_update: clnt_create");
915       return YPERR_RPC;
916     }
917
918   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
919     {
920       fputs (_("yp_update: cannot get server address\n"), stderr);
921       return YPERR_RPC;
922     }
923
924   switch (ypop)
925     {
926     case YPOP_CHANGE:
927     case YPOP_INSERT:
928     case YPOP_STORE:
929       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
930       break;
931     case YPOP_DELETE:
932       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
933       break;
934     default:
935       return YPERR_BADARGS;
936       break;
937     }
938
939   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
940
941   if (clnt->cl_auth == NULL)
942     clnt->cl_auth = authunix_create_default ();
943
944 again:
945   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
946                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
947
948   if (r == RPC_AUTHERROR)
949     {
950       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
951         {
952           clnt->cl_auth = authunix_create_default ();
953           goto again;
954         }
955       else
956         return YPERR_ACCESS;
957     }
958   if (r != RPC_SUCCESS)
959     {
960       clnt_perror (clnt, "yp_update: clnt_call");
961       return YPERR_RPC;
962     }
963   return res;
964 }