Remove K&R compatibility.
[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@suse.de>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU 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   };
46 typedef struct dom_binding dom_binding;
47
48 static struct timeval RPCTIMEOUT = {25, 0};
49 static struct timeval UDPTIMEOUT = {5, 0};
50 static int const MAXTRIES = 2;
51 static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
52 __libc_lock_define_initialized (static, ypbindlist_lock)
53 static dom_binding *__ypbindlist = NULL;
54
55
56 static int
57 __yp_bind (const char *domain, dom_binding **ypdb)
58 {
59   struct sockaddr_in clnt_saddr;
60   struct ypbind_resp ypbr;
61   dom_binding *ysd = NULL;
62   int clnt_sock;
63   CLIENT *client;
64   int is_new = 0;
65
66   if (domain == NULL || domain[0] == '\0')
67     return YPERR_BADARGS;
68
69   if (ypdb != NULL)
70     {
71       ysd = *ypdb;
72       while (ysd != NULL)
73         {
74           if (strcmp (domain, ysd->dom_domain) == 0)
75             break;
76           ysd = ysd->dom_pnext;
77         }
78     }
79
80   if (ysd == NULL)
81     {
82       is_new = 1;
83       ysd = (dom_binding *) calloc (1, sizeof *ysd);
84     }
85
86 #if USE_BINDINGDIR
87   if (ysd->dom_client == NULL)
88     {
89       /* Try binding dir at first if we have no binding */
90       char path[sizeof (BINDINGDIR) + strlen (domain) + 10];
91       struct iovec vec[2];
92       unsigned short port;
93       int fd;
94
95       sprintf (path, "%s/%s.%d", BINDINGDIR, domain, YPBINDVERS);
96       fd = open (path, O_RDONLY);
97       if (fd >= 0)
98         {
99           /* We have a binding file and could save a RPC call */
100           vec[0].iov_base = &port;
101           vec[0].iov_len = sizeof (port);
102           vec[1].iov_base = &ypbr;
103           vec[1].iov_len = sizeof (ypbr);
104
105           if (readv (fd, vec, 2) == sizeof (port) + sizeof (ypbr))
106             {
107               ysd->dom_server_addr.sin_family = AF_INET;
108               memcpy (&ysd->dom_server_addr.sin_port,
109                       ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
110                       sizeof (ysd->dom_server_addr.sin_port));
111               memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
112                       ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
113                       sizeof (ysd->dom_server_addr.sin_addr.s_addr));
114               strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
115               ysd->dom_domain[YPMAXDOMAIN] = '\0';
116
117               ysd->dom_socket = RPC_ANYSOCK;
118               ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG,
119                                                 YPVERS, UDPTIMEOUT,
120                                                 &ysd->dom_socket);
121
122               if (ysd->dom_client != NULL)
123                 /* If the program exits, close the socket */
124                 if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
125                   perror ("fcntl: F_SETFD");
126             }
127           close (fd);
128         }
129     }
130 #endif /* USE_BINDINGDIR */
131
132   if (ysd->dom_client == NULL)
133     {
134       memset (&clnt_saddr, '\0', sizeof clnt_saddr);
135       clnt_saddr.sin_family = AF_INET;
136       clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
137       clnt_sock = RPC_ANYSOCK;
138       client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
139                                &clnt_sock, 0, 0);
140       if (client == NULL)
141         {
142           if (is_new)
143             free (ysd);
144           return YPERR_YPBIND;
145         }
146       /* Check the port number -- should be < IPPORT_RESERVED.
147          If not, it's possible someone has registered a bogus
148          ypbind with the portmapper and is trying to trick us. */
149       if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
150         {
151           clnt_destroy (client);
152           if (is_new)
153             free (ysd);
154           return YPERR_YPBIND;
155         }
156
157       if (clnt_call (client, YPBINDPROC_DOMAIN,
158                      (xdrproc_t) xdr_domainname, (caddr_t) &domain,
159                      (xdrproc_t) xdr_ypbind_resp,
160                      (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
161         {
162           clnt_destroy (client);
163           if (is_new)
164             free (ysd);
165           return YPERR_YPBIND;
166         }
167
168       clnt_destroy (client);
169
170       if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
171         {
172           fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
173                    ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
174           if (is_new)
175             free (ysd);
176           return YPERR_DOMAIN;
177         }
178       memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
179       ysd->dom_server_addr.sin_family = AF_INET;
180       memcpy (&ysd->dom_server_addr.sin_port,
181               ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
182               sizeof (ysd->dom_server_addr.sin_port));
183       memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
184               ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
185               sizeof (ysd->dom_server_addr.sin_addr.s_addr));
186       strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
187       ysd->dom_domain[YPMAXDOMAIN] = '\0';
188
189       ysd->dom_socket = RPC_ANYSOCK;
190       ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
191                                         UDPTIMEOUT, &ysd->dom_socket);
192
193       if (ysd->dom_client != NULL)
194         /* If the program exits, close the socket */
195         if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
196           perror ("fcntl: F_SETFD");
197     }
198
199   if (ysd->dom_client == NULL)
200     {
201       if (is_new)
202         free (ysd);
203       return YPERR_YPSERV;
204     }
205
206   if (is_new && ypdb != NULL)
207     {
208       ysd->dom_pnext = *ypdb;
209       *ypdb = ysd;
210     }
211
212   return YPERR_SUCCESS;
213 }
214
215 static void
216 __yp_unbind (dom_binding *ydb)
217 {
218   clnt_destroy (ydb->dom_client);
219   ydb->dom_client = NULL;
220 }
221
222 int
223 yp_bind (const char *indomain)
224 {
225   int status;
226
227   __libc_lock_lock (ypbindlist_lock);
228
229   status = __yp_bind (indomain, &__ypbindlist);
230
231   __libc_lock_unlock (ypbindlist_lock);
232
233   return status;
234 }
235
236 static void
237 yp_unbind_locked (const char *indomain)
238 {
239   dom_binding *ydbptr, *ydbptr2;
240
241   ydbptr2 = NULL;
242   ydbptr = __ypbindlist;
243
244   while (ydbptr != NULL)
245     {
246       if (strcmp (ydbptr->dom_domain, indomain) == 0)
247         {
248           dom_binding *work;
249
250           work = ydbptr;
251           if (ydbptr2 == NULL)
252             __ypbindlist = __ypbindlist->dom_pnext;
253           else
254             ydbptr2 = ydbptr->dom_pnext;
255           __yp_unbind (work);
256           free (work);
257           break;
258         }
259       ydbptr2 = ydbptr;
260       ydbptr = ydbptr->dom_pnext;
261     }
262 }
263
264 void
265 yp_unbind (const char *indomain)
266 {
267   __libc_lock_lock (ypbindlist_lock);
268
269   yp_unbind_locked (indomain);
270
271   __libc_lock_unlock (ypbindlist_lock);
272
273   return;
274 }
275
276 static int
277 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
278            caddr_t req, xdrproc_t xres, caddr_t resp)
279 {
280   dom_binding *ydb = NULL;
281   bool_t use_ypbindlist = FALSE;
282   int try, status;
283   enum clnt_stat result;
284   int saved_errno = errno;
285
286   try = 0;
287   status = YPERR_YPERR;
288
289   __libc_lock_lock (ypbindlist_lock);
290   if (__ypbindlist != NULL)
291     {
292       ydb = __ypbindlist;
293       while (ydb != NULL)
294         {
295           if (strcmp (domain, ydb->dom_domain) == 0)
296             break;
297           ydb = ydb->dom_pnext;
298         }
299       if (ydb != NULL)
300         use_ypbindlist = TRUE;
301       else
302         __libc_lock_unlock (ypbindlist_lock);
303     }
304   else
305     __libc_lock_unlock (ypbindlist_lock);
306
307   while (try < MAXTRIES && status != YPERR_SUCCESS)
308     {
309       if (__yp_bind (domain, &ydb) != 0)
310         {
311           if (use_ypbindlist)
312             __libc_lock_unlock (ypbindlist_lock);
313           __set_errno (saved_errno);
314           return YPERR_DOMAIN;
315         }
316
317       result = clnt_call (ydb->dom_client, prog,
318                           xargs, req, xres, resp, RPCTIMEOUT);
319
320       if (result != RPC_SUCCESS)
321         {
322           /* Don't print the error message on the first try. It
323              could be that we use cached data which is now invalid. */
324           if (try != 0)
325             clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
326
327           if (use_ypbindlist)
328             {
329               /* We use ypbindlist, and the old cached data is
330                  invalid. unbind now and create a new binding */
331               yp_unbind_locked (domain);
332               __libc_lock_unlock (ypbindlist_lock);
333               use_ypbindlist = FALSE;
334             }
335           else
336             {
337               __yp_unbind (ydb);
338               free (ydb);
339             }
340
341           ydb = NULL;
342           status = YPERR_RPC;
343         }
344       else
345         status = YPERR_SUCCESS;
346
347       try++;
348     }
349   if (use_ypbindlist)
350     {
351       __libc_lock_unlock (ypbindlist_lock);
352       use_ypbindlist = FALSE;
353     }
354   else
355     if (ydb != NULL)
356       {
357         __yp_unbind (ydb);
358         free (ydb);
359         ydb = NULL;
360       }
361
362   __set_errno (saved_errno);
363
364   return status;
365 }
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) (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             /* We are not allowed to modify the key and val data.
640                But we are allowed to add data behind the buffer,
641                if we don't modify the length. So add an extra NUL
642                character to avoid trouble with broken code. */
643             *objp = YP_TRUE;
644             memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
645             key[keylen] = '\0';
646             memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
647             val[vallen] = '\0';
648             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
649             if ((*ypall_foreach) (*objp, key, keylen,
650                                   val, vallen, ypall_data))
651               return TRUE;
652           }
653           break;
654         default:
655           *objp = resp.ypresp_all_u.val.stat;
656           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
657           /* Sun says we don't need to make this call, but must return
658              immediatly. Since Solaris makes this call, we will call
659              the callback function, too. */
660           (*ypall_foreach) (*objp, NULL, 0, NULL, 0, ypall_data);
661           return TRUE;
662         }
663     }
664 }
665
666 int
667 yp_all (const char *indomain, const char *inmap,
668         const struct ypall_callback *incallback)
669 {
670   struct ypreq_nokey req;
671   dom_binding *ydb = NULL;
672   int try, res;
673   enum clnt_stat result;
674   struct sockaddr_in clnt_sin;
675   CLIENT *clnt;
676   unsigned long status;
677   int clnt_sock;
678   int saved_errno = errno;
679
680   if (indomain == NULL || indomain[0] == '\0' ||
681       inmap == NULL || inmap == '\0')
682     return YPERR_BADARGS;
683
684   try = 0;
685   res = YPERR_YPERR;
686
687   while (try < MAXTRIES && res != YPERR_SUCCESS)
688     {
689       if (__yp_bind (indomain, &ydb) != 0)
690         {
691           __set_errno (saved_errno);
692           return YPERR_DOMAIN;
693         }
694
695       /* YPPROC_ALL get its own TCP channel to ypserv.  Therefore we
696          close the socket opened by the __yp_bind call.  */
697       close (ydb->dom_socket);
698       clnt_sock = RPC_ANYSOCK;
699       clnt_sin = ydb->dom_server_addr;
700       clnt_sin.sin_port = 0;
701       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
702       if (clnt == NULL)
703         {
704           __yp_unbind (ydb);
705           __set_errno (saved_errno);
706           return YPERR_PMAP;
707         }
708       req.domain = (char *) indomain;
709       req.map = (char *) inmap;
710
711       ypall_foreach = incallback->foreach;
712       ypall_data = (void *) incallback->data;
713
714       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
715                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
716                           (caddr_t) &status, RPCTIMEOUT);
717
718       if (result != RPC_SUCCESS)
719         {
720           clnt_perror (clnt, "yp_all: clnt_call");
721           res = YPERR_RPC;
722         }
723       else
724         res = YPERR_SUCCESS;
725
726       __yp_unbind (ydb);
727       clnt_destroy (clnt);
728
729       if (status != YP_NOMORE)
730         {
731           __set_errno (saved_errno);
732           return ypprot_err (status);
733         }
734       ++try;
735     }
736
737   __set_errno (saved_errno);
738
739   return res;
740 }
741
742 int
743 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
744 {
745   struct ypresp_maplist resp;
746   enum clnt_stat result;
747
748   if (indomain == NULL || indomain[0] == '\0')
749     return YPERR_BADARGS;
750
751   memset (&resp, '\0', sizeof (resp));
752
753   result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
754     (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
755
756   if (result != YPERR_SUCCESS)
757     return result;
758   if (resp.stat != YP_TRUE)
759     return ypprot_err (resp.stat);
760
761   *outmaplist = resp.maps;
762   /* We give the list not free, this will be done by ypserv
763      xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
764
765   return YPERR_SUCCESS;
766 }
767
768 const char *
769 yperr_string (const int error)
770 {
771   switch (error)
772     {
773     case YPERR_SUCCESS:
774       return _("Success");
775     case YPERR_BADARGS:
776       return _("Request arguments bad");
777     case YPERR_RPC:
778       return _("RPC failure on NIS operation");
779     case YPERR_DOMAIN:
780       return _("Can't bind to server which serves this domain");
781     case YPERR_MAP:
782       return _("No such map in server's domain");
783     case YPERR_KEY:
784       return _("No such key in map");
785     case YPERR_YPERR:
786       return _("Internal NIS error");
787     case YPERR_RESRC:
788       return _("Local resource allocation failure");
789     case YPERR_NOMORE:
790       return _("No more records in map database");
791     case YPERR_PMAP:
792       return _("Can't communicate with portmapper");
793     case YPERR_YPBIND:
794       return _("Can't communicate with ypbind");
795     case YPERR_YPSERV:
796       return _("Can't communicate with ypserv");
797     case YPERR_NODOM:
798       return _("Local domain name not set");
799     case YPERR_BADDB:
800       return _("NIS map database is bad");
801     case YPERR_VERS:
802       return _("NIS client/server version mismatch - can't supply service");
803     case YPERR_ACCESS:
804       return _("Permission denied");
805     case YPERR_BUSY:
806       return _("Database is busy");
807     }
808   return _("Unknown NIS error code");
809 }
810
811 int
812 ypprot_err (const int code)
813 {
814   switch (code)
815     {
816     case YP_TRUE:
817       return YPERR_SUCCESS;
818     case YP_NOMORE:
819       return YPERR_NOMORE;
820     case YP_FALSE:
821       return YPERR_YPERR;
822     case YP_NOMAP:
823       return YPERR_MAP;
824     case YP_NODOM:
825       return YPERR_DOMAIN;
826     case YP_NOKEY:
827       return YPERR_KEY;
828     case YP_BADOP:
829       return YPERR_YPERR;
830     case YP_BADDB:
831       return YPERR_BADDB;
832     case YP_YPERR:
833       return YPERR_YPERR;
834     case YP_BADARGS:
835       return YPERR_BADARGS;
836     case YP_VERS:
837       return YPERR_VERS;
838     }
839   return YPERR_YPERR;
840 }
841
842 const char *
843 ypbinderr_string (const int error)
844 {
845   switch (error)
846     {
847     case 0:
848       return _("Success");
849     case YPBIND_ERR_ERR:
850       return _("Internal ypbind error");
851     case YPBIND_ERR_NOSERV:
852       return _("Domain not bound");
853     case YPBIND_ERR_RESC:
854       return _("System resource allocation failure");
855     default:
856       return _("Unknown ypbind error");
857     }
858 }
859
860
861 #define WINDOW 60
862
863 int
864 yp_update (char *domain, char *map, unsigned ypop,
865            char *key, int keylen, char *data, int datalen)
866 {
867   union
868     {
869       ypupdate_args update_args;
870       ypdelete_args delete_args;
871     }
872   args;
873   xdrproc_t xdr_argument;
874   unsigned res = 0;
875   CLIENT *clnt;
876   char *master;
877   struct sockaddr saddr;
878   char servername[MAXNETNAMELEN + 1];
879   int r;
880
881   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
882     return YPERR_BADARGS;
883
884   args.update_args.mapname = map;
885   args.update_args.key.yp_buf_len = keylen;
886   args.update_args.key.yp_buf_val = key;
887   args.update_args.datum.yp_buf_len = datalen;
888   args.update_args.datum.yp_buf_val = data;
889
890   if ((r = yp_master (domain, map, &master)) != 0)
891     return r;
892
893   if (!host2netname (servername, master, domain))
894     {
895       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
896       return YPERR_YPERR;
897     }
898
899   if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
900     {
901       clnt_pcreateerror ("yp_update: clnt_create");
902       return YPERR_RPC;
903     }
904
905   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
906     {
907       fputs (_("yp_update: cannot get server address\n"), stderr);
908       return YPERR_RPC;
909     }
910
911   switch (ypop)
912     {
913     case YPOP_CHANGE:
914     case YPOP_INSERT:
915     case YPOP_STORE:
916       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
917       break;
918     case YPOP_DELETE:
919       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
920       break;
921     default:
922       return YPERR_BADARGS;
923       break;
924     }
925
926   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
927
928   if (clnt->cl_auth == NULL)
929     clnt->cl_auth = authunix_create_default ();
930
931 again:
932   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
933                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
934
935   if (r == RPC_AUTHERROR)
936     {
937       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
938         {
939           clnt->cl_auth = authunix_create_default ();
940           goto again;
941         }
942       else
943         return YPERR_ACCESS;
944     }
945   if (r != RPC_SUCCESS)
946     {
947       clnt_perror (clnt, "yp_update: clnt_call");
948       return YPERR_RPC;
949     }
950   return res;
951 }