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