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