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