soft-fp: Fix _FP_TO_INT latent bug in overflow handling.
[glibc.git] / nis / ypclnt.c
blobdd1833bbf688362424073e3a1bab183dc79f97e4
1 /* Copyright (C) 1996-2014 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
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.
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.
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/>. */
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 <bits/libc-lock.h>
33 /* This should only be defined on systems with a BSD compatible ypbind */
34 #ifndef BINDINGDIR
35 # define BINDINGDIR "/var/yp/binding"
36 #endif
38 struct dom_binding
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;
46 typedef struct dom_binding dom_binding;
48 static const struct timeval RPCTIMEOUT = {25, 0};
49 static const struct timeval UDPTIMEOUT = {5, 0};
50 static int const MAXTRIES = 2;
51 static char ypdomainname[NIS_MAXNAMELEN + 1];
52 __libc_lock_define_initialized (static, ypbindlist_lock)
53 static dom_binding *ypbindlist = NULL;
56 static void
57 yp_bind_client_create (const char *domain, dom_binding *ysd,
58 struct ypbind_resp *ypbr)
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';
70 ysd->dom_socket = RPC_ANYSOCK;
71 #ifdef SOCK_CLOEXEC
72 # define xflags SOCK_CLOEXEC
73 #else
74 # define xflags 0
75 #endif
76 ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
77 YPVERS, UDPTIMEOUT,
78 &ysd->dom_socket,
79 UDPMSGSIZE, UDPMSGSIZE,
80 xflags);
82 if (ysd->dom_client != NULL)
84 #ifndef SOCK_CLOEXEC
85 /* If the program exits, close the socket */
86 if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
87 perror ("fcntl: F_SETFD");
88 #endif
92 #if USE_BINDINGDIR
93 static void
94 yp_bind_file (const char *domain, dom_binding *ysd)
96 char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
98 snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
99 int fd = open (path, O_RDONLY);
100 if (fd >= 0)
102 /* We have a binding file and could save a RPC call. The file
103 contains a port number and the YPBIND_RESP record. The port
104 number (16 bits) can be ignored. */
105 struct ypbind_resp ypbr;
107 if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
108 yp_bind_client_create (domain, ysd, &ypbr);
110 close (fd);
113 #endif
115 static int
116 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
118 struct sockaddr_in clnt_saddr;
119 struct ypbind_resp ypbr;
120 int clnt_sock;
121 CLIENT *client;
123 clnt_saddr.sin_family = AF_INET;
124 clnt_saddr.sin_port = 0;
125 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
126 clnt_sock = RPC_ANYSOCK;
127 client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
128 &clnt_sock, 0, 0);
129 if (client == NULL)
130 return YPERR_YPBIND;
132 /* Check the port number -- should be < IPPORT_RESERVED.
133 If not, it's possible someone has registered a bogus
134 ypbind with the portmapper and is trying to trick us. */
135 if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
137 clnt_destroy (client);
138 return YPERR_YPBIND;
141 if (clnt_call (client, YPBINDPROC_DOMAIN,
142 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
143 (xdrproc_t) xdr_ypbind_resp,
144 (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
146 clnt_destroy (client);
147 return YPERR_YPBIND;
150 clnt_destroy (client);
152 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
154 fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
155 ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
156 return YPERR_DOMAIN;
158 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
160 yp_bind_client_create (domain, ysd, &ypbr);
162 return YPERR_SUCCESS;
165 static int
166 __yp_bind (const char *domain, dom_binding **ypdb)
168 dom_binding *ysd = NULL;
169 int is_new = 0;
171 if (domain == NULL || domain[0] == '\0')
172 return YPERR_BADARGS;
174 ysd = *ypdb;
175 while (ysd != NULL)
177 if (strcmp (domain, ysd->dom_domain) == 0)
178 break;
179 ysd = ysd->dom_pnext;
182 if (ysd == NULL)
184 is_new = 1;
185 ysd = (dom_binding *) calloc (1, sizeof *ysd);
186 if (__glibc_unlikely (ysd == NULL))
187 return YPERR_RESRC;
190 #if USE_BINDINGDIR
191 /* Try binding dir at first if we have no binding */
192 if (ysd->dom_client == NULL)
193 yp_bind_file (domain, ysd);
194 #endif /* USE_BINDINGDIR */
196 if (ysd->dom_client == NULL)
198 int retval = yp_bind_ypbindprog (domain, ysd);
199 if (retval != YPERR_SUCCESS)
201 if (is_new)
202 free (ysd);
203 return retval;
207 if (ysd->dom_client == NULL)
209 if (is_new)
210 free (ysd);
211 return YPERR_YPSERV;
214 if (is_new)
216 ysd->dom_pnext = *ypdb;
217 *ypdb = ysd;
220 return YPERR_SUCCESS;
223 static void
224 __yp_unbind (dom_binding *ydb)
226 clnt_destroy (ydb->dom_client);
227 free (ydb);
231 yp_bind (const char *indomain)
233 int status;
235 __libc_lock_lock (ypbindlist_lock);
237 status = __yp_bind (indomain, &ypbindlist);
239 __libc_lock_unlock (ypbindlist_lock);
241 return status;
243 libnsl_hidden_def (yp_bind)
245 static void
246 yp_unbind_locked (const char *indomain)
248 dom_binding *ydbptr, *ydbptr2;
250 ydbptr2 = NULL;
251 ydbptr = ypbindlist;
253 while (ydbptr != NULL)
255 if (strcmp (ydbptr->dom_domain, indomain) == 0)
257 dom_binding *work;
259 work = ydbptr;
260 if (ydbptr2 == NULL)
261 ypbindlist = ypbindlist->dom_pnext;
262 else
263 ydbptr2 = ydbptr->dom_pnext;
264 __yp_unbind (work);
265 break;
267 ydbptr2 = ydbptr;
268 ydbptr = ydbptr->dom_pnext;
272 void
273 yp_unbind (const char *indomain)
275 __libc_lock_lock (ypbindlist_lock);
277 yp_unbind_locked (indomain);
279 __libc_lock_unlock (ypbindlist_lock);
281 return;
284 static int
285 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
286 caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
287 int print_error)
289 enum clnt_stat result;
291 result = clnt_call ((*ydb)->dom_client, prog,
292 xargs, req, xres, resp, RPCTIMEOUT);
294 if (result != RPC_SUCCESS)
296 /* We don't print an error message, if we try our old,
297 cached data. Only print this for data, which should work. */
298 if (print_error)
299 clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
301 return YPERR_RPC;
304 return YPERR_SUCCESS;
307 static int
308 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
309 caddr_t req, xdrproc_t xres, caddr_t resp)
311 dom_binding *ydb;
312 int status;
313 int saved_errno = errno;
315 status = YPERR_YPERR;
317 __libc_lock_lock (ypbindlist_lock);
318 ydb = ypbindlist;
319 while (ydb != NULL)
321 if (strcmp (domain, ydb->dom_domain) == 0)
323 if (__yp_bind (domain, &ydb) == 0)
325 /* Call server, print no error message, do not unbind. */
326 status = __ypclnt_call (domain, prog, xargs, req, xres,
327 resp, &ydb, 0);
328 if (status == YPERR_SUCCESS)
330 __libc_lock_unlock (ypbindlist_lock);
331 __set_errno (saved_errno);
332 return status;
335 /* We use ypbindlist, and the old cached data is
336 invalid. unbind now and create a new binding */
337 yp_unbind_locked (domain);
339 break;
341 ydb = ydb->dom_pnext;
343 __libc_lock_unlock (ypbindlist_lock);
345 /* First try with cached data failed. Now try to get
346 current data from the system. */
347 ydb = NULL;
348 if (__yp_bind (domain, &ydb) == 0)
350 status = __ypclnt_call (domain, prog, xargs, req, xres,
351 resp, &ydb, 1);
352 __yp_unbind (ydb);
355 #if USE_BINDINGDIR
356 /* If we support binding dir data, we have a third chance:
357 Ask ypbind. */
358 if (status != YPERR_SUCCESS)
360 ydb = calloc (1, sizeof (dom_binding));
361 if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
363 status = __ypclnt_call (domain, prog, xargs, req, xres,
364 resp, &ydb, 1);
365 __yp_unbind (ydb);
367 else
368 free (ydb);
370 #endif
372 __set_errno (saved_errno);
374 return status;
377 /* Like do_ypcall, but translate the status value if necessary. */
378 static int
379 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
380 caddr_t req, xdrproc_t xres, caddr_t resp)
382 int status = do_ypcall (domain, prog, xargs, req, xres, resp);
383 if (status == YPERR_SUCCESS)
384 /* We cast to ypresp_val although the pointer could also be of
385 type ypresp_key_val or ypresp_master or ypresp_order or
386 ypresp_maplist. But the stat element is in a common prefix so
387 this does not matter. */
388 status = ypprot_err (((struct ypresp_val *) resp)->stat);
389 return status;
393 __libc_lock_define_initialized (static, domainname_lock)
396 yp_get_default_domain (char **outdomain)
398 int result = YPERR_SUCCESS;;
399 *outdomain = NULL;
401 __libc_lock_lock (domainname_lock);
403 if (ypdomainname[0] == '\0')
405 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
406 result = YPERR_NODOM;
407 else if (strcmp (ypdomainname, "(none)") == 0)
409 /* If domainname is not set, some systems will return "(none)" */
410 ypdomainname[0] = '\0';
411 result = YPERR_NODOM;
413 else
414 *outdomain = ypdomainname;
416 else
417 *outdomain = ypdomainname;
419 __libc_lock_unlock (domainname_lock);
421 return result;
423 libnsl_hidden_def (yp_get_default_domain)
426 __yp_check (char **domain)
428 char *unused;
430 if (ypdomainname[0] == '\0')
431 if (yp_get_default_domain (&unused))
432 return 0;
434 if (domain)
435 *domain = ypdomainname;
437 if (yp_bind (ypdomainname) == 0)
438 return 1;
439 return 0;
443 yp_match (const char *indomain, const char *inmap, const char *inkey,
444 const int inkeylen, char **outval, int *outvallen)
446 ypreq_key req;
447 ypresp_val resp;
448 enum clnt_stat result;
450 if (indomain == NULL || indomain[0] == '\0' ||
451 inmap == NULL || inmap[0] == '\0' ||
452 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
453 return YPERR_BADARGS;
455 req.domain = (char *) indomain;
456 req.map = (char *) inmap;
457 req.key.keydat_val = (char *) inkey;
458 req.key.keydat_len = inkeylen;
460 *outval = NULL;
461 *outvallen = 0;
462 memset (&resp, '\0', sizeof (resp));
464 result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
465 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
466 (caddr_t) &resp);
468 if (result != YPERR_SUCCESS)
469 return result;
471 *outvallen = resp.val.valdat_len;
472 *outval = malloc (*outvallen + 1);
473 int status = YPERR_RESRC;
474 if (__glibc_likely (*outval != NULL))
476 memcpy (*outval, resp.val.valdat_val, *outvallen);
477 (*outval)[*outvallen] = '\0';
478 status = YPERR_SUCCESS;
481 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
483 return status;
487 yp_first (const char *indomain, const char *inmap, char **outkey,
488 int *outkeylen, char **outval, int *outvallen)
490 ypreq_nokey req;
491 ypresp_key_val resp;
492 enum clnt_stat result;
494 if (indomain == NULL || indomain[0] == '\0' ||
495 inmap == NULL || inmap[0] == '\0')
496 return YPERR_BADARGS;
498 req.domain = (char *) indomain;
499 req.map = (char *) inmap;
501 *outkey = *outval = NULL;
502 *outkeylen = *outvallen = 0;
503 memset (&resp, '\0', sizeof (resp));
505 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
506 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
507 (caddr_t) &resp);
509 if (result != RPC_SUCCESS)
510 return YPERR_RPC;
511 if (resp.stat != YP_TRUE)
512 return ypprot_err (resp.stat);
514 int status;
515 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
516 && (*outval = malloc (resp.val.valdat_len
517 + 1)) != NULL, 1))
519 *outkeylen = resp.key.keydat_len;
520 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
521 (*outkey)[*outkeylen] = '\0';
523 *outvallen = resp.val.valdat_len;
524 memcpy (*outval, resp.val.valdat_val, *outvallen);
525 (*outval)[*outvallen] = '\0';
527 status = YPERR_SUCCESS;
529 else
531 free (*outkey);
532 status = YPERR_RESRC;
535 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
537 return status;
541 yp_next (const char *indomain, const char *inmap, const char *inkey,
542 const int inkeylen, char **outkey, int *outkeylen, char **outval,
543 int *outvallen)
545 ypreq_key req;
546 ypresp_key_val resp;
547 enum clnt_stat result;
549 if (indomain == NULL || indomain[0] == '\0' ||
550 inmap == NULL || inmap[0] == '\0' ||
551 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
552 return YPERR_BADARGS;
554 req.domain = (char *) indomain;
555 req.map = (char *) inmap;
556 req.key.keydat_val = (char *) inkey;
557 req.key.keydat_len = inkeylen;
559 *outkey = *outval = NULL;
560 *outkeylen = *outvallen = 0;
561 memset (&resp, '\0', sizeof (resp));
563 result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
564 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
565 (caddr_t) &resp);
567 if (result != YPERR_SUCCESS)
568 return result;
570 int status;
571 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
572 && (*outval = malloc (resp.val.valdat_len
573 + 1)) != NULL, 1))
575 *outkeylen = resp.key.keydat_len;
576 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
577 (*outkey)[*outkeylen] = '\0';
579 *outvallen = resp.val.valdat_len;
580 memcpy (*outval, resp.val.valdat_val, *outvallen);
581 (*outval)[*outvallen] = '\0';
583 status = YPERR_SUCCESS;
585 else
587 free (*outkey);
588 status = YPERR_RESRC;
591 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
593 return status;
597 yp_master (const char *indomain, const char *inmap, char **outname)
599 ypreq_nokey req;
600 ypresp_master resp;
601 enum clnt_stat result;
603 if (indomain == NULL || indomain[0] == '\0' ||
604 inmap == NULL || inmap[0] == '\0')
605 return YPERR_BADARGS;
607 req.domain = (char *) indomain;
608 req.map = (char *) inmap;
610 memset (&resp, '\0', sizeof (ypresp_master));
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);
616 if (result != YPERR_SUCCESS)
617 return result;
619 *outname = strdup (resp.peer);
620 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
622 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
624 libnsl_hidden_def (yp_master)
627 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
629 struct ypreq_nokey req;
630 struct ypresp_order resp;
631 enum clnt_stat result;
633 if (indomain == NULL || indomain[0] == '\0' ||
634 inmap == NULL || inmap[0] == '\0')
635 return YPERR_BADARGS;
637 req.domain = (char *) indomain;
638 req.map = (char *) inmap;
640 memset (&resp, '\0', sizeof (resp));
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);
646 if (result != YPERR_SUCCESS)
647 return result;
649 *outorder = resp.ordernum;
650 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
652 return result;
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;
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;
824 const char *
825 yperr_string (const int error)
827 const char *str;
828 switch (error)
830 case YPERR_SUCCESS:
831 str = N_("Success");
832 break;
833 case YPERR_BADARGS:
834 str = N_("Request arguments bad");
835 break;
836 case YPERR_RPC:
837 str = N_("RPC failure on NIS operation");
838 break;
839 case YPERR_DOMAIN:
840 str = N_("Can't bind to server which serves this domain");
841 break;
842 case YPERR_MAP:
843 str = N_("No such map in server's domain");
844 break;
845 case YPERR_KEY:
846 str = N_("No such key in map");
847 break;
848 case YPERR_YPERR:
849 str = N_("Internal NIS error");
850 break;
851 case YPERR_RESRC:
852 str = N_("Local resource allocation failure");
853 break;
854 case YPERR_NOMORE:
855 str = N_("No more records in map database");
856 break;
857 case YPERR_PMAP:
858 str = N_("Can't communicate with portmapper");
859 break;
860 case YPERR_YPBIND:
861 str = N_("Can't communicate with ypbind");
862 break;
863 case YPERR_YPSERV:
864 str = N_("Can't communicate with ypserv");
865 break;
866 case YPERR_NODOM:
867 str = N_("Local domain name not set");
868 break;
869 case YPERR_BADDB:
870 str = N_("NIS map database is bad");
871 break;
872 case YPERR_VERS:
873 str = N_("NIS client/server version mismatch - can't supply service");
874 break;
875 case YPERR_ACCESS:
876 str = N_("Permission denied");
877 break;
878 case YPERR_BUSY:
879 str = N_("Database is busy");
880 break;
881 default:
882 str = N_("Unknown NIS error code");
883 break;
885 return _(str);
888 static const int8_t yp_2_yperr[] =
890 #define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
891 YP2YPERR (TRUE, SUCCESS),
892 YP2YPERR (NOMORE, NOMORE),
893 YP2YPERR (FALSE, YPERR),
894 YP2YPERR (NOMAP, MAP),
895 YP2YPERR (NODOM, DOMAIN),
896 YP2YPERR (NOKEY, KEY),
897 YP2YPERR (BADOP, YPERR),
898 YP2YPERR (BADDB, BADDB),
899 YP2YPERR (YPERR, YPERR),
900 YP2YPERR (BADARGS, BADARGS),
901 YP2YPERR (VERS, VERS)
904 ypprot_err (const int code)
906 if (code < YP_VERS || code > YP_NOMORE)
907 return YPERR_YPERR;
908 return yp_2_yperr[code - YP_VERS];
910 libnsl_hidden_def (ypprot_err)
912 const char *
913 ypbinderr_string (const int error)
915 const char *str;
916 switch (error)
918 case 0:
919 str = N_("Success");
920 break;
921 case YPBIND_ERR_ERR:
922 str = N_("Internal ypbind error");
923 break;
924 case YPBIND_ERR_NOSERV:
925 str = N_("Domain not bound");
926 break;
927 case YPBIND_ERR_RESC:
928 str = N_("System resource allocation failure");
929 break;
930 default:
931 str = N_("Unknown ypbind error");
932 break;
934 return _(str);
936 libnsl_hidden_def (ypbinderr_string)
938 #define WINDOW 60
941 yp_update (char *domain, char *map, unsigned ypop,
942 char *key, int keylen, char *data, int datalen)
944 union
946 ypupdate_args update_args;
947 ypdelete_args delete_args;
949 args;
950 xdrproc_t xdr_argument;
951 unsigned res = 0;
952 CLIENT *clnt;
953 char *master;
954 struct sockaddr saddr;
955 char servername[MAXNETNAMELEN + 1];
956 int r;
958 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
959 return YPERR_BADARGS;
961 args.update_args.mapname = map;
962 args.update_args.key.yp_buf_len = keylen;
963 args.update_args.key.yp_buf_val = key;
964 args.update_args.datum.yp_buf_len = datalen;
965 args.update_args.datum.yp_buf_val = data;
967 if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
968 return r;
970 if (!host2netname (servername, master, domain))
972 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
973 free (master);
974 return YPERR_YPERR;
977 clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
979 /* We do not need the string anymore. */
980 free (master);
982 if (clnt == NULL)
984 clnt_pcreateerror ("yp_update: clnt_create");
985 return YPERR_RPC;
988 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
990 fputs (_("yp_update: cannot get server address\n"), stderr);
991 return YPERR_RPC;
994 switch (ypop)
996 case YPOP_CHANGE:
997 case YPOP_INSERT:
998 case YPOP_STORE:
999 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
1000 break;
1001 case YPOP_DELETE:
1002 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
1003 break;
1004 default:
1005 return YPERR_BADARGS;
1006 break;
1009 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
1011 if (clnt->cl_auth == NULL)
1012 clnt->cl_auth = authunix_create_default ();
1014 again:
1015 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
1016 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
1018 if (r == RPC_AUTHERROR)
1020 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1022 auth_destroy (clnt->cl_auth);
1023 clnt->cl_auth = authunix_create_default ();
1024 goto again;
1026 else
1027 return YPERR_ACCESS;
1029 if (r != RPC_SUCCESS)
1031 clnt_perror (clnt, "yp_update: clnt_call");
1032 return YPERR_RPC;
1034 return res;