1 /* Copyright (C) 1996-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <libintl.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/socket.h>
29 #include <sys/uio.h>
30 #include <libc-lock.h>
31 #include <shlib-compat.h>
32 #include <libc-diag.h>
33 
34 /* This should only be defined on systems with a BSD compatible ypbind */
35 #ifndef BINDINGDIR
36 # define BINDINGDIR "/var/yp/binding"
37 #endif
38 
39 struct dom_binding
40   {
41     struct dom_binding *dom_pnext;
42     char dom_domain[YPMAXDOMAIN + 1];
43     struct sockaddr_in dom_server_addr;
44     int dom_socket;
45     CLIENT *dom_client;
46   };
47 typedef struct dom_binding dom_binding;
48 
49 static const struct timeval RPCTIMEOUT = {25, 0};
50 static const struct timeval UDPTIMEOUT = {5, 0};
51 static int const MAXTRIES = 2;
52 static char ypdomainname[NIS_MAXNAMELEN + 1];
53 __libc_lock_define_initialized (static, ypbindlist_lock)
54 static dom_binding *ypbindlist = NULL;
55 
56 
57 static void
yp_bind_client_create(const char * domain,dom_binding * ysd,struct ypbind_resp * ypbr)58 yp_bind_client_create (const char *domain, dom_binding *ysd,
59 		       struct ypbind_resp *ypbr)
60 {
61   ysd->dom_server_addr.sin_family = AF_INET;
62   memcpy (&ysd->dom_server_addr.sin_port,
63 	  ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
64 	  sizeof (ysd->dom_server_addr.sin_port));
65   memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
66 	  ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
67 	  sizeof (ysd->dom_server_addr.sin_addr.s_addr));
68   strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
69   ysd->dom_domain[YPMAXDOMAIN] = '\0';
70 
71   ysd->dom_socket = RPC_ANYSOCK;
72   ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
73 					      YPVERS, UDPTIMEOUT,
74 					      &ysd->dom_socket,
75 					      UDPMSGSIZE, UDPMSGSIZE,
76 					      SOCK_CLOEXEC);
77 }
78 
79 #if USE_BINDINGDIR
80 static void
yp_bind_file(const char * domain,dom_binding * ysd)81 yp_bind_file (const char *domain, dom_binding *ysd)
82 {
83   char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
84 
85   snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
86   int fd = open (path, O_RDONLY);
87   if (fd >= 0)
88     {
89       /* We have a binding file and could save a RPC call.  The file
90 	 contains a port number and the YPBIND_RESP record.  The port
91 	 number (16 bits) can be ignored.  */
92       struct ypbind_resp ypbr;
93 
94       if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
95 	yp_bind_client_create (domain, ysd, &ypbr);
96 
97       close (fd);
98     }
99 }
100 #endif
101 
102 static int
yp_bind_ypbindprog(const char * domain,dom_binding * ysd)103 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
104 {
105   struct sockaddr_in clnt_saddr;
106   struct ypbind_resp ypbr;
107   int clnt_sock;
108   CLIENT *client;
109 
110   clnt_saddr.sin_family = AF_INET;
111   clnt_saddr.sin_port = 0;
112   clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
113   clnt_sock = RPC_ANYSOCK;
114   client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
115 			   &clnt_sock, 0, 0);
116   if (client == NULL)
117     return YPERR_YPBIND;
118 
119   /* Check the port number -- should be < IPPORT_RESERVED.
120      If not, it's possible someone has registered a bogus
121      ypbind with the portmapper and is trying to trick us. */
122   if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
123     {
124       clnt_destroy (client);
125       return YPERR_YPBIND;
126     }
127 
128   if (clnt_call (client, YPBINDPROC_DOMAIN,
129 		 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
130 		 (xdrproc_t) xdr_ypbind_resp,
131 		 (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
132     {
133       clnt_destroy (client);
134       return YPERR_YPBIND;
135     }
136 
137   clnt_destroy (client);
138 
139   if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
140     {
141       fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
142 	       ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
143       return YPERR_DOMAIN;
144     }
145   memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
146 
147   yp_bind_client_create (domain, ysd, &ypbr);
148 
149   return YPERR_SUCCESS;
150 }
151 
152 static int
__yp_bind(const char * domain,dom_binding ** ypdb)153 __yp_bind (const char *domain, dom_binding **ypdb)
154 {
155   dom_binding *ysd = NULL;
156   int is_new = 0;
157 
158   if (domain == NULL || domain[0] == '\0')
159     return YPERR_BADARGS;
160 
161   ysd = *ypdb;
162   while (ysd != NULL)
163     {
164       if (strcmp (domain, ysd->dom_domain) == 0)
165 	break;
166       ysd = ysd->dom_pnext;
167     }
168 
169   if (ysd == NULL)
170     {
171       is_new = 1;
172       ysd = (dom_binding *) calloc (1, sizeof *ysd);
173       if (__glibc_unlikely (ysd == NULL))
174 	return YPERR_RESRC;
175     }
176 
177 #if USE_BINDINGDIR
178   /* Try binding dir at first if we have no binding */
179   if (ysd->dom_client == NULL)
180     yp_bind_file (domain, ysd);
181 #endif /* USE_BINDINGDIR */
182 
183   if (ysd->dom_client == NULL)
184     {
185       int retval = yp_bind_ypbindprog (domain, ysd);
186       if (retval != YPERR_SUCCESS)
187 	{
188 	  if (is_new)
189 	    free (ysd);
190 	  return retval;
191 	}
192     }
193 
194   if (ysd->dom_client == NULL)
195     {
196       if (is_new)
197 	free (ysd);
198       return YPERR_YPSERV;
199     }
200 
201   if (is_new)
202     {
203       ysd->dom_pnext = *ypdb;
204       *ypdb = ysd;
205     }
206 
207   return YPERR_SUCCESS;
208 }
209 
210 static void
__yp_unbind(dom_binding * ydb)211 __yp_unbind (dom_binding *ydb)
212 {
213   clnt_destroy (ydb->dom_client);
214   free (ydb);
215 }
216 
217 int
yp_bind(const char * indomain)218 yp_bind (const char *indomain)
219 {
220   int status;
221 
222   __libc_lock_lock (ypbindlist_lock);
223 
224   status = __yp_bind (indomain, &ypbindlist);
225 
226   __libc_lock_unlock (ypbindlist_lock);
227 
228   return status;
229 }
libnsl_hidden_nolink_def(yp_bind,GLIBC_2_0)230 libnsl_hidden_nolink_def (yp_bind, GLIBC_2_0)
231 
232 static void
233 yp_unbind_locked (const char *indomain)
234 {
235   dom_binding *ydbptr, *ydbptr2;
236 
237   ydbptr2 = NULL;
238   ydbptr = ypbindlist;
239 
240   while (ydbptr != NULL)
241     {
242       if (strcmp (ydbptr->dom_domain, indomain) == 0)
243 	{
244 	  dom_binding *work;
245 
246 	  work = ydbptr;
247 	  if (ydbptr2 == NULL)
248 	    ypbindlist = ypbindlist->dom_pnext;
249 	  else
250 	    ydbptr2 = ydbptr->dom_pnext;
251 	  __yp_unbind (work);
252 	  break;
253 	}
254       ydbptr2 = ydbptr;
255       ydbptr = ydbptr->dom_pnext;
256     }
257 }
258 
259 void
yp_unbind(const char * indomain)260 yp_unbind (const char *indomain)
261 {
262   __libc_lock_lock (ypbindlist_lock);
263 
264   yp_unbind_locked (indomain);
265 
266   __libc_lock_unlock (ypbindlist_lock);
267 
268   return;
269 }
libnsl_hidden_nolink_def(yp_unbind,GLIBC_2_0)270 libnsl_hidden_nolink_def(yp_unbind, GLIBC_2_0)
271 
272 static int
273 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
274 	       caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
275 	       int print_error)
276 {
277   enum clnt_stat result;
278 
279   result = clnt_call ((*ydb)->dom_client, prog,
280 		      xargs, req, xres, resp, RPCTIMEOUT);
281 
282   if (result != RPC_SUCCESS)
283     {
284       /* We don't print an error message, if we try our old,
285 	 cached data. Only print this for data, which should work.  */
286       if (print_error)
287 	clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
288 
289       return YPERR_RPC;
290     }
291 
292   return YPERR_SUCCESS;
293 }
294 
295 static int
do_ypcall(const char * domain,u_long prog,xdrproc_t xargs,caddr_t req,xdrproc_t xres,caddr_t resp)296 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
297 	   caddr_t req, xdrproc_t xres, caddr_t resp)
298 {
299   dom_binding *ydb;
300   int status;
301   int saved_errno = errno;
302 
303   status = YPERR_YPERR;
304 
305   __libc_lock_lock (ypbindlist_lock);
306   ydb = ypbindlist;
307   while (ydb != NULL)
308     {
309       if (strcmp (domain, ydb->dom_domain) == 0)
310 	{
311           if (__yp_bind (domain, &ydb) == 0)
312 	    {
313 	      /* Call server, print no error message, do not unbind.  */
314 	      status = __ypclnt_call (domain, prog, xargs, req, xres,
315 				      resp, &ydb, 0);
316 	      if (status == YPERR_SUCCESS)
317 	        {
318 		  __libc_lock_unlock (ypbindlist_lock);
319 	          __set_errno (saved_errno);
320 	          return status;
321 	        }
322 	    }
323 	  /* We use ypbindlist, and the old cached data is
324 	     invalid. unbind now and create a new binding */
325 	  yp_unbind_locked (domain);
326 
327 	  break;
328 	}
329       ydb = ydb->dom_pnext;
330     }
331   __libc_lock_unlock (ypbindlist_lock);
332 
333   /* First try with cached data failed. Now try to get
334      current data from the system.  */
335   ydb = NULL;
336   if (__yp_bind (domain, &ydb) == 0)
337     {
338       status = __ypclnt_call (domain, prog, xargs, req, xres,
339 			      resp, &ydb, 1);
340       __yp_unbind (ydb);
341     }
342 
343 #if USE_BINDINGDIR
344   /* If we support binding dir data, we have a third chance:
345      Ask ypbind.  */
346   if (status != YPERR_SUCCESS)
347     {
348       ydb = calloc (1, sizeof (dom_binding));
349       if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
350 	{
351 	  status = __ypclnt_call (domain, prog, xargs, req, xres,
352 				  resp, &ydb, 1);
353 	  __yp_unbind (ydb);
354 	}
355       else
356 	free (ydb);
357     }
358 #endif
359 
360   __set_errno (saved_errno);
361 
362   return status;
363 }
364 
365 /* Like do_ypcall, but translate the status value if necessary.  */
366 static int
do_ypcall_tr(const char * domain,u_long prog,xdrproc_t xargs,caddr_t req,xdrproc_t xres,caddr_t resp)367 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
368 	      caddr_t req, xdrproc_t xres, caddr_t resp)
369 {
370   int status = do_ypcall (domain, prog, xargs, req, xres, resp);
371   DIAG_PUSH_NEEDS_COMMENT;
372   /* This cast results in a warning that a ypresp_val is partly
373      outside the bounds of the actual object referenced, but as
374      explained below only the stat element (in a common prefix) is
375      accessed.  */
376   DIAG_IGNORE_NEEDS_COMMENT (11, "-Warray-bounds");
377   if (status == YPERR_SUCCESS)
378     /* We cast to ypresp_val although the pointer could also be of
379        type ypresp_key_val or ypresp_master or ypresp_order or
380        ypresp_maplist.  But the stat element is in a common prefix so
381        this does not matter.  */
382     status = ypprot_err (((struct ypresp_val *) resp)->stat);
383   DIAG_POP_NEEDS_COMMENT;
384   return status;
385 }
386 
387 
__libc_lock_define_initialized(static,domainname_lock)388 __libc_lock_define_initialized (static, domainname_lock)
389 
390 int
391 yp_get_default_domain (char **outdomain)
392 {
393   int result = YPERR_SUCCESS;;
394   *outdomain = NULL;
395 
396   __libc_lock_lock (domainname_lock);
397 
398   if (ypdomainname[0] == '\0')
399     {
400       if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
401 	result = YPERR_NODOM;
402       else if (strcmp (ypdomainname, "(none)") == 0)
403 	{
404 	  /* If domainname is not set, some systems will return "(none)" */
405 	  ypdomainname[0] = '\0';
406 	  result = YPERR_NODOM;
407 	}
408       else
409 	*outdomain = ypdomainname;
410     }
411   else
412     *outdomain = ypdomainname;
413 
414   __libc_lock_unlock (domainname_lock);
415 
416   return result;
417 }
libnsl_hidden_nolink_def(yp_get_default_domain,GLIBC_2_0)418 libnsl_hidden_nolink_def (yp_get_default_domain, GLIBC_2_0)
419 
420 int
421 __yp_check (char **domain)
422 {
423   char *unused;
424 
425   if (ypdomainname[0] == '\0')
426     if (yp_get_default_domain (&unused))
427       return 0;
428 
429   if (domain)
430     *domain = ypdomainname;
431 
432   if (yp_bind (ypdomainname) == 0)
433     return 1;
434   return 0;
435 }
libnsl_hidden_nolink_def(__yp_check,GLIBC_2_0)436 libnsl_hidden_nolink_def(__yp_check, GLIBC_2_0)
437 
438 int
439 yp_match (const char *indomain, const char *inmap, const char *inkey,
440 	  const int inkeylen, char **outval, int *outvallen)
441 {
442   ypreq_key req;
443   ypresp_val resp;
444   enum clnt_stat result;
445 
446   if (indomain == NULL || indomain[0] == '\0'
447       || inmap == NULL || inmap[0] == '\0'
448       || inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
449     return YPERR_BADARGS;
450 
451   req.domain = (char *) indomain;
452   req.map = (char *) inmap;
453   req.key.keydat_val = (char *) inkey;
454   req.key.keydat_len = inkeylen;
455 
456   *outval = NULL;
457   *outvallen = 0;
458   memset (&resp, '\0', sizeof (resp));
459 
460   result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
461 			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
462 			 (caddr_t) &resp);
463 
464   if (result != YPERR_SUCCESS)
465     return result;
466 
467   *outvallen = resp.val.valdat_len;
468   *outval = malloc (*outvallen + 1);
469   int status = YPERR_RESRC;
470   if (__glibc_likely (*outval != NULL))
471     {
472       memcpy (*outval, resp.val.valdat_val, *outvallen);
473       (*outval)[*outvallen] = '\0';
474       status = YPERR_SUCCESS;
475     }
476 
477   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
478 
479   return status;
480 }
libnsl_hidden_nolink_def(yp_match,GLIBC_2_0)481 libnsl_hidden_nolink_def(yp_match, GLIBC_2_0)
482 
483 int
484 yp_first (const char *indomain, const char *inmap, char **outkey,
485 	  int *outkeylen, char **outval, int *outvallen)
486 {
487   ypreq_nokey req;
488   ypresp_key_val resp;
489   enum clnt_stat result;
490 
491   if (indomain == NULL || indomain[0] == '\0'
492       || inmap == NULL || inmap[0] == '\0')
493     return YPERR_BADARGS;
494 
495   req.domain = (char *) indomain;
496   req.map = (char *) inmap;
497 
498   *outkey = *outval = NULL;
499   *outkeylen = *outvallen = 0;
500   memset (&resp, '\0', sizeof (resp));
501 
502   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
503 		      (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
504 		      (caddr_t) &resp);
505 
506   if (result != RPC_SUCCESS)
507     return YPERR_RPC;
508   if (resp.stat != YP_TRUE)
509     return ypprot_err (resp.stat);
510 
511   int status;
512   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
513 			&& (*outval = malloc (resp.val.valdat_len
514 					      + 1)) != NULL, 1))
515     {
516       *outkeylen = resp.key.keydat_len;
517       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
518       (*outkey)[*outkeylen] = '\0';
519 
520       *outvallen = resp.val.valdat_len;
521       memcpy (*outval, resp.val.valdat_val, *outvallen);
522       (*outval)[*outvallen] = '\0';
523 
524       status = YPERR_SUCCESS;
525     }
526   else
527     {
528       free (*outkey);
529       status = YPERR_RESRC;
530     }
531 
532   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
533 
534   return status;
535 }
libnsl_hidden_nolink_def(yp_first,GLIBC_2_0)536 libnsl_hidden_nolink_def(yp_first, GLIBC_2_0)
537 
538 int
539 yp_next (const char *indomain, const char *inmap, const char *inkey,
540 	 const int inkeylen, char **outkey, int *outkeylen, char **outval,
541 	 int *outvallen)
542 {
543   ypreq_key req;
544   ypresp_key_val resp;
545   enum clnt_stat result;
546 
547   if (indomain == NULL || indomain[0] == '\0'
548       || inmap == NULL || inmap[0] == '\0'
549       || inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
550     return YPERR_BADARGS;
551 
552   req.domain = (char *) indomain;
553   req.map = (char *) inmap;
554   req.key.keydat_val = (char *) inkey;
555   req.key.keydat_len = inkeylen;
556 
557   *outkey = *outval = NULL;
558   *outkeylen = *outvallen = 0;
559   memset (&resp, '\0', sizeof (resp));
560 
561   result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
562 			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
563 			 (caddr_t) &resp);
564 
565   if (result != YPERR_SUCCESS)
566     return result;
567 
568   int status;
569   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
570 			&& (*outval = malloc (resp.val.valdat_len
571 					      + 1)) != NULL, 1))
572     {
573       *outkeylen = resp.key.keydat_len;
574       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
575       (*outkey)[*outkeylen] = '\0';
576 
577       *outvallen = resp.val.valdat_len;
578       memcpy (*outval, resp.val.valdat_val, *outvallen);
579       (*outval)[*outvallen] = '\0';
580 
581       status = YPERR_SUCCESS;
582     }
583   else
584     {
585       free (*outkey);
586       status = YPERR_RESRC;
587     }
588 
589   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
590 
591   return status;
592 }
libnsl_hidden_nolink_def(yp_next,GLIBC_2_0)593 libnsl_hidden_nolink_def(yp_next, GLIBC_2_0)
594 
595 int
596 yp_master (const char *indomain, const char *inmap, char **outname)
597 {
598   ypreq_nokey req;
599   ypresp_master resp;
600   enum clnt_stat result;
601 
602   if (indomain == NULL || indomain[0] == '\0'
603       || inmap == NULL || inmap[0] == '\0')
604     return YPERR_BADARGS;
605 
606   req.domain = (char *) indomain;
607   req.map = (char *) inmap;
608 
609   memset (&resp, '\0', sizeof (ypresp_master));
610 
611   result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
612 			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
613 			 (caddr_t) &resp);
614 
615   if (result != YPERR_SUCCESS)
616     return result;
617 
618   *outname = strdup (resp.peer);
619   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
620 
621   return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
622 }
libnsl_hidden_nolink_def(yp_master,GLIBC_2_0)623 libnsl_hidden_nolink_def (yp_master, GLIBC_2_0)
624 
625 int
626 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
627 {
628   struct ypreq_nokey req;
629   struct ypresp_order resp;
630   enum clnt_stat result;
631 
632   if (indomain == NULL || indomain[0] == '\0'
633       || inmap == NULL || inmap[0] == '\0')
634     return YPERR_BADARGS;
635 
636   req.domain = (char *) indomain;
637   req.map = (char *) inmap;
638 
639   memset (&resp, '\0', sizeof (resp));
640 
641   result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
642 			 (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
643 			 (caddr_t) &resp);
644 
645   if (result != YPERR_SUCCESS)
646     return result;
647 
648   *outorder = resp.ordernum;
649   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
650 
651   return result;
652 }
653 libnsl_hidden_nolink_def(yp_order, GLIBC_2_0)
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
__xdr_ypresp_all(XDR * xdrs,struct ypresp_all_data * objp)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
yp_all(const char * indomain,const char * inmap,const struct ypall_callback * incallback)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 (__glibc_unlikely (result != RPC_SUCCESS))
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 }
libnsl_hidden_nolink_def(yp_all,GLIBC_2_0)797 libnsl_hidden_nolink_def (yp_all, GLIBC_2_0)
798 
799 int
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 (__glibc_likely (result == YPERR_SUCCESS))
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 }
libnsl_hidden_nolink_def(yp_maplist,GLIBC_2_0)823 libnsl_hidden_nolink_def (yp_maplist, GLIBC_2_0)
824 
825 const char *
826 yperr_string (const int error)
827 {
828   const char *str;
829   switch (error)
830     {
831     case YPERR_SUCCESS:
832       str = N_("Success");
833       break;
834     case YPERR_BADARGS:
835       str = N_("Request arguments bad");
836       break;
837     case YPERR_RPC:
838       str = N_("RPC failure on NIS operation");
839       break;
840     case YPERR_DOMAIN:
841       str = N_("Can't bind to server which serves this domain");
842       break;
843     case YPERR_MAP:
844       str = N_("No such map in server's domain");
845       break;
846     case YPERR_KEY:
847       str = N_("No such key in map");
848       break;
849     case YPERR_YPERR:
850       str = N_("Internal NIS error");
851       break;
852     case YPERR_RESRC:
853       str = N_("Local resource allocation failure");
854       break;
855     case YPERR_NOMORE:
856       str = N_("No more records in map database");
857       break;
858     case YPERR_PMAP:
859       str = N_("Can't communicate with portmapper");
860       break;
861     case YPERR_YPBIND:
862       str = N_("Can't communicate with ypbind");
863       break;
864     case YPERR_YPSERV:
865       str = N_("Can't communicate with ypserv");
866       break;
867     case YPERR_NODOM:
868       str = N_("Local domain name not set");
869       break;
870     case YPERR_BADDB:
871       str = N_("NIS map database is bad");
872       break;
873     case YPERR_VERS:
874       str = N_("NIS client/server version mismatch - can't supply service");
875       break;
876     case YPERR_ACCESS:
877       str = N_("Permission denied");
878       break;
879     case YPERR_BUSY:
880       str = N_("Database is busy");
881       break;
882     default:
883       str = N_("Unknown NIS error code");
884       break;
885     }
886   return _(str);
887 }
888 libnsl_hidden_nolink_def(yperr_string, GLIBC_2_0)
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
ypprot_err(const int code)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 }
libnsl_hidden_nolink_def(ypprot_err,GLIBC_2_0)912 libnsl_hidden_nolink_def (ypprot_err, GLIBC_2_0)
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 }
libnsl_hidden_nolink_def(ypbinderr_string,GLIBC_2_0)938 libnsl_hidden_nolink_def (ypbinderr_string, GLIBC_2_0)
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 }
1038 libnsl_hidden_nolink_def(yp_update, GLIBC_2_0)
1039