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