(yp_all): Free the dom_binding object after unwinding it.
[kopensolaris-gnu/glibc.git] / nis / ypclnt.c
1 /* Copyright (C) 1996-2001, 2002, 2003 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)
209     {
210       if (ypdb != NULL)
211         {
212           ysd->dom_pnext = *ypdb;
213           *ypdb = ysd;
214         }
215       else
216         free (ysd);
217     }
218
219   return YPERR_SUCCESS;
220 }
221
222 static void
223 __yp_unbind (dom_binding *ydb)
224 {
225   clnt_destroy (ydb->dom_client);
226   ydb->dom_client = NULL;
227 }
228
229 int
230 yp_bind (const char *indomain)
231 {
232   int status;
233
234   __libc_lock_lock (ypbindlist_lock);
235
236   status = __yp_bind (indomain, &__ypbindlist);
237
238   __libc_lock_unlock (ypbindlist_lock);
239
240   return status;
241 }
242
243 static void
244 yp_unbind_locked (const char *indomain)
245 {
246   dom_binding *ydbptr, *ydbptr2;
247
248   ydbptr2 = NULL;
249   ydbptr = __ypbindlist;
250
251   while (ydbptr != NULL)
252     {
253       if (strcmp (ydbptr->dom_domain, indomain) == 0)
254         {
255           dom_binding *work;
256
257           work = ydbptr;
258           if (ydbptr2 == NULL)
259             __ypbindlist = __ypbindlist->dom_pnext;
260           else
261             ydbptr2 = ydbptr->dom_pnext;
262           __yp_unbind (work);
263           free (work);
264           break;
265         }
266       ydbptr2 = ydbptr;
267       ydbptr = ydbptr->dom_pnext;
268     }
269 }
270
271 void
272 yp_unbind (const char *indomain)
273 {
274   __libc_lock_lock (ypbindlist_lock);
275
276   yp_unbind_locked (indomain);
277
278   __libc_lock_unlock (ypbindlist_lock);
279
280   return;
281 }
282
283 static int
284 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
285            caddr_t req, xdrproc_t xres, caddr_t resp)
286 {
287   dom_binding *ydb = NULL;
288   bool_t use_ypbindlist = FALSE;
289   int try, status;
290   enum clnt_stat result;
291   int saved_errno = errno;
292
293   try = 0;
294   status = YPERR_YPERR;
295
296   __libc_lock_lock (ypbindlist_lock);
297   if (__ypbindlist != NULL)
298     {
299       ydb = __ypbindlist;
300       while (ydb != NULL)
301         {
302           if (strcmp (domain, ydb->dom_domain) == 0)
303             break;
304           ydb = ydb->dom_pnext;
305         }
306       if (ydb != NULL)
307         use_ypbindlist = TRUE;
308       else
309         __libc_lock_unlock (ypbindlist_lock);
310     }
311   else
312     __libc_lock_unlock (ypbindlist_lock);
313
314   while (try < MAXTRIES && status != YPERR_SUCCESS)
315     {
316       if (__yp_bind (domain, &ydb) != 0)
317         {
318           if (use_ypbindlist)
319             __libc_lock_unlock (ypbindlist_lock);
320           __set_errno (saved_errno);
321           return YPERR_DOMAIN;
322         }
323
324       result = clnt_call (ydb->dom_client, prog,
325                           xargs, req, xres, resp, RPCTIMEOUT);
326
327       if (result != RPC_SUCCESS)
328         {
329           /* Don't print the error message on the first try. It
330              could be that we use cached data which is now invalid. */
331           if (try != 0)
332             clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
333
334           if (use_ypbindlist)
335             {
336               /* We use ypbindlist, and the old cached data is
337                  invalid. unbind now and create a new binding */
338               yp_unbind_locked (domain);
339               __libc_lock_unlock (ypbindlist_lock);
340               use_ypbindlist = FALSE;
341             }
342           else
343             {
344               __yp_unbind (ydb);
345               free (ydb);
346             }
347
348           ydb = NULL;
349           status = YPERR_RPC;
350         }
351       else
352         status = YPERR_SUCCESS;
353
354       try++;
355     }
356   if (use_ypbindlist)
357     {
358       __libc_lock_unlock (ypbindlist_lock);
359       use_ypbindlist = FALSE;
360     }
361   else
362     if (ydb != NULL)
363       {
364         __yp_unbind (ydb);
365         free (ydb);
366         ydb = NULL;
367       }
368
369   __set_errno (saved_errno);
370
371   return status;
372 }
373
374
375 __libc_lock_define_initialized (static, domainname_lock)
376
377 int
378 yp_get_default_domain (char **outdomain)
379 {
380   int result = YPERR_SUCCESS;;
381   *outdomain = NULL;
382
383   __libc_lock_lock (domainname_lock);
384
385   if (__ypdomainname[0] == '\0')
386     {
387       if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
388         result = YPERR_NODOM;
389       else if (strcmp (__ypdomainname, "(none)") == 0)
390         {
391           /* If domainname is not set, some systems will return "(none)" */
392           __ypdomainname[0] = '\0';
393           result = YPERR_NODOM;
394         }
395       else
396         *outdomain = __ypdomainname;
397     }
398   else
399     *outdomain = __ypdomainname;
400
401   __libc_lock_unlock (domainname_lock);
402
403   return result;
404 }
405
406 int
407 __yp_check (char **domain)
408 {
409   char *unused;
410
411   if (__ypdomainname[0] == '\0')
412     if (yp_get_default_domain (&unused))
413       return 0;
414
415   if (domain)
416     *domain = __ypdomainname;
417
418   if (yp_bind (__ypdomainname) == 0)
419     return 1;
420   return 0;
421 }
422
423 int
424 yp_match (const char *indomain, const char *inmap, const char *inkey,
425           const int inkeylen, char **outval, int *outvallen)
426 {
427   ypreq_key req;
428   ypresp_val resp;
429   enum clnt_stat result;
430
431   if (indomain == NULL || indomain[0] == '\0' ||
432       inmap == NULL || inmap[0] == '\0' ||
433       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
434     return YPERR_BADARGS;
435
436   req.domain = (char *) indomain;
437   req.map = (char *) inmap;
438   req.key.keydat_val = (char *) inkey;
439   req.key.keydat_len = inkeylen;
440
441   *outval = NULL;
442   *outvallen = 0;
443   memset (&resp, '\0', sizeof (resp));
444
445   result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
446                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
447                       (caddr_t) & resp);
448
449   if (result != YPERR_SUCCESS)
450     return result;
451   if (resp.stat != YP_TRUE)
452     return ypprot_err (resp.stat);
453
454   *outvallen = resp.val.valdat_len;
455   *outval = malloc (*outvallen + 1);
456   if (__builtin_expect (*outval == NULL, 0))
457     return YPERR_RESRC;
458   memcpy (*outval, resp.val.valdat_val, *outvallen);
459   (*outval)[*outvallen] = '\0';
460
461   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
462
463   return YPERR_SUCCESS;
464 }
465
466 int
467 yp_first (const char *indomain, const char *inmap, char **outkey,
468           int *outkeylen, char **outval, int *outvallen)
469 {
470   ypreq_nokey req;
471   ypresp_key_val resp;
472   enum clnt_stat result;
473
474   if (indomain == NULL || indomain[0] == '\0' ||
475       inmap == NULL || inmap[0] == '\0')
476     return YPERR_BADARGS;
477
478   req.domain = (char *) indomain;
479   req.map = (char *) inmap;
480
481   *outkey = *outval = NULL;
482   *outkeylen = *outvallen = 0;
483   memset (&resp, '\0', sizeof (resp));
484
485   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
486                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
487                       (caddr_t) & resp);
488
489   if (result != RPC_SUCCESS)
490     return YPERR_RPC;
491   if (resp.stat != YP_TRUE)
492     return ypprot_err (resp.stat);
493
494   *outkeylen = resp.key.keydat_len;
495   *outkey = malloc (*outkeylen + 1);
496   if (__builtin_expect (*outkey == NULL, 0))
497     return YPERR_RESRC;
498   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
499   (*outkey)[*outkeylen] = '\0';
500   *outvallen = resp.val.valdat_len;
501   *outval = malloc (*outvallen + 1);
502   if (__builtin_expect (*outval == NULL, 0))
503     return YPERR_RESRC;
504   memcpy (*outval, resp.val.valdat_val, *outvallen);
505   (*outval)[*outvallen] = '\0';
506
507   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
508
509   return YPERR_SUCCESS;
510 }
511
512 int
513 yp_next (const char *indomain, const char *inmap, const char *inkey,
514          const int inkeylen, char **outkey, int *outkeylen, char **outval,
515          int *outvallen)
516 {
517   ypreq_key req;
518   ypresp_key_val resp;
519   enum clnt_stat result;
520
521   if (indomain == NULL || indomain[0] == '\0' ||
522       inmap == NULL || inmap[0] == '\0' ||
523       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
524     return YPERR_BADARGS;
525
526   req.domain = (char *) indomain;
527   req.map = (char *) inmap;
528   req.key.keydat_val = (char *) inkey;
529   req.key.keydat_len = inkeylen;
530
531   *outkey = *outval = NULL;
532   *outkeylen = *outvallen = 0;
533   memset (&resp, '\0', sizeof (resp));
534
535   result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
536                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
537                       (caddr_t) & resp);
538
539   if (result != YPERR_SUCCESS)
540     return result;
541   if (resp.stat != YP_TRUE)
542     return ypprot_err (resp.stat);
543
544   *outkeylen = resp.key.keydat_len;
545   *outkey = malloc (*outkeylen + 1);
546   if (__builtin_expect (*outkey == NULL, 0))
547     return YPERR_RESRC;
548   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
549   (*outkey)[*outkeylen] = '\0';
550   *outvallen = resp.val.valdat_len;
551   *outval = malloc (*outvallen + 1);
552   if (__builtin_expect (*outval == NULL, 0))
553     return YPERR_RESRC;
554   memcpy (*outval, resp.val.valdat_val, *outvallen);
555   (*outval)[*outvallen] = '\0';
556
557   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
558
559   return YPERR_SUCCESS;
560 }
561
562 int
563 yp_master (const char *indomain, const char *inmap, char **outname)
564 {
565   ypreq_nokey req;
566   ypresp_master resp;
567   enum clnt_stat result;
568
569   if (indomain == NULL || indomain[0] == '\0' ||
570       inmap == NULL || inmap[0] == '\0')
571     return YPERR_BADARGS;
572
573   req.domain = (char *) indomain;
574   req.map = (char *) inmap;
575
576   memset (&resp, '\0', sizeof (ypresp_master));
577
578   result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
579           (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
580
581   if (result != YPERR_SUCCESS)
582     return result;
583   if (resp.stat != YP_TRUE)
584     return ypprot_err (resp.stat);
585
586   *outname = strdup (resp.peer);
587   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
588
589   return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
590 }
591
592 int
593 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
594 {
595   struct ypreq_nokey req;
596   struct ypresp_order resp;
597   enum clnt_stat result;
598
599   if (indomain == NULL || indomain[0] == '\0' ||
600       inmap == NULL || inmap == '\0')
601     return YPERR_BADARGS;
602
603   req.domain = (char *) indomain;
604   req.map = (char *) inmap;
605
606   memset (&resp, '\0', sizeof (resp));
607
608   result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
609            (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
610
611   if (result != YPERR_SUCCESS)
612     return result;
613   if (resp.stat != YP_TRUE)
614     return ypprot_err (resp.stat);
615
616   *outorder = resp.ordernum;
617   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
618
619   return YPERR_SUCCESS;
620 }
621
622 static void *ypall_data;
623 static int (*ypall_foreach) (int status, char *key, int keylen,
624                              char *val, int vallen, char *data);
625
626 static bool_t
627 __xdr_ypresp_all (XDR *xdrs, u_long *objp)
628 {
629   while (1)
630     {
631       struct ypresp_all resp;
632
633       memset (&resp, '\0', sizeof (struct ypresp_all));
634       if (!xdr_ypresp_all (xdrs, &resp))
635         {
636           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
637           *objp = YP_YPERR;
638           return FALSE;
639         }
640       if (resp.more == 0)
641         {
642           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
643           *objp = YP_NOMORE;
644           return TRUE;
645         }
646
647       switch (resp.ypresp_all_u.val.stat)
648         {
649         case YP_TRUE:
650           {
651             char key[resp.ypresp_all_u.val.key.keydat_len + 1];
652             char val[resp.ypresp_all_u.val.val.valdat_len + 1];
653             int keylen = resp.ypresp_all_u.val.key.keydat_len;
654             int vallen = resp.ypresp_all_u.val.val.valdat_len;
655
656             /* We are not allowed to modify the key and val data.
657                But we are allowed to add data behind the buffer,
658                if we don't modify the length. So add an extra NUL
659                character to avoid trouble with broken code. */
660             *objp = YP_TRUE;
661             memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
662             key[keylen] = '\0';
663             memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
664             val[vallen] = '\0';
665             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
666             if ((*ypall_foreach) (*objp, key, keylen,
667                                   val, vallen, ypall_data))
668               return TRUE;
669           }
670           break;
671         default:
672           *objp = resp.ypresp_all_u.val.stat;
673           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
674           /* Sun says we don't need to make this call, but must return
675              immediatly. Since Solaris makes this call, we will call
676              the callback function, too. */
677           (*ypall_foreach) (*objp, NULL, 0, NULL, 0, ypall_data);
678           return TRUE;
679         }
680     }
681 }
682
683 int
684 yp_all (const char *indomain, const char *inmap,
685         const struct ypall_callback *incallback)
686 {
687   struct ypreq_nokey req;
688   dom_binding *ydb = NULL;
689   int try, res;
690   enum clnt_stat result;
691   struct sockaddr_in clnt_sin;
692   CLIENT *clnt;
693   unsigned long status;
694   int clnt_sock;
695   int saved_errno = errno;
696
697   if (indomain == NULL || indomain[0] == '\0' ||
698       inmap == NULL || inmap == '\0')
699     return YPERR_BADARGS;
700
701   try = 0;
702   res = YPERR_YPERR;
703
704   while (try < MAXTRIES && res != YPERR_SUCCESS)
705     {
706       if (__yp_bind (indomain, &ydb) != 0)
707         {
708           __set_errno (saved_errno);
709           return YPERR_DOMAIN;
710         }
711
712       clnt_sock = RPC_ANYSOCK;
713       clnt_sin = ydb->dom_server_addr;
714       clnt_sin.sin_port = 0;
715
716       /* We don't need the UDP connection anymore.  */
717       __yp_unbind (ydb);
718       free (ydb);
719       ydb = NULL;
720
721       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
722       if (clnt == NULL)
723         {
724           __set_errno (saved_errno);
725           return YPERR_PMAP;
726         }
727       req.domain = (char *) indomain;
728       req.map = (char *) inmap;
729
730       ypall_foreach = incallback->foreach;
731       ypall_data = (void *) incallback->data;
732
733       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
734                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
735                           (caddr_t) &status, RPCTIMEOUT);
736
737       if (result != RPC_SUCCESS)
738         {
739           /* Print the error message only on the last try */
740           if (try == MAXTRIES - 1)
741             clnt_perror (clnt, "yp_all: clnt_call");
742           res = YPERR_RPC;
743         }
744       else
745         res = YPERR_SUCCESS;
746
747       clnt_destroy (clnt);
748
749       if (res == YPERR_SUCCESS && status != YP_NOMORE)
750         {
751           __set_errno (saved_errno);
752           return ypprot_err (status);
753         }
754       ++try;
755     }
756
757   __set_errno (saved_errno);
758
759   return res;
760 }
761
762 int
763 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
764 {
765   struct ypresp_maplist resp;
766   enum clnt_stat result;
767
768   if (indomain == NULL || indomain[0] == '\0')
769     return YPERR_BADARGS;
770
771   memset (&resp, '\0', sizeof (resp));
772
773   result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
774     (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
775
776   if (result != YPERR_SUCCESS)
777     return result;
778   if (resp.stat != YP_TRUE)
779     return ypprot_err (resp.stat);
780
781   *outmaplist = resp.maps;
782   /* We give the list not free, this will be done by ypserv
783      xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
784
785   return YPERR_SUCCESS;
786 }
787
788 const char *
789 yperr_string (const int error)
790 {
791   switch (error)
792     {
793     case YPERR_SUCCESS:
794       return _("Success");
795     case YPERR_BADARGS:
796       return _("Request arguments bad");
797     case YPERR_RPC:
798       return _("RPC failure on NIS operation");
799     case YPERR_DOMAIN:
800       return _("Can't bind to server which serves this domain");
801     case YPERR_MAP:
802       return _("No such map in server's domain");
803     case YPERR_KEY:
804       return _("No such key in map");
805     case YPERR_YPERR:
806       return _("Internal NIS error");
807     case YPERR_RESRC:
808       return _("Local resource allocation failure");
809     case YPERR_NOMORE:
810       return _("No more records in map database");
811     case YPERR_PMAP:
812       return _("Can't communicate with portmapper");
813     case YPERR_YPBIND:
814       return _("Can't communicate with ypbind");
815     case YPERR_YPSERV:
816       return _("Can't communicate with ypserv");
817     case YPERR_NODOM:
818       return _("Local domain name not set");
819     case YPERR_BADDB:
820       return _("NIS map database is bad");
821     case YPERR_VERS:
822       return _("NIS client/server version mismatch - can't supply service");
823     case YPERR_ACCESS:
824       return _("Permission denied");
825     case YPERR_BUSY:
826       return _("Database is busy");
827     }
828   return _("Unknown NIS error code");
829 }
830
831 int
832 ypprot_err (const int code)
833 {
834   switch (code)
835     {
836     case YP_TRUE:
837       return YPERR_SUCCESS;
838     case YP_NOMORE:
839       return YPERR_NOMORE;
840     case YP_FALSE:
841       return YPERR_YPERR;
842     case YP_NOMAP:
843       return YPERR_MAP;
844     case YP_NODOM:
845       return YPERR_DOMAIN;
846     case YP_NOKEY:
847       return YPERR_KEY;
848     case YP_BADOP:
849       return YPERR_YPERR;
850     case YP_BADDB:
851       return YPERR_BADDB;
852     case YP_YPERR:
853       return YPERR_YPERR;
854     case YP_BADARGS:
855       return YPERR_BADARGS;
856     case YP_VERS:
857       return YPERR_VERS;
858     }
859   return YPERR_YPERR;
860 }
861
862 const char *
863 ypbinderr_string (const int error)
864 {
865   switch (error)
866     {
867     case 0:
868       return _("Success");
869     case YPBIND_ERR_ERR:
870       return _("Internal ypbind error");
871     case YPBIND_ERR_NOSERV:
872       return _("Domain not bound");
873     case YPBIND_ERR_RESC:
874       return _("System resource allocation failure");
875     default:
876       return _("Unknown ypbind error");
877     }
878 }
879
880
881 #define WINDOW 60
882
883 int
884 yp_update (char *domain, char *map, unsigned ypop,
885            char *key, int keylen, char *data, int datalen)
886 {
887   union
888     {
889       ypupdate_args update_args;
890       ypdelete_args delete_args;
891     }
892   args;
893   xdrproc_t xdr_argument;
894   unsigned res = 0;
895   CLIENT *clnt;
896   char *master;
897   struct sockaddr saddr;
898   char servername[MAXNETNAMELEN + 1];
899   int r;
900
901   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
902     return YPERR_BADARGS;
903
904   args.update_args.mapname = map;
905   args.update_args.key.yp_buf_len = keylen;
906   args.update_args.key.yp_buf_val = key;
907   args.update_args.datum.yp_buf_len = datalen;
908   args.update_args.datum.yp_buf_val = data;
909
910   if ((r = yp_master (domain, map, &master)) != 0)
911     return r;
912
913   if (!host2netname (servername, master, domain))
914     {
915       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
916       return YPERR_YPERR;
917     }
918
919   if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
920     {
921       clnt_pcreateerror ("yp_update: clnt_create");
922       return YPERR_RPC;
923     }
924
925   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
926     {
927       fputs (_("yp_update: cannot get server address\n"), stderr);
928       return YPERR_RPC;
929     }
930
931   switch (ypop)
932     {
933     case YPOP_CHANGE:
934     case YPOP_INSERT:
935     case YPOP_STORE:
936       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
937       break;
938     case YPOP_DELETE:
939       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
940       break;
941     default:
942       return YPERR_BADARGS;
943       break;
944     }
945
946   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
947
948   if (clnt->cl_auth == NULL)
949     clnt->cl_auth = authunix_create_default ();
950
951 again:
952   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
953                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
954
955   if (r == RPC_AUTHERROR)
956     {
957       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
958         {
959           clnt->cl_auth = authunix_create_default ();
960           goto again;
961         }
962       else
963         return YPERR_ACCESS;
964     }
965   if (r != RPC_SUCCESS)
966     {
967       clnt_perror (clnt, "yp_update: clnt_call");
968       return YPERR_RPC;
969     }
970   return res;
971 }