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