manual: Clarify undefined behavior of feenableexcept (BZ 31019)
[glibc.git] / nis / ypclnt.c
blob19a53a1054621ad3c8531cb32cd0c7b97c1530e3
1 /* Copyright (C) 1996-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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/>. */
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>
34 /* This should only be defined on systems with a BSD compatible ypbind */
35 #ifndef BINDINGDIR
36 # define BINDINGDIR "/var/yp/binding"
37 #endif
39 struct dom_binding
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;
47 typedef struct dom_binding dom_binding;
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;
57 static void
58 yp_bind_client_create (const char *domain, dom_binding *ysd,
59 struct ypbind_resp *ypbr)
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';
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);
79 #if USE_BINDINGDIR
80 static void
81 yp_bind_file (const char *domain, dom_binding *ysd)
83 char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
85 snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
86 int fd = open (path, O_RDONLY);
87 if (fd >= 0)
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;
94 if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
95 yp_bind_client_create (domain, ysd, &ypbr);
97 close (fd);
100 #endif
102 static int
103 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
105 struct sockaddr_in clnt_saddr;
106 struct ypbind_resp ypbr;
107 int clnt_sock;
108 CLIENT *client;
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;
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)
124 clnt_destroy (client);
125 return YPERR_YPBIND;
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)
133 clnt_destroy (client);
134 return YPERR_YPBIND;
137 clnt_destroy (client);
139 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
141 fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
142 ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
143 return YPERR_DOMAIN;
145 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
147 yp_bind_client_create (domain, ysd, &ypbr);
149 return YPERR_SUCCESS;
152 static int
153 __yp_bind (const char *domain, dom_binding **ypdb)
155 dom_binding *ysd = NULL;
156 int is_new = 0;
158 if (domain == NULL || domain[0] == '\0')
159 return YPERR_BADARGS;
161 ysd = *ypdb;
162 while (ysd != NULL)
164 if (strcmp (domain, ysd->dom_domain) == 0)
165 break;
166 ysd = ysd->dom_pnext;
169 if (ysd == NULL)
171 is_new = 1;
172 ysd = (dom_binding *) calloc (1, sizeof *ysd);
173 if (__glibc_unlikely (ysd == NULL))
174 return YPERR_RESRC;
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 */
183 if (ysd->dom_client == NULL)
185 int retval = yp_bind_ypbindprog (domain, ysd);
186 if (retval != YPERR_SUCCESS)
188 if (is_new)
189 free (ysd);
190 return retval;
194 if (ysd->dom_client == NULL)
196 if (is_new)
197 free (ysd);
198 return YPERR_YPSERV;
201 if (is_new)
203 ysd->dom_pnext = *ypdb;
204 *ypdb = ysd;
207 return YPERR_SUCCESS;
210 static void
211 __yp_unbind (dom_binding *ydb)
213 clnt_destroy (ydb->dom_client);
214 free (ydb);
218 yp_bind (const char *indomain)
220 int status;
222 __libc_lock_lock (ypbindlist_lock);
224 status = __yp_bind (indomain, &ypbindlist);
226 __libc_lock_unlock (ypbindlist_lock);
228 return status;
230 libnsl_hidden_nolink_def (yp_bind, GLIBC_2_0)
232 static void
233 yp_unbind_locked (const char *indomain)
235 dom_binding *ydbptr, *ydbptr2;
237 ydbptr2 = NULL;
238 ydbptr = ypbindlist;
240 while (ydbptr != NULL)
242 if (strcmp (ydbptr->dom_domain, indomain) == 0)
244 dom_binding *work;
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;
254 ydbptr2 = ydbptr;
255 ydbptr = ydbptr->dom_pnext;
259 void
260 yp_unbind (const char *indomain)
262 __libc_lock_lock (ypbindlist_lock);
264 yp_unbind_locked (indomain);
266 __libc_lock_unlock (ypbindlist_lock);
268 return;
270 libnsl_hidden_nolink_def(yp_unbind, GLIBC_2_0)
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)
277 enum clnt_stat result;
279 result = clnt_call ((*ydb)->dom_client, prog,
280 xargs, req, xres, resp, RPCTIMEOUT);
282 if (result != RPC_SUCCESS)
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");
289 return YPERR_RPC;
292 return YPERR_SUCCESS;
295 static int
296 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
297 caddr_t req, xdrproc_t xres, caddr_t resp)
299 dom_binding *ydb;
300 int status;
301 int saved_errno = errno;
303 status = YPERR_YPERR;
305 __libc_lock_lock (ypbindlist_lock);
306 ydb = ypbindlist;
307 while (ydb != NULL)
309 if (strcmp (domain, ydb->dom_domain) == 0)
311 if (__yp_bind (domain, &ydb) == 0)
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)
318 __libc_lock_unlock (ypbindlist_lock);
319 __set_errno (saved_errno);
320 return status;
323 /* We use ypbindlist, and the old cached data is
324 invalid. unbind now and create a new binding */
325 yp_unbind_locked (domain);
327 break;
329 ydb = ydb->dom_pnext;
331 __libc_lock_unlock (ypbindlist_lock);
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)
338 status = __ypclnt_call (domain, prog, xargs, req, xres,
339 resp, &ydb, 1);
340 __yp_unbind (ydb);
343 #if USE_BINDINGDIR
344 /* If we support binding dir data, we have a third chance:
345 Ask ypbind. */
346 if (status != YPERR_SUCCESS)
348 ydb = calloc (1, sizeof (dom_binding));
349 if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
351 status = __ypclnt_call (domain, prog, xargs, req, xres,
352 resp, &ydb, 1);
353 __yp_unbind (ydb);
355 else
356 free (ydb);
358 #endif
360 __set_errno (saved_errno);
362 return status;
365 /* Like do_ypcall, but translate the status value if necessary. */
366 static int
367 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
368 caddr_t req, xdrproc_t xres, caddr_t resp)
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;
388 __libc_lock_define_initialized (static, domainname_lock)
391 yp_get_default_domain (char **outdomain)
393 int result = YPERR_SUCCESS;;
394 *outdomain = NULL;
396 __libc_lock_lock (domainname_lock);
398 if (ypdomainname[0] == '\0')
400 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
401 result = YPERR_NODOM;
402 else if (strcmp (ypdomainname, "(none)") == 0)
404 /* If domainname is not set, some systems will return "(none)" */
405 ypdomainname[0] = '\0';
406 result = YPERR_NODOM;
408 else
409 *outdomain = ypdomainname;
411 else
412 *outdomain = ypdomainname;
414 __libc_lock_unlock (domainname_lock);
416 return result;
418 libnsl_hidden_nolink_def (yp_get_default_domain, GLIBC_2_0)
421 __yp_check (char **domain)
423 char *unused;
425 if (ypdomainname[0] == '\0')
426 if (yp_get_default_domain (&unused))
427 return 0;
429 if (domain)
430 *domain = ypdomainname;
432 if (yp_bind (ypdomainname) == 0)
433 return 1;
434 return 0;
436 libnsl_hidden_nolink_def(__yp_check, GLIBC_2_0)
439 yp_match (const char *indomain, const char *inmap, const char *inkey,
440 const int inkeylen, char **outval, int *outvallen)
442 ypreq_key req;
443 ypresp_val resp;
444 enum clnt_stat result;
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;
451 req.domain = (char *) indomain;
452 req.map = (char *) inmap;
453 req.key.keydat_val = (char *) inkey;
454 req.key.keydat_len = inkeylen;
456 *outval = NULL;
457 *outvallen = 0;
458 memset (&resp, '\0', sizeof (resp));
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);
464 if (result != YPERR_SUCCESS)
465 return result;
467 *outvallen = resp.val.valdat_len;
468 *outval = malloc (*outvallen + 1);
469 int status = YPERR_RESRC;
470 if (__glibc_likely (*outval != NULL))
472 memcpy (*outval, resp.val.valdat_val, *outvallen);
473 (*outval)[*outvallen] = '\0';
474 status = YPERR_SUCCESS;
477 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
479 return status;
481 libnsl_hidden_nolink_def(yp_match, GLIBC_2_0)
484 yp_first (const char *indomain, const char *inmap, char **outkey,
485 int *outkeylen, char **outval, int *outvallen)
487 ypreq_nokey req;
488 ypresp_key_val resp;
489 enum clnt_stat result;
491 if (indomain == NULL || indomain[0] == '\0'
492 || inmap == NULL || inmap[0] == '\0')
493 return YPERR_BADARGS;
495 req.domain = (char *) indomain;
496 req.map = (char *) inmap;
498 *outkey = *outval = NULL;
499 *outkeylen = *outvallen = 0;
500 memset (&resp, '\0', sizeof (resp));
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);
506 if (result != RPC_SUCCESS)
507 return YPERR_RPC;
508 if (resp.stat != YP_TRUE)
509 return ypprot_err (resp.stat);
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))
516 *outkeylen = resp.key.keydat_len;
517 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
518 (*outkey)[*outkeylen] = '\0';
520 *outvallen = resp.val.valdat_len;
521 memcpy (*outval, resp.val.valdat_val, *outvallen);
522 (*outval)[*outvallen] = '\0';
524 status = YPERR_SUCCESS;
526 else
528 free (*outkey);
529 status = YPERR_RESRC;
532 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
534 return status;
536 libnsl_hidden_nolink_def(yp_first, GLIBC_2_0)
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)
543 ypreq_key req;
544 ypresp_key_val resp;
545 enum clnt_stat result;
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;
552 req.domain = (char *) indomain;
553 req.map = (char *) inmap;
554 req.key.keydat_val = (char *) inkey;
555 req.key.keydat_len = inkeylen;
557 *outkey = *outval = NULL;
558 *outkeylen = *outvallen = 0;
559 memset (&resp, '\0', sizeof (resp));
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);
565 if (result != YPERR_SUCCESS)
566 return result;
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))
573 *outkeylen = resp.key.keydat_len;
574 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
575 (*outkey)[*outkeylen] = '\0';
577 *outvallen = resp.val.valdat_len;
578 memcpy (*outval, resp.val.valdat_val, *outvallen);
579 (*outval)[*outvallen] = '\0';
581 status = YPERR_SUCCESS;
583 else
585 free (*outkey);
586 status = YPERR_RESRC;
589 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
591 return status;
593 libnsl_hidden_nolink_def(yp_next, GLIBC_2_0)
596 yp_master (const char *indomain, const char *inmap, char **outname)
598 ypreq_nokey req;
599 ypresp_master resp;
600 enum clnt_stat result;
602 if (indomain == NULL || indomain[0] == '\0'
603 || inmap == NULL || inmap[0] == '\0')
604 return YPERR_BADARGS;
606 req.domain = (char *) indomain;
607 req.map = (char *) inmap;
609 memset (&resp, '\0', sizeof (ypresp_master));
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);
615 if (result != YPERR_SUCCESS)
616 return result;
618 *outname = strdup (resp.peer);
619 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
621 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
623 libnsl_hidden_nolink_def (yp_master, GLIBC_2_0)
626 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
628 struct ypreq_nokey req;
629 struct ypresp_order resp;
630 enum clnt_stat result;
632 if (indomain == NULL || indomain[0] == '\0'
633 || inmap == NULL || inmap[0] == '\0')
634 return YPERR_BADARGS;
636 req.domain = (char *) indomain;
637 req.map = (char *) inmap;
639 memset (&resp, '\0', sizeof (resp));
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);
645 if (result != YPERR_SUCCESS)
646 return result;
648 *outorder = resp.ordernum;
649 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
651 return result;
653 libnsl_hidden_nolink_def(yp_order, GLIBC_2_0)
655 struct ypresp_all_data
657 unsigned long status;
658 void *data;
659 int (*foreach) (int status, char *key, int keylen,
660 char *val, int vallen, char *data);
663 static bool_t
664 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
666 while (1)
668 struct ypresp_all resp;
670 memset (&resp, '\0', sizeof (struct ypresp_all));
671 if (!xdr_ypresp_all (xdrs, &resp))
673 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
674 objp->status = YP_YPERR;
675 return FALSE;
677 if (resp.more == 0)
679 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
680 objp->status = YP_NOMORE;
681 return TRUE;
684 switch (resp.ypresp_all_u.val.stat)
686 case YP_TRUE:
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;
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;
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;
721 yp_all (const char *indomain, const char *inmap,
722 const struct ypall_callback *incallback)
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;
734 if (indomain == NULL || indomain[0] == '\0'
735 || inmap == NULL || inmap[0] == '\0')
736 return YPERR_BADARGS;
738 try = 0;
739 res = YPERR_YPERR;
741 while (try < MAXTRIES && res != YPERR_SUCCESS)
743 if (__yp_bind (indomain, &ydb) != 0)
745 __set_errno (saved_errno);
746 return YPERR_DOMAIN;
749 clnt_sock = RPC_ANYSOCK;
750 clnt_sin = ydb->dom_server_addr;
751 clnt_sin.sin_port = 0;
753 /* We don't need the UDP connection anymore. */
754 __yp_unbind (ydb);
755 ydb = NULL;
757 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
758 if (clnt == NULL)
760 __set_errno (saved_errno);
761 return YPERR_PMAP;
763 req.domain = (char *) indomain;
764 req.map = (char *) inmap;
766 data.foreach = incallback->foreach;
767 data.data = (void *) incallback->data;
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);
773 if (__glibc_unlikely (result != RPC_SUCCESS))
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;
780 else
781 res = YPERR_SUCCESS;
783 clnt_destroy (clnt);
785 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
787 __set_errno (saved_errno);
788 return ypprot_err (data.status);
790 ++try;
793 __set_errno (saved_errno);
795 return res;
797 libnsl_hidden_nolink_def (yp_all, GLIBC_2_0)
800 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
802 struct ypresp_maplist resp;
803 enum clnt_stat result;
805 if (indomain == NULL || indomain[0] == '\0')
806 return YPERR_BADARGS;
808 memset (&resp, '\0', sizeof (resp));
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);
814 if (__glibc_likely (result == YPERR_SUCCESS))
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); */
821 return result;
823 libnsl_hidden_nolink_def (yp_maplist, GLIBC_2_0)
825 const char *
826 yperr_string (const int error)
828 const char *str;
829 switch (error)
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;
886 return _(str);
888 libnsl_hidden_nolink_def(yperr_string, GLIBC_2_0)
890 static const int8_t yp_2_yperr[] =
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)
906 ypprot_err (const int code)
908 if (code < YP_VERS || code > YP_NOMORE)
909 return YPERR_YPERR;
910 return yp_2_yperr[code - YP_VERS];
912 libnsl_hidden_nolink_def (ypprot_err, GLIBC_2_0)
914 const char *
915 ypbinderr_string (const int error)
917 const char *str;
918 switch (error)
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;
936 return _(str);
938 libnsl_hidden_nolink_def (ypbinderr_string, GLIBC_2_0)
940 #define WINDOW 60
943 yp_update (char *domain, char *map, unsigned ypop,
944 char *key, int keylen, char *data, int datalen)
946 union
948 ypupdate_args update_args;
949 ypdelete_args delete_args;
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;
960 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
961 return YPERR_BADARGS;
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;
969 if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
970 return r;
972 if (!host2netname (servername, master, domain))
974 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
975 free (master);
976 return YPERR_YPERR;
979 clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
981 /* We do not need the string anymore. */
982 free (master);
984 if (clnt == NULL)
986 clnt_pcreateerror ("yp_update: clnt_create");
987 return YPERR_RPC;
990 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
992 fputs (_("yp_update: cannot get server address\n"), stderr);
993 return YPERR_RPC;
996 switch (ypop)
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;
1011 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
1013 if (clnt->cl_auth == NULL)
1014 clnt->cl_auth = authunix_create_default ();
1016 again:
1017 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
1018 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
1020 if (r == RPC_AUTHERROR)
1022 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1024 auth_destroy (clnt->cl_auth);
1025 clnt->cl_auth = authunix_create_default ();
1026 goto again;
1028 else
1029 return YPERR_ACCESS;
1031 if (r != RPC_SUCCESS)
1033 clnt_perror (clnt, "yp_update: clnt_call");
1034 return YPERR_RPC;
1036 return res;
1038 libnsl_hidden_nolink_def(yp_update, GLIBC_2_0)