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