chiark / gitweb /
Apply https://sourceware.org/git/?p=glibc.git;a=commit;h=d5dd6189d506068ed11c8bfa1e1e...
[eglibc.git] / nis / ypclnt.c
1 /* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008
2    Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <libintl.h>
26 #include <rpc/rpc.h>
27 #include <rpcsvc/nis.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/ypupd.h>
31 #include <sys/socket.h>
32 #include <sys/uio.h>
33 #include <bits/libc-lock.h>
34
35 /* This should only be defined on systems with a BSD compatible ypbind */
36 #ifndef BINDINGDIR
37 # define BINDINGDIR "/var/yp/binding"
38 #endif
39
40 struct dom_binding
41   {
42     struct dom_binding *dom_pnext;
43     char dom_domain[YPMAXDOMAIN + 1];
44     struct sockaddr_in dom_server_addr;
45     int dom_socket;
46     CLIENT *dom_client;
47   };
48 typedef struct dom_binding dom_binding;
49
50 static const struct timeval RPCTIMEOUT = {25, 0};
51 static const struct timeval UDPTIMEOUT = {5, 0};
52 static int const MAXTRIES = 2;
53 static char ypdomainname[NIS_MAXNAMELEN + 1];
54 __libc_lock_define_initialized (static, ypbindlist_lock)
55 static dom_binding *ypbindlist = NULL;
56
57
58 static void
59 yp_bind_client_create (const char *domain, dom_binding *ysd,
60                        struct ypbind_resp *ypbr)
61 {
62   ysd->dom_server_addr.sin_family = AF_INET;
63   memcpy (&ysd->dom_server_addr.sin_port,
64           ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
65           sizeof (ysd->dom_server_addr.sin_port));
66   memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
67           ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
68           sizeof (ysd->dom_server_addr.sin_addr.s_addr));
69   strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
70   ysd->dom_domain[YPMAXDOMAIN] = '\0';
71
72   ysd->dom_socket = RPC_ANYSOCK;
73 #ifdef SOCK_CLOEXEC
74 # define xflags SOCK_CLOEXEC
75 #else
76 # define xflags 0
77 #endif
78   ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
79                                               YPVERS, UDPTIMEOUT,
80                                               &ysd->dom_socket,
81                                               UDPMSGSIZE, UDPMSGSIZE,
82                                               xflags);
83
84   if (ysd->dom_client != NULL)
85     {
86 #ifndef SOCK_CLOEXEC
87       /* If the program exits, close the socket */
88       if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
89         perror ("fcntl: F_SETFD");
90 #endif
91     }
92 }
93
94 #if USE_BINDINGDIR
95 static void
96 yp_bind_file (const char *domain, dom_binding *ysd)
97 {
98   char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
99
100   snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
101   int fd = open (path, O_RDONLY);
102   if (fd >= 0)
103     {
104       /* We have a binding file and could save a RPC call.  The file
105          contains a port number and the YPBIND_RESP record.  The port
106          number (16 bits) can be ignored.  */
107       struct ypbind_resp ypbr;
108
109       if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
110         yp_bind_client_create (domain, ysd, &ypbr);
111
112       close (fd);
113     }
114 }
115 #endif
116
117 static int
118 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
119 {
120   struct sockaddr_in clnt_saddr;
121   struct ypbind_resp ypbr;
122   int clnt_sock;
123   CLIENT *client;
124
125   clnt_saddr.sin_family = AF_INET;
126   clnt_saddr.sin_port = 0;
127   clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
128   clnt_sock = RPC_ANYSOCK;
129   client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
130                            &clnt_sock, 0, 0);
131   if (client == NULL)
132     return YPERR_YPBIND;
133
134   /* Check the port number -- should be < IPPORT_RESERVED.
135      If not, it's possible someone has registered a bogus
136      ypbind with the portmapper and is trying to trick us. */
137   if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
138     {
139       clnt_destroy (client);
140       return YPERR_YPBIND;
141     }
142
143   if (clnt_call (client, YPBINDPROC_DOMAIN,
144                  (xdrproc_t) xdr_domainname, (caddr_t) &domain,
145                  (xdrproc_t) xdr_ypbind_resp,
146                  (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
147     {
148       clnt_destroy (client);
149       return YPERR_YPBIND;
150     }
151
152   clnt_destroy (client);
153
154   if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
155     {
156       fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
157                ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
158       return YPERR_DOMAIN;
159     }
160   memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
161
162   yp_bind_client_create (domain, ysd, &ypbr);
163
164   return YPERR_SUCCESS;
165 }
166
167 static int
168 __yp_bind (const char *domain, dom_binding **ypdb)
169 {
170   dom_binding *ysd = NULL;
171   int is_new = 0;
172
173   if (domain == NULL || domain[0] == '\0')
174     return YPERR_BADARGS;
175
176   ysd = *ypdb;
177   while (ysd != NULL)
178     {
179       if (strcmp (domain, ysd->dom_domain) == 0)
180         break;
181       ysd = ysd->dom_pnext;
182     }
183
184   if (ysd == NULL)
185     {
186       is_new = 1;
187       ysd = (dom_binding *) calloc (1, sizeof *ysd);
188       if (__builtin_expect (ysd == NULL, 0))
189         return YPERR_RESRC;
190     }
191
192 #if USE_BINDINGDIR
193   /* Try binding dir at first if we have no binding */
194   if (ysd->dom_client == NULL)
195     yp_bind_file (domain, ysd);
196 #endif /* USE_BINDINGDIR */
197
198   if (ysd->dom_client == NULL)
199     {
200       int retval = yp_bind_ypbindprog (domain, ysd);
201       if (retval != YPERR_SUCCESS)
202         {
203           if (is_new)
204             free (ysd);
205           return retval;
206         }
207     }
208
209   if (ysd->dom_client == NULL)
210     {
211       if (is_new)
212         free (ysd);
213       return YPERR_YPSERV;
214     }
215
216   if (is_new)
217     {
218       ysd->dom_pnext = *ypdb;
219       *ypdb = ysd;
220     }
221
222   return YPERR_SUCCESS;
223 }
224
225 static void
226 __yp_unbind (dom_binding *ydb)
227 {
228   clnt_destroy (ydb->dom_client);
229   free (ydb);
230 }
231
232 int
233 yp_bind (const char *indomain)
234 {
235   int status;
236
237   __libc_lock_lock (ypbindlist_lock);
238
239   status = __yp_bind (indomain, &ypbindlist);
240
241   __libc_lock_unlock (ypbindlist_lock);
242
243   return status;
244 }
245 libnsl_hidden_def (yp_bind)
246
247 static void
248 yp_unbind_locked (const char *indomain)
249 {
250   dom_binding *ydbptr, *ydbptr2;
251
252   ydbptr2 = NULL;
253   ydbptr = ypbindlist;
254
255   while (ydbptr != NULL)
256     {
257       if (strcmp (ydbptr->dom_domain, indomain) == 0)
258         {
259           dom_binding *work;
260
261           work = ydbptr;
262           if (ydbptr2 == NULL)
263             ypbindlist = ypbindlist->dom_pnext;
264           else
265             ydbptr2 = ydbptr->dom_pnext;
266           __yp_unbind (work);
267           break;
268         }
269       ydbptr2 = ydbptr;
270       ydbptr = ydbptr->dom_pnext;
271     }
272 }
273
274 void
275 yp_unbind (const char *indomain)
276 {
277   __libc_lock_lock (ypbindlist_lock);
278
279   yp_unbind_locked (indomain);
280
281   __libc_lock_unlock (ypbindlist_lock);
282
283   return;
284 }
285
286 static int
287 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
288                caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
289                int print_error)
290 {
291   enum clnt_stat result;
292
293   result = clnt_call ((*ydb)->dom_client, prog,
294                       xargs, req, xres, resp, RPCTIMEOUT);
295
296   if (result != RPC_SUCCESS)
297     {
298       /* We don't print an error message, if we try our old,
299          cached data. Only print this for data, which should work.  */
300       if (print_error)
301         clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
302
303       return YPERR_RPC;
304     }
305
306   return YPERR_SUCCESS;
307 }
308
309 static int
310 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
311            caddr_t req, xdrproc_t xres, caddr_t resp)
312 {
313   dom_binding *ydb;
314   int status;
315   int saved_errno = errno;
316
317   status = YPERR_YPERR;
318
319   __libc_lock_lock (ypbindlist_lock);
320   ydb = ypbindlist;
321   while (ydb != NULL)
322     {
323       if (strcmp (domain, ydb->dom_domain) == 0)
324         {
325           if (__yp_bind (domain, &ydb) == 0)
326             {
327               /* Call server, print no error message, do not unbind.  */
328               status = __ypclnt_call (domain, prog, xargs, req, xres,
329                                       resp, &ydb, 0);
330               if (status == YPERR_SUCCESS)
331                 {
332                   __libc_lock_unlock (ypbindlist_lock);
333                   __set_errno (saved_errno);
334                   return status;
335                 }
336             }
337           /* We use ypbindlist, and the old cached data is
338              invalid. unbind now and create a new binding */
339           yp_unbind_locked (domain);
340
341           break;
342         }
343       ydb = ydb->dom_pnext;
344     }
345   __libc_lock_unlock (ypbindlist_lock);
346
347   /* First try with cached data failed. Now try to get
348      current data from the system.  */
349   ydb = NULL;
350   if (__yp_bind (domain, &ydb) == 0)
351     {
352       status = __ypclnt_call (domain, prog, xargs, req, xres,
353                               resp, &ydb, 1);
354       __yp_unbind (ydb);
355     }
356
357 #if USE_BINDINGDIR
358   /* If we support binding dir data, we have a third chance:
359      Ask ypbind.  */
360   if (status != YPERR_SUCCESS)
361     {
362       ydb = calloc (1, sizeof (dom_binding));
363       if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
364         {
365           status = __ypclnt_call (domain, prog, xargs, req, xres,
366                                   resp, &ydb, 1);
367           __yp_unbind (ydb);
368         }
369       else
370         free (ydb);
371     }
372 #endif
373
374   __set_errno (saved_errno);
375
376   return status;
377 }
378
379 /* Like do_ypcall, but translate the status value if necessary.  */
380 static int
381 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
382               caddr_t req, xdrproc_t xres, caddr_t resp)
383 {
384   int status = do_ypcall (domain, prog, xargs, req, xres, resp);
385   if (status == YPERR_SUCCESS)
386     /* We cast to ypresp_val although the pointer could also be of
387        type ypresp_key_val or ypresp_master or ypresp_order or
388        ypresp_maplist.  But the stat element is in a common prefix so
389        this does not matter.  */
390     status = ypprot_err (((struct ypresp_val *) resp)->stat);
391   return status;
392 }
393
394
395 __libc_lock_define_initialized (static, domainname_lock)
396
397 int
398 yp_get_default_domain (char **outdomain)
399 {
400   int result = YPERR_SUCCESS;;
401   *outdomain = NULL;
402
403   __libc_lock_lock (domainname_lock);
404
405   if (ypdomainname[0] == '\0')
406     {
407       if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
408         result = YPERR_NODOM;
409       else if (strcmp (ypdomainname, "(none)") == 0)
410         {
411           /* If domainname is not set, some systems will return "(none)" */
412           ypdomainname[0] = '\0';
413           result = YPERR_NODOM;
414         }
415       else
416         *outdomain = ypdomainname;
417     }
418   else
419     *outdomain = ypdomainname;
420
421   __libc_lock_unlock (domainname_lock);
422
423   return result;
424 }
425 libnsl_hidden_def (yp_get_default_domain)
426
427 int
428 __yp_check (char **domain)
429 {
430   char *unused;
431
432   if (ypdomainname[0] == '\0')
433     if (yp_get_default_domain (&unused))
434       return 0;
435
436   if (domain)
437     *domain = ypdomainname;
438
439   if (yp_bind (ypdomainname) == 0)
440     return 1;
441   return 0;
442 }
443
444 int
445 yp_match (const char *indomain, const char *inmap, const char *inkey,
446           const int inkeylen, char **outval, int *outvallen)
447 {
448   ypreq_key req;
449   ypresp_val resp;
450   enum clnt_stat result;
451
452   if (indomain == NULL || indomain[0] == '\0' ||
453       inmap == NULL || inmap[0] == '\0' ||
454       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
455     return YPERR_BADARGS;
456
457   req.domain = (char *) indomain;
458   req.map = (char *) inmap;
459   req.key.keydat_val = (char *) inkey;
460   req.key.keydat_len = inkeylen;
461
462   *outval = NULL;
463   *outvallen = 0;
464   memset (&resp, '\0', sizeof (resp));
465
466   result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
467                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
468                          (caddr_t) &resp);
469
470   if (result != YPERR_SUCCESS)
471     return result;
472
473   *outvallen = resp.val.valdat_len;
474   *outval = malloc (*outvallen + 1);
475   int status = YPERR_RESRC;
476   if (__builtin_expect (*outval != NULL, 1))
477     {
478       memcpy (*outval, resp.val.valdat_val, *outvallen);
479       (*outval)[*outvallen] = '\0';
480       status = YPERR_SUCCESS;
481     }
482
483   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
484
485   return status;
486 }
487
488 int
489 yp_first (const char *indomain, const char *inmap, char **outkey,
490           int *outkeylen, char **outval, int *outvallen)
491 {
492   ypreq_nokey req;
493   ypresp_key_val resp;
494   enum clnt_stat result;
495
496   if (indomain == NULL || indomain[0] == '\0' ||
497       inmap == NULL || inmap[0] == '\0')
498     return YPERR_BADARGS;
499
500   req.domain = (char *) indomain;
501   req.map = (char *) inmap;
502
503   *outkey = *outval = NULL;
504   *outkeylen = *outvallen = 0;
505   memset (&resp, '\0', sizeof (resp));
506
507   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
508                       (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
509                       (caddr_t) &resp);
510
511   if (result != RPC_SUCCESS)
512     return YPERR_RPC;
513   if (resp.stat != YP_TRUE)
514     return ypprot_err (resp.stat);
515
516   int status;
517   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
518                         && (*outval = malloc (resp.val.valdat_len
519                                               + 1)) != NULL, 1))
520     {
521       *outkeylen = resp.key.keydat_len;
522       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
523       (*outkey)[*outkeylen] = '\0';
524
525       *outvallen = resp.val.valdat_len;
526       memcpy (*outval, resp.val.valdat_val, *outvallen);
527       (*outval)[*outvallen] = '\0';
528
529       status = YPERR_SUCCESS;
530     }
531   else
532     {
533       free (*outkey);
534       status = YPERR_RESRC;
535     }
536
537   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
538
539   return status;
540 }
541
542 int
543 yp_next (const char *indomain, const char *inmap, const char *inkey,
544          const int inkeylen, char **outkey, int *outkeylen, char **outval,
545          int *outvallen)
546 {
547   ypreq_key req;
548   ypresp_key_val resp;
549   enum clnt_stat result;
550
551   if (indomain == NULL || indomain[0] == '\0' ||
552       inmap == NULL || inmap[0] == '\0' ||
553       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
554     return YPERR_BADARGS;
555
556   req.domain = (char *) indomain;
557   req.map = (char *) inmap;
558   req.key.keydat_val = (char *) inkey;
559   req.key.keydat_len = inkeylen;
560
561   *outkey = *outval = NULL;
562   *outkeylen = *outvallen = 0;
563   memset (&resp, '\0', sizeof (resp));
564
565   result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
566                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
567                          (caddr_t) &resp);
568
569   if (result != YPERR_SUCCESS)
570     return result;
571
572   int status;
573   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
574                         && (*outval = malloc (resp.val.valdat_len
575                                               + 1)) != NULL, 1))
576     {
577       *outkeylen = resp.key.keydat_len;
578       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
579       (*outkey)[*outkeylen] = '\0';
580
581       *outvallen = resp.val.valdat_len;
582       memcpy (*outval, resp.val.valdat_val, *outvallen);
583       (*outval)[*outvallen] = '\0';
584
585       status = YPERR_SUCCESS;
586     }
587   else
588     {
589       free (*outkey);
590       status = YPERR_RESRC;
591     }
592
593   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
594
595   return status;
596 }
597
598 int
599 yp_master (const char *indomain, const char *inmap, char **outname)
600 {
601   ypreq_nokey req;
602   ypresp_master resp;
603   enum clnt_stat result;
604
605   if (indomain == NULL || indomain[0] == '\0' ||
606       inmap == NULL || inmap[0] == '\0')
607     return YPERR_BADARGS;
608
609   req.domain = (char *) indomain;
610   req.map = (char *) inmap;
611
612   memset (&resp, '\0', sizeof (ypresp_master));
613
614   result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
615                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
616                          (caddr_t) &resp);
617
618   if (result != YPERR_SUCCESS)
619     return result;
620
621   *outname = strdup (resp.peer);
622   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
623
624   return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
625 }
626 libnsl_hidden_def (yp_master)
627
628 int
629 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
630 {
631   struct ypreq_nokey req;
632   struct ypresp_order resp;
633   enum clnt_stat result;
634
635   if (indomain == NULL || indomain[0] == '\0' ||
636       inmap == NULL || inmap[0] == '\0')
637     return YPERR_BADARGS;
638
639   req.domain = (char *) indomain;
640   req.map = (char *) inmap;
641
642   memset (&resp, '\0', sizeof (resp));
643
644   result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
645                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
646                          (caddr_t) &resp);
647
648   if (result != YPERR_SUCCESS)
649     return result;
650
651   *outorder = resp.ordernum;
652   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
653
654   return result;
655 }
656
657 struct ypresp_all_data
658 {
659   unsigned long status;
660   void *data;
661   int (*foreach) (int status, char *key, int keylen,
662                   char *val, int vallen, char *data);
663 };
664
665 static bool_t
666 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
667 {
668   while (1)
669     {
670       struct ypresp_all resp;
671
672       memset (&resp, '\0', sizeof (struct ypresp_all));
673       if (!xdr_ypresp_all (xdrs, &resp))
674         {
675           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
676           objp->status = YP_YPERR;
677           return FALSE;
678         }
679       if (resp.more == 0)
680         {
681           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
682           objp->status = YP_NOMORE;
683           return TRUE;
684         }
685
686       switch (resp.ypresp_all_u.val.stat)
687         {
688         case YP_TRUE:
689           {
690             char key[resp.ypresp_all_u.val.key.keydat_len + 1];
691             char val[resp.ypresp_all_u.val.val.valdat_len + 1];
692             int keylen = resp.ypresp_all_u.val.key.keydat_len;
693             int vallen = resp.ypresp_all_u.val.val.valdat_len;
694
695             /* We are not allowed to modify the key and val data.
696                But we are allowed to add data behind the buffer,
697                if we don't modify the length. So add an extra NUL
698                character to avoid trouble with broken code. */
699             objp->status = YP_TRUE;
700             *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
701                                   keylen)) = '\0';
702             *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
703                                   vallen)) = '\0';
704             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
705             if ((*objp->foreach) (objp->status, key, keylen,
706                                   val, vallen, objp->data))
707               return TRUE;
708           }
709           break;
710         default:
711           objp->status = resp.ypresp_all_u.val.stat;
712           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
713           /* Sun says we don't need to make this call, but must return
714              immediately. Since Solaris makes this call, we will call
715              the callback function, too. */
716           (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
717           return TRUE;
718         }
719     }
720 }
721
722 int
723 yp_all (const char *indomain, const char *inmap,
724         const struct ypall_callback *incallback)
725 {
726   struct ypreq_nokey req;
727   dom_binding *ydb = NULL;
728   int try, res;
729   enum clnt_stat result;
730   struct sockaddr_in clnt_sin;
731   CLIENT *clnt;
732   struct ypresp_all_data data;
733   int clnt_sock;
734   int saved_errno = errno;
735
736   if (indomain == NULL || indomain[0] == '\0'
737       || inmap == NULL || inmap[0] == '\0')
738     return YPERR_BADARGS;
739
740   try = 0;
741   res = YPERR_YPERR;
742
743   while (try < MAXTRIES && res != YPERR_SUCCESS)
744     {
745       if (__yp_bind (indomain, &ydb) != 0)
746         {
747           __set_errno (saved_errno);
748           return YPERR_DOMAIN;
749         }
750
751       clnt_sock = RPC_ANYSOCK;
752       clnt_sin = ydb->dom_server_addr;
753       clnt_sin.sin_port = 0;
754
755       /* We don't need the UDP connection anymore.  */
756       __yp_unbind (ydb);
757       ydb = NULL;
758
759       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
760       if (clnt == NULL)
761         {
762           __set_errno (saved_errno);
763           return YPERR_PMAP;
764         }
765       req.domain = (char *) indomain;
766       req.map = (char *) inmap;
767
768       data.foreach = incallback->foreach;
769       data.data = (void *) incallback->data;
770
771       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
772                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
773                           (caddr_t) &data, RPCTIMEOUT);
774
775       if (__builtin_expect (result != RPC_SUCCESS, 0))
776         {
777           /* Print the error message only on the last try.  */
778           if (try == MAXTRIES - 1)
779             clnt_perror (clnt, "yp_all: clnt_call");
780           res = YPERR_RPC;
781         }
782       else
783         res = YPERR_SUCCESS;
784
785       clnt_destroy (clnt);
786
787       if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
788         {
789           __set_errno (saved_errno);
790           return ypprot_err (data.status);
791         }
792       ++try;
793     }
794
795   __set_errno (saved_errno);
796
797   return res;
798 }
799
800 int
801
802 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
803 {
804   struct ypresp_maplist resp;
805   enum clnt_stat result;
806
807   if (indomain == NULL || indomain[0] == '\0')
808     return YPERR_BADARGS;
809
810   memset (&resp, '\0', sizeof (resp));
811
812   result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
813                          (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
814                          (caddr_t) &resp);
815
816   if (__builtin_expect (result == YPERR_SUCCESS, 1))
817     {
818       *outmaplist = resp.maps;
819       /* We don't free the list, this will be done by ypserv
820          xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
821     }
822
823   return result;
824 }
825
826 const char *
827 yperr_string (const int error)
828 {
829   const char *str;
830   switch (error)
831     {
832     case YPERR_SUCCESS:
833       str = N_("Success");
834       break;
835     case YPERR_BADARGS:
836       str = N_("Request arguments bad");
837       break;
838     case YPERR_RPC:
839       str = N_("RPC failure on NIS operation");
840       break;
841     case YPERR_DOMAIN:
842       str = N_("Can't bind to server which serves this domain");
843       break;
844     case YPERR_MAP:
845       str = N_("No such map in server's domain");
846       break;
847     case YPERR_KEY:
848       str = N_("No such key in map");
849       break;
850     case YPERR_YPERR:
851       str = N_("Internal NIS error");
852       break;
853     case YPERR_RESRC:
854       str = N_("Local resource allocation failure");
855       break;
856     case YPERR_NOMORE:
857       str = N_("No more records in map database");
858       break;
859     case YPERR_PMAP:
860       str = N_("Can't communicate with portmapper");
861       break;
862     case YPERR_YPBIND:
863       str = N_("Can't communicate with ypbind");
864       break;
865     case YPERR_YPSERV:
866       str = N_("Can't communicate with ypserv");
867       break;
868     case YPERR_NODOM:
869       str = N_("Local domain name not set");
870       break;
871     case YPERR_BADDB:
872       str = N_("NIS map database is bad");
873       break;
874     case YPERR_VERS:
875       str = N_("NIS client/server version mismatch - can't supply service");
876       break;
877     case YPERR_ACCESS:
878       str = N_("Permission denied");
879       break;
880     case YPERR_BUSY:
881       str = N_("Database is busy");
882       break;
883     default:
884       str = N_("Unknown NIS error code");
885       break;
886     }
887   return _(str);
888 }
889
890 static const int8_t yp_2_yperr[] =
891   {
892 #define YP2YPERR(yp, yperr)  [YP_##yp - YP_VERS] = YPERR_##yperr
893     YP2YPERR (TRUE, SUCCESS),
894     YP2YPERR (NOMORE, NOMORE),
895     YP2YPERR (FALSE, YPERR),
896     YP2YPERR (NOMAP, MAP),
897     YP2YPERR (NODOM, DOMAIN),
898     YP2YPERR (NOKEY, KEY),
899     YP2YPERR (BADOP, YPERR),
900     YP2YPERR (BADDB, BADDB),
901     YP2YPERR (YPERR, YPERR),
902     YP2YPERR (BADARGS, BADARGS),
903     YP2YPERR (VERS, VERS)
904   };
905 int
906 ypprot_err (const int code)
907 {
908   if (code < YP_VERS || code > YP_NOMORE)
909     return YPERR_YPERR;
910   return yp_2_yperr[code - YP_VERS];
911 }
912 libnsl_hidden_def (ypprot_err)
913
914 const char *
915 ypbinderr_string (const int error)
916 {
917   const char *str;
918   switch (error)
919     {
920     case 0:
921       str = N_("Success");
922       break;
923     case YPBIND_ERR_ERR:
924       str = N_("Internal ypbind error");
925       break;
926     case YPBIND_ERR_NOSERV:
927       str = N_("Domain not bound");
928       break;
929     case YPBIND_ERR_RESC:
930       str = N_("System resource allocation failure");
931       break;
932     default:
933       str = N_("Unknown ypbind error");
934       break;
935     }
936   return _(str);
937 }
938 libnsl_hidden_def (ypbinderr_string)
939
940 #define WINDOW 60
941
942 int
943 yp_update (char *domain, char *map, unsigned ypop,
944            char *key, int keylen, char *data, int datalen)
945 {
946   union
947     {
948       ypupdate_args update_args;
949       ypdelete_args delete_args;
950     }
951   args;
952   xdrproc_t xdr_argument;
953   unsigned res = 0;
954   CLIENT *clnt;
955   char *master;
956   struct sockaddr saddr;
957   char servername[MAXNETNAMELEN + 1];
958   int r;
959
960   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
961     return YPERR_BADARGS;
962
963   args.update_args.mapname = map;
964   args.update_args.key.yp_buf_len = keylen;
965   args.update_args.key.yp_buf_val = key;
966   args.update_args.datum.yp_buf_len = datalen;
967   args.update_args.datum.yp_buf_val = data;
968
969   if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
970     return r;
971
972   if (!host2netname (servername, master, domain))
973     {
974       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
975       free (master);
976       return YPERR_YPERR;
977     }
978
979   clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
980
981   /* We do not need the string anymore.  */
982   free (master);
983
984   if (clnt == NULL)
985     {
986       clnt_pcreateerror ("yp_update: clnt_create");
987       return YPERR_RPC;
988     }
989
990   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
991     {
992       fputs (_("yp_update: cannot get server address\n"), stderr);
993       return YPERR_RPC;
994     }
995
996   switch (ypop)
997     {
998     case YPOP_CHANGE:
999     case YPOP_INSERT:
1000     case YPOP_STORE:
1001       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
1002       break;
1003     case YPOP_DELETE:
1004       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
1005       break;
1006     default:
1007       return YPERR_BADARGS;
1008       break;
1009     }
1010
1011   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
1012
1013   if (clnt->cl_auth == NULL)
1014     clnt->cl_auth = authunix_create_default ();
1015
1016 again:
1017   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
1018                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
1019
1020   if (r == RPC_AUTHERROR)
1021     {
1022       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1023         {
1024           auth_destroy (clnt->cl_auth);
1025           clnt->cl_auth = authunix_create_default ();
1026           goto again;
1027         }
1028       else
1029         return YPERR_ACCESS;
1030     }
1031   if (r != RPC_SUCCESS)
1032     {
1033       clnt_perror (clnt, "yp_update: clnt_call");
1034       return YPERR_RPC;
1035     }
1036   return res;
1037 }