1/* Copyright (C) 1996-2017 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 <libc-lock.h>
32#include <shlib-compat.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
39struct 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 };
47typedef struct dom_binding dom_binding;
48
49static const struct timeval RPCTIMEOUT = {25, 0};
50static const struct timeval UDPTIMEOUT = {5, 0};
51static int const MAXTRIES = 2;
52static char ypdomainname[NIS_MAXNAMELEN + 1];
53__libc_lock_define_initialized (static, ypbindlist_lock)
54static dom_binding *ypbindlist = NULL;
55
56
57static void
58yp_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
80static void
81yp_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
102static int
103yp_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
152static int
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
210static void
211__yp_unbind (dom_binding *ydb)
212{
213 clnt_destroy (ydb->dom_client);
214 free (ydb);
215}
216
217int
218yp_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}
230libnsl_hidden_nolink_def (yp_bind, GLIBC_2_0)
231
232static void
233yp_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
259void
260yp_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}
270libnsl_hidden_nolink_def(yp_unbind, GLIBC_2_0)
271
272static 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
295static int
296do_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. */
366static int
367do_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 if (status == YPERR_SUCCESS)
372 /* We cast to ypresp_val although the pointer could also be of
373 type ypresp_key_val or ypresp_master or ypresp_order or
374 ypresp_maplist. But the stat element is in a common prefix so
375 this does not matter. */
376 status = ypprot_err (((struct ypresp_val *) resp)->stat);
377 return status;
378}
379
380
381__libc_lock_define_initialized (static, domainname_lock)
382
383int
384yp_get_default_domain (char **outdomain)
385{
386 int result = YPERR_SUCCESS;;
387 *outdomain = NULL;
388
389 __libc_lock_lock (domainname_lock);
390
391 if (ypdomainname[0] == '\0')
392 {
393 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
394 result = YPERR_NODOM;
395 else if (strcmp (ypdomainname, "(none)") == 0)
396 {
397 /* If domainname is not set, some systems will return "(none)" */
398 ypdomainname[0] = '\0';
399 result = YPERR_NODOM;
400 }
401 else
402 *outdomain = ypdomainname;
403 }
404 else
405 *outdomain = ypdomainname;
406
407 __libc_lock_unlock (domainname_lock);
408
409 return result;
410}
411libnsl_hidden_nolink_def (yp_get_default_domain, GLIBC_2_0)
412
413int
414__yp_check (char **domain)
415{
416 char *unused;
417
418 if (ypdomainname[0] == '\0')
419 if (yp_get_default_domain (&unused))
420 return 0;
421
422 if (domain)
423 *domain = ypdomainname;
424
425 if (yp_bind (ypdomainname) == 0)
426 return 1;
427 return 0;
428}
429libnsl_hidden_nolink_def(__yp_check, GLIBC_2_0)
430
431int
432yp_match (const char *indomain, const char *inmap, const char *inkey,
433 const int inkeylen, char **outval, int *outvallen)
434{
435 ypreq_key req;
436 ypresp_val resp;
437 enum clnt_stat result;
438
439 if (indomain == NULL || indomain[0] == '\0' ||
440 inmap == NULL || inmap[0] == '\0' ||
441 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
442 return YPERR_BADARGS;
443
444 req.domain = (char *) indomain;
445 req.map = (char *) inmap;
446 req.key.keydat_val = (char *) inkey;
447 req.key.keydat_len = inkeylen;
448
449 *outval = NULL;
450 *outvallen = 0;
451 memset (&resp, '\0', sizeof (resp));
452
453 result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
454 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
455 (caddr_t) &resp);
456
457 if (result != YPERR_SUCCESS)
458 return result;
459
460 *outvallen = resp.val.valdat_len;
461 *outval = malloc (*outvallen + 1);
462 int status = YPERR_RESRC;
463 if (__glibc_likely (*outval != NULL))
464 {
465 memcpy (*outval, resp.val.valdat_val, *outvallen);
466 (*outval)[*outvallen] = '\0';
467 status = YPERR_SUCCESS;
468 }
469
470 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
471
472 return status;
473}
474libnsl_hidden_nolink_def(yp_match, GLIBC_2_0)
475
476int
477yp_first (const char *indomain, const char *inmap, char **outkey,
478 int *outkeylen, char **outval, int *outvallen)
479{
480 ypreq_nokey req;
481 ypresp_key_val resp;
482 enum clnt_stat result;
483
484 if (indomain == NULL || indomain[0] == '\0' ||
485 inmap == NULL || inmap[0] == '\0')
486 return YPERR_BADARGS;
487
488 req.domain = (char *) indomain;
489 req.map = (char *) inmap;
490
491 *outkey = *outval = NULL;
492 *outkeylen = *outvallen = 0;
493 memset (&resp, '\0', sizeof (resp));
494
495 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
496 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
497 (caddr_t) &resp);
498
499 if (result != RPC_SUCCESS)
500 return YPERR_RPC;
501 if (resp.stat != YP_TRUE)
502 return ypprot_err (resp.stat);
503
504 int status;
505 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
506 && (*outval = malloc (resp.val.valdat_len
507 + 1)) != NULL, 1))
508 {
509 *outkeylen = resp.key.keydat_len;
510 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
511 (*outkey)[*outkeylen] = '\0';
512
513 *outvallen = resp.val.valdat_len;
514 memcpy (*outval, resp.val.valdat_val, *outvallen);
515 (*outval)[*outvallen] = '\0';
516
517 status = YPERR_SUCCESS;
518 }
519 else
520 {
521 free (*outkey);
522 status = YPERR_RESRC;
523 }
524
525 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
526
527 return status;
528}
529libnsl_hidden_nolink_def(yp_first, GLIBC_2_0)
530
531int
532yp_next (const char *indomain, const char *inmap, const char *inkey,
533 const int inkeylen, char **outkey, int *outkeylen, char **outval,
534 int *outvallen)
535{
536 ypreq_key req;
537 ypresp_key_val resp;
538 enum clnt_stat result;
539
540 if (indomain == NULL || indomain[0] == '\0' ||
541 inmap == NULL || inmap[0] == '\0' ||
542 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
543 return YPERR_BADARGS;
544
545 req.domain = (char *) indomain;
546 req.map = (char *) inmap;
547 req.key.keydat_val = (char *) inkey;
548 req.key.keydat_len = inkeylen;
549
550 *outkey = *outval = NULL;
551 *outkeylen = *outvallen = 0;
552 memset (&resp, '\0', sizeof (resp));
553
554 result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
555 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
556 (caddr_t) &resp);
557
558 if (result != YPERR_SUCCESS)
559 return result;
560
561 int status;
562 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
563 && (*outval = malloc (resp.val.valdat_len
564 + 1)) != NULL, 1))
565 {
566 *outkeylen = resp.key.keydat_len;
567 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
568 (*outkey)[*outkeylen] = '\0';
569
570 *outvallen = resp.val.valdat_len;
571 memcpy (*outval, resp.val.valdat_val, *outvallen);
572 (*outval)[*outvallen] = '\0';
573
574 status = YPERR_SUCCESS;
575 }
576 else
577 {
578 free (*outkey);
579 status = YPERR_RESRC;
580 }
581
582 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
583
584 return status;
585}
586libnsl_hidden_nolink_def(yp_next, GLIBC_2_0)
587
588int
589yp_master (const char *indomain, const char *inmap, char **outname)
590{
591 ypreq_nokey req;
592 ypresp_master resp;
593 enum clnt_stat result;
594
595 if (indomain == NULL || indomain[0] == '\0' ||
596 inmap == NULL || inmap[0] == '\0')
597 return YPERR_BADARGS;
598
599 req.domain = (char *) indomain;
600 req.map = (char *) inmap;
601
602 memset (&resp, '\0', sizeof (ypresp_master));
603
604 result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
605 (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
606 (caddr_t) &resp);
607
608 if (result != YPERR_SUCCESS)
609 return result;
610
611 *outname = strdup (resp.peer);
612 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
613
614 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
615}
616libnsl_hidden_nolink_def (yp_master, GLIBC_2_0)
617
618int
619yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
620{
621 struct ypreq_nokey req;
622 struct ypresp_order resp;
623 enum clnt_stat result;
624
625 if (indomain == NULL || indomain[0] == '\0' ||
626 inmap == NULL || inmap[0] == '\0')
627 return YPERR_BADARGS;
628
629 req.domain = (char *) indomain;
630 req.map = (char *) inmap;
631
632 memset (&resp, '\0', sizeof (resp));
633
634 result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
635 (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
636 (caddr_t) &resp);
637
638 if (result != YPERR_SUCCESS)
639 return result;
640
641 *outorder = resp.ordernum;
642 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
643
644 return result;
645}
646libnsl_hidden_nolink_def(yp_order, GLIBC_2_0)
647
648struct ypresp_all_data
649{
650 unsigned long status;
651 void *data;
652 int (*foreach) (int status, char *key, int keylen,
653 char *val, int vallen, char *data);
654};
655
656static bool_t
657__xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
658{
659 while (1)
660 {
661 struct ypresp_all resp;
662
663 memset (&resp, '\0', sizeof (struct ypresp_all));
664 if (!xdr_ypresp_all (xdrs, &resp))
665 {
666 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
667 objp->status = YP_YPERR;
668 return FALSE;
669 }
670 if (resp.more == 0)
671 {
672 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
673 objp->status = YP_NOMORE;
674 return TRUE;
675 }
676
677 switch (resp.ypresp_all_u.val.stat)
678 {
679 case YP_TRUE:
680 {
681 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
682 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
683 int keylen = resp.ypresp_all_u.val.key.keydat_len;
684 int vallen = resp.ypresp_all_u.val.val.valdat_len;
685
686 /* We are not allowed to modify the key and val data.
687 But we are allowed to add data behind the buffer,
688 if we don't modify the length. So add an extra NUL
689 character to avoid trouble with broken code. */
690 objp->status = YP_TRUE;
691 *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
692 keylen)) = '\0';
693 *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
694 vallen)) = '\0';
695 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
696 if ((*objp->foreach) (objp->status, key, keylen,
697 val, vallen, objp->data))
698 return TRUE;
699 }
700 break;
701 default:
702 objp->status = resp.ypresp_all_u.val.stat;
703 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
704 /* Sun says we don't need to make this call, but must return
705 immediately. Since Solaris makes this call, we will call
706 the callback function, too. */
707 (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
708 return TRUE;
709 }
710 }
711}
712
713int
714yp_all (const char *indomain, const char *inmap,
715 const struct ypall_callback *incallback)
716{
717 struct ypreq_nokey req;
718 dom_binding *ydb = NULL;
719 int try, res;
720 enum clnt_stat result;
721 struct sockaddr_in clnt_sin;
722 CLIENT *clnt;
723 struct ypresp_all_data data;
724 int clnt_sock;
725 int saved_errno = errno;
726
727 if (indomain == NULL || indomain[0] == '\0'
728 || inmap == NULL || inmap[0] == '\0')
729 return YPERR_BADARGS;
730
731 try = 0;
732 res = YPERR_YPERR;
733
734 while (try < MAXTRIES && res != YPERR_SUCCESS)
735 {
736 if (__yp_bind (indomain, &ydb) != 0)
737 {
738 __set_errno (saved_errno);
739 return YPERR_DOMAIN;
740 }
741
742 clnt_sock = RPC_ANYSOCK;
743 clnt_sin = ydb->dom_server_addr;
744 clnt_sin.sin_port = 0;
745
746 /* We don't need the UDP connection anymore. */
747 __yp_unbind (ydb);
748 ydb = NULL;
749
750 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
751 if (clnt == NULL)
752 {
753 __set_errno (saved_errno);
754 return YPERR_PMAP;
755 }
756 req.domain = (char *) indomain;
757 req.map = (char *) inmap;
758
759 data.foreach = incallback->foreach;
760 data.data = (void *) incallback->data;
761
762 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
763 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
764 (caddr_t) &data, RPCTIMEOUT);
765
766 if (__glibc_unlikely (result != RPC_SUCCESS))
767 {
768 /* Print the error message only on the last try. */
769 if (try == MAXTRIES - 1)
770 clnt_perror (clnt, "yp_all: clnt_call");
771 res = YPERR_RPC;
772 }
773 else
774 res = YPERR_SUCCESS;
775
776 clnt_destroy (clnt);
777
778 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
779 {
780 __set_errno (saved_errno);
781 return ypprot_err (data.status);
782 }
783 ++try;
784 }
785
786 __set_errno (saved_errno);
787
788 return res;
789}
790libnsl_hidden_nolink_def (yp_all, GLIBC_2_0)
791
792int
793yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
794{
795 struct ypresp_maplist resp;
796 enum clnt_stat result;
797
798 if (indomain == NULL || indomain[0] == '\0')
799 return YPERR_BADARGS;
800
801 memset (&resp, '\0', sizeof (resp));
802
803 result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
804 (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
805 (caddr_t) &resp);
806
807 if (__glibc_likely (result == YPERR_SUCCESS))
808 {
809 *outmaplist = resp.maps;
810 /* We don't free the list, this will be done by ypserv
811 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
812 }
813
814 return result;
815}
816
817const char *
818yperr_string (const int error)
819{
820 const char *str;
821 switch (error)
822 {
823 case YPERR_SUCCESS:
824 str = N_("Success");
825 break;
826 case YPERR_BADARGS:
827 str = N_("Request arguments bad");
828 break;
829 case YPERR_RPC:
830 str = N_("RPC failure on NIS operation");
831 break;
832 case YPERR_DOMAIN:
833 str = N_("Can't bind to server which serves this domain");
834 break;
835 case YPERR_MAP:
836 str = N_("No such map in server's domain");
837 break;
838 case YPERR_KEY:
839 str = N_("No such key in map");
840 break;
841 case YPERR_YPERR:
842 str = N_("Internal NIS error");
843 break;
844 case YPERR_RESRC:
845 str = N_("Local resource allocation failure");
846 break;
847 case YPERR_NOMORE:
848 str = N_("No more records in map database");
849 break;
850 case YPERR_PMAP:
851 str = N_("Can't communicate with portmapper");
852 break;
853 case YPERR_YPBIND:
854 str = N_("Can't communicate with ypbind");
855 break;
856 case YPERR_YPSERV:
857 str = N_("Can't communicate with ypserv");
858 break;
859 case YPERR_NODOM:
860 str = N_("Local domain name not set");
861 break;
862 case YPERR_BADDB:
863 str = N_("NIS map database is bad");
864 break;
865 case YPERR_VERS:
866 str = N_("NIS client/server version mismatch - can't supply service");
867 break;
868 case YPERR_ACCESS:
869 str = N_("Permission denied");
870 break;
871 case YPERR_BUSY:
872 str = N_("Database is busy");
873 break;
874 default:
875 str = N_("Unknown NIS error code");
876 break;
877 }
878 return _(str);
879}
880libnsl_hidden_nolink_def(yperr_string, GLIBC_2_0)
881
882static const int8_t yp_2_yperr[] =
883 {
884#define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
885 YP2YPERR (TRUE, SUCCESS),
886 YP2YPERR (NOMORE, NOMORE),
887 YP2YPERR (FALSE, YPERR),
888 YP2YPERR (NOMAP, MAP),
889 YP2YPERR (NODOM, DOMAIN),
890 YP2YPERR (NOKEY, KEY),
891 YP2YPERR (BADOP, YPERR),
892 YP2YPERR (BADDB, BADDB),
893 YP2YPERR (YPERR, YPERR),
894 YP2YPERR (BADARGS, BADARGS),
895 YP2YPERR (VERS, VERS)
896 };
897int
898ypprot_err (const int code)
899{
900 if (code < YP_VERS || code > YP_NOMORE)
901 return YPERR_YPERR;
902 return yp_2_yperr[code - YP_VERS];
903}
904libnsl_hidden_nolink_def (ypprot_err, GLIBC_2_0)
905
906const char *
907ypbinderr_string (const int error)
908{
909 const char *str;
910 switch (error)
911 {
912 case 0:
913 str = N_("Success");
914 break;
915 case YPBIND_ERR_ERR:
916 str = N_("Internal ypbind error");
917 break;
918 case YPBIND_ERR_NOSERV:
919 str = N_("Domain not bound");
920 break;
921 case YPBIND_ERR_RESC:
922 str = N_("System resource allocation failure");
923 break;
924 default:
925 str = N_("Unknown ypbind error");
926 break;
927 }
928 return _(str);
929}
930libnsl_hidden_nolink_def (ypbinderr_string, GLIBC_2_0)
931
932#define WINDOW 60
933
934int
935yp_update (char *domain, char *map, unsigned ypop,
936 char *key, int keylen, char *data, int datalen)
937{
938 union
939 {
940 ypupdate_args update_args;
941 ypdelete_args delete_args;
942 }
943 args;
944 xdrproc_t xdr_argument;
945 unsigned res = 0;
946 CLIENT *clnt;
947 char *master;
948 struct sockaddr saddr;
949 char servername[MAXNETNAMELEN + 1];
950 int r;
951
952 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
953 return YPERR_BADARGS;
954
955 args.update_args.mapname = map;
956 args.update_args.key.yp_buf_len = keylen;
957 args.update_args.key.yp_buf_val = key;
958 args.update_args.datum.yp_buf_len = datalen;
959 args.update_args.datum.yp_buf_val = data;
960
961 if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
962 return r;
963
964 if (!host2netname (servername, master, domain))
965 {
966 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
967 free (master);
968 return YPERR_YPERR;
969 }
970
971 clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
972
973 /* We do not need the string anymore. */
974 free (master);
975
976 if (clnt == NULL)
977 {
978 clnt_pcreateerror ("yp_update: clnt_create");
979 return YPERR_RPC;
980 }
981
982 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
983 {
984 fputs (_("yp_update: cannot get server address\n"), stderr);
985 return YPERR_RPC;
986 }
987
988 switch (ypop)
989 {
990 case YPOP_CHANGE:
991 case YPOP_INSERT:
992 case YPOP_STORE:
993 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
994 break;
995 case YPOP_DELETE:
996 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
997 break;
998 default:
999 return YPERR_BADARGS;
1000 break;
1001 }
1002
1003 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
1004
1005 if (clnt->cl_auth == NULL)
1006 clnt->cl_auth = authunix_create_default ();
1007
1008again:
1009 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
1010 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
1011
1012 if (r == RPC_AUTHERROR)
1013 {
1014 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1015 {
1016 auth_destroy (clnt->cl_auth);
1017 clnt->cl_auth = authunix_create_default ();
1018 goto again;
1019 }
1020 else
1021 return YPERR_ACCESS;
1022 }
1023 if (r != RPC_SUCCESS)
1024 {
1025 clnt_perror (clnt, "yp_update: clnt_call");
1026 return YPERR_RPC;
1027 }
1028 return res;
1029}
1030libnsl_hidden_nolink_def(yp_update, GLIBC_2_0)
1031