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