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