[BZ #6411]
[glibc.git] / nis / ypclnt.c
blobaaf4eb6e5945dc7bfb5e8719f52b383f477fae72
1 /* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <libintl.h>
26 #include <rpc/rpc.h>
27 #include <rpcsvc/nis.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/ypupd.h>
31 #include <sys/socket.h>
32 #include <sys/uio.h>
33 #include <bits/libc-lock.h>
35 /* This should only be defined on systems with a BSD compatible ypbind */
36 #ifndef BINDINGDIR
37 # define BINDINGDIR "/var/yp/binding"
38 #endif
40 struct dom_binding
42 struct dom_binding *dom_pnext;
43 char dom_domain[YPMAXDOMAIN + 1];
44 struct sockaddr_in dom_server_addr;
45 int dom_socket;
46 CLIENT *dom_client;
48 typedef struct dom_binding dom_binding;
50 static const struct timeval RPCTIMEOUT = {25, 0};
51 static const struct timeval UDPTIMEOUT = {5, 0};
52 static int const MAXTRIES = 2;
53 static char ypdomainname[NIS_MAXNAMELEN + 1];
54 __libc_lock_define_initialized (static, ypbindlist_lock)
55 static dom_binding *ypbindlist = NULL;
58 static void
59 yp_bind_client_create (const char *domain, dom_binding *ysd,
60 struct ypbind_resp *ypbr)
62 ysd->dom_server_addr.sin_family = AF_INET;
63 memcpy (&ysd->dom_server_addr.sin_port,
64 ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
65 sizeof (ysd->dom_server_addr.sin_port));
66 memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
67 ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
68 sizeof (ysd->dom_server_addr.sin_addr.s_addr));
69 strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
70 ysd->dom_domain[YPMAXDOMAIN] = '\0';
72 ysd->dom_socket = RPC_ANYSOCK;
73 #ifdef SOCK_CLOEXEC
74 # define xflags SOCK_CLOEXEC
75 #else
76 # define xflags 0
77 #endif
78 ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
79 YPVERS, UDPTIMEOUT,
80 &ysd->dom_socket,
81 UDPMSGSIZE, UDPMSGSIZE,
82 xflags);
84 if (ysd->dom_client != NULL)
86 #ifndef SOCK_CLOEXEC
87 /* If the program exits, close the socket */
88 if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
89 perror ("fcntl: F_SETFD");
90 #endif
94 #if USE_BINDINGDIR
95 static void
96 yp_bind_file (const char *domain, dom_binding *ysd)
98 char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
100 snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
101 int fd = open (path, O_RDONLY);
102 if (fd >= 0)
104 /* We have a binding file and could save a RPC call. The file
105 contains a port number and the YPBIND_RESP record. The port
106 number (16 bits) can be ignored. */
107 struct ypbind_resp ypbr;
109 if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
110 yp_bind_client_create (domain, ysd, &ypbr);
112 close (fd);
115 #endif
117 static int
118 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
120 struct sockaddr_in clnt_saddr;
121 struct ypbind_resp ypbr;
122 int clnt_sock;
123 CLIENT *client;
125 clnt_saddr.sin_family = AF_INET;
126 clnt_saddr.sin_port = 0;
127 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
128 clnt_sock = RPC_ANYSOCK;
129 client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
130 &clnt_sock, 0, 0);
131 if (client == NULL)
132 return YPERR_YPBIND;
134 /* Check the port number -- should be < IPPORT_RESERVED.
135 If not, it's possible someone has registered a bogus
136 ypbind with the portmapper and is trying to trick us. */
137 if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
139 clnt_destroy (client);
140 return YPERR_YPBIND;
143 if (clnt_call (client, YPBINDPROC_DOMAIN,
144 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
145 (xdrproc_t) xdr_ypbind_resp,
146 (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
148 clnt_destroy (client);
149 return YPERR_YPBIND;
152 clnt_destroy (client);
154 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
156 fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
157 ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
158 return YPERR_DOMAIN;
160 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
162 yp_bind_client_create (domain, ysd, &ypbr);
164 return YPERR_SUCCESS;
167 static int
168 __yp_bind (const char *domain, dom_binding **ypdb)
170 dom_binding *ysd = NULL;
171 int is_new = 0;
173 if (domain == NULL || domain[0] == '\0')
174 return YPERR_BADARGS;
176 ysd = *ypdb;
177 while (ysd != NULL)
179 if (strcmp (domain, ysd->dom_domain) == 0)
180 break;
181 ysd = ysd->dom_pnext;
184 if (ysd == NULL)
186 is_new = 1;
187 ysd = (dom_binding *) calloc (1, sizeof *ysd);
188 if (__builtin_expect (ysd == NULL, 0))
189 return YPERR_RESRC;
192 #if USE_BINDINGDIR
193 /* Try binding dir at first if we have no binding */
194 if (ysd->dom_client == NULL)
195 yp_bind_file (domain, ysd);
196 #endif /* USE_BINDINGDIR */
198 if (ysd->dom_client == NULL)
200 int retval = yp_bind_ypbindprog (domain, ysd);
201 if (retval != YPERR_SUCCESS)
203 if (is_new)
204 free (ysd);
205 return retval;
209 if (ysd->dom_client == NULL)
211 if (is_new)
212 free (ysd);
213 return YPERR_YPSERV;
216 if (is_new)
218 ysd->dom_pnext = *ypdb;
219 *ypdb = ysd;
222 return YPERR_SUCCESS;
225 static void
226 __yp_unbind (dom_binding *ydb)
228 clnt_destroy (ydb->dom_client);
229 free (ydb);
233 yp_bind (const char *indomain)
235 int status;
237 __libc_lock_lock (ypbindlist_lock);
239 status = __yp_bind (indomain, &ypbindlist);
241 __libc_lock_unlock (ypbindlist_lock);
243 return status;
245 libnsl_hidden_def (yp_bind)
247 static void
248 yp_unbind_locked (const char *indomain)
250 dom_binding *ydbptr, *ydbptr2;
252 ydbptr2 = NULL;
253 ydbptr = ypbindlist;
255 while (ydbptr != NULL)
257 if (strcmp (ydbptr->dom_domain, indomain) == 0)
259 dom_binding *work;
261 work = ydbptr;
262 if (ydbptr2 == NULL)
263 ypbindlist = ypbindlist->dom_pnext;
264 else
265 ydbptr2 = ydbptr->dom_pnext;
266 __yp_unbind (work);
267 break;
269 ydbptr2 = ydbptr;
270 ydbptr = ydbptr->dom_pnext;
274 void
275 yp_unbind (const char *indomain)
277 __libc_lock_lock (ypbindlist_lock);
279 yp_unbind_locked (indomain);
281 __libc_lock_unlock (ypbindlist_lock);
283 return;
286 static int
287 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
288 caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
289 int print_error)
291 enum clnt_stat result;
293 result = clnt_call ((*ydb)->dom_client, prog,
294 xargs, req, xres, resp, RPCTIMEOUT);
296 if (result != RPC_SUCCESS)
298 /* We don't print an error message, if we try our old,
299 cached data. Only print this for data, which should work. */
300 if (print_error)
301 clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
303 return YPERR_RPC;
306 return YPERR_SUCCESS;
309 static int
310 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
311 caddr_t req, xdrproc_t xres, caddr_t resp)
313 dom_binding *ydb;
314 int status;
315 int saved_errno = errno;
317 status = YPERR_YPERR;
319 __libc_lock_lock (ypbindlist_lock);
320 ydb = ypbindlist;
321 while (ydb != NULL)
323 if (strcmp (domain, ydb->dom_domain) == 0)
325 if (__yp_bind (domain, &ydb) == 0)
327 /* Call server, print no error message, do not unbind. */
328 status = __ypclnt_call (domain, prog, xargs, req, xres,
329 resp, &ydb, 0);
330 if (status == YPERR_SUCCESS)
332 __libc_lock_unlock (ypbindlist_lock);
333 __set_errno (saved_errno);
334 return status;
337 /* We use ypbindlist, and the old cached data is
338 invalid. unbind now and create a new binding */
339 yp_unbind_locked (domain);
341 break;
343 ydb = ydb->dom_pnext;
345 __libc_lock_unlock (ypbindlist_lock);
347 /* First try with cached data failed. Now try to get
348 current data from the system. */
349 ydb = NULL;
350 if (__yp_bind (domain, &ydb) == 0)
352 status = __ypclnt_call (domain, prog, xargs, req, xres,
353 resp, &ydb, 1);
354 __yp_unbind (ydb);
357 #if USE_BINDINGDIR
358 /* If we support binding dir data, we have a third chance:
359 Ask ypbind. */
360 if (status != YPERR_SUCCESS)
362 ydb = calloc (1, sizeof (dom_binding));
363 if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
365 status = __ypclnt_call (domain, prog, xargs, req, xres,
366 resp, &ydb, 1);
367 __yp_unbind (ydb);
369 else
370 free (ydb);
372 #endif
374 __set_errno (saved_errno);
376 return status;
379 /* Like do_ypcall, but translate the status value if necessary. */
380 static int
381 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
382 caddr_t req, xdrproc_t xres, caddr_t resp)
384 int status = do_ypcall (domain, prog, xargs, req, xres, resp);
385 if (status == YPERR_SUCCESS)
386 /* We cast to ypresp_val although the pointer could also be of
387 type ypresp_key_val or ypresp_master or ypresp_order or
388 ypresp_maplist. But the stat element is in a common prefix so
389 this does not matter. */
390 status = ypprot_err (((struct ypresp_val *) resp)->stat);
391 return status;
395 __libc_lock_define_initialized (static, domainname_lock)
398 yp_get_default_domain (char **outdomain)
400 int result = YPERR_SUCCESS;;
401 *outdomain = NULL;
403 __libc_lock_lock (domainname_lock);
405 if (ypdomainname[0] == '\0')
407 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
408 result = YPERR_NODOM;
409 else if (strcmp (ypdomainname, "(none)") == 0)
411 /* If domainname is not set, some systems will return "(none)" */
412 ypdomainname[0] = '\0';
413 result = YPERR_NODOM;
415 else
416 *outdomain = ypdomainname;
418 else
419 *outdomain = ypdomainname;
421 __libc_lock_unlock (domainname_lock);
423 return result;
425 libnsl_hidden_def (yp_get_default_domain)
428 __yp_check (char **domain)
430 char *unused;
432 if (ypdomainname[0] == '\0')
433 if (yp_get_default_domain (&unused))
434 return 0;
436 if (domain)
437 *domain = ypdomainname;
439 if (yp_bind (ypdomainname) == 0)
440 return 1;
441 return 0;
445 yp_match (const char *indomain, const char *inmap, const char *inkey,
446 const int inkeylen, char **outval, int *outvallen)
448 ypreq_key req;
449 ypresp_val resp;
450 enum clnt_stat result;
452 if (indomain == NULL || indomain[0] == '\0' ||
453 inmap == NULL || inmap[0] == '\0' ||
454 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
455 return YPERR_BADARGS;
457 req.domain = (char *) indomain;
458 req.map = (char *) inmap;
459 req.key.keydat_val = (char *) inkey;
460 req.key.keydat_len = inkeylen;
462 *outval = NULL;
463 *outvallen = 0;
464 memset (&resp, '\0', sizeof (resp));
466 result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
467 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
468 (caddr_t) &resp);
470 if (result != YPERR_SUCCESS)
471 return result;
473 *outvallen = resp.val.valdat_len;
474 *outval = malloc (*outvallen + 1);
475 int status = YPERR_RESRC;
476 if (__builtin_expect (*outval != NULL, 1))
478 memcpy (*outval, resp.val.valdat_val, *outvallen);
479 (*outval)[*outvallen] = '\0';
480 status = YPERR_SUCCESS;
483 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
485 return status;
489 yp_first (const char *indomain, const char *inmap, char **outkey,
490 int *outkeylen, char **outval, int *outvallen)
492 ypreq_nokey req;
493 ypresp_key_val resp;
494 enum clnt_stat result;
496 if (indomain == NULL || indomain[0] == '\0' ||
497 inmap == NULL || inmap[0] == '\0')
498 return YPERR_BADARGS;
500 req.domain = (char *) indomain;
501 req.map = (char *) inmap;
503 *outkey = *outval = NULL;
504 *outkeylen = *outvallen = 0;
505 memset (&resp, '\0', sizeof (resp));
507 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
508 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
509 (caddr_t) &resp);
511 if (result != RPC_SUCCESS)
512 return YPERR_RPC;
513 if (resp.stat != YP_TRUE)
514 return ypprot_err (resp.stat);
516 int status;
517 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
518 && (*outval = malloc (resp.val.valdat_len
519 + 1)) != NULL, 1))
521 *outkeylen = resp.key.keydat_len;
522 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
523 (*outkey)[*outkeylen] = '\0';
525 *outvallen = resp.val.valdat_len;
526 memcpy (*outval, resp.val.valdat_val, *outvallen);
527 (*outval)[*outvallen] = '\0';
529 status = YPERR_SUCCESS;
531 else
533 free (*outkey);
534 status = YPERR_RESRC;
537 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
539 return status;
543 yp_next (const char *indomain, const char *inmap, const char *inkey,
544 const int inkeylen, char **outkey, int *outkeylen, char **outval,
545 int *outvallen)
547 ypreq_key req;
548 ypresp_key_val resp;
549 enum clnt_stat result;
551 if (indomain == NULL || indomain[0] == '\0' ||
552 inmap == NULL || inmap[0] == '\0' ||
553 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
554 return YPERR_BADARGS;
556 req.domain = (char *) indomain;
557 req.map = (char *) inmap;
558 req.key.keydat_val = (char *) inkey;
559 req.key.keydat_len = inkeylen;
561 *outkey = *outval = NULL;
562 *outkeylen = *outvallen = 0;
563 memset (&resp, '\0', sizeof (resp));
565 result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
566 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
567 (caddr_t) &resp);
569 if (result != YPERR_SUCCESS)
570 return result;
572 int status;
573 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
574 && (*outval = malloc (resp.val.valdat_len
575 + 1)) != NULL, 1))
577 *outkeylen = resp.key.keydat_len;
578 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
579 (*outkey)[*outkeylen] = '\0';
581 *outvallen = resp.val.valdat_len;
582 memcpy (*outval, resp.val.valdat_val, *outvallen);
583 (*outval)[*outvallen] = '\0';
585 status = YPERR_SUCCESS;
587 else
589 free (*outkey);
590 status = YPERR_RESRC;
593 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
595 return status;
599 yp_master (const char *indomain, const char *inmap, char **outname)
601 ypreq_nokey req;
602 ypresp_master resp;
603 enum clnt_stat result;
605 if (indomain == NULL || indomain[0] == '\0' ||
606 inmap == NULL || inmap[0] == '\0')
607 return YPERR_BADARGS;
609 req.domain = (char *) indomain;
610 req.map = (char *) inmap;
612 memset (&resp, '\0', sizeof (ypresp_master));
614 result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
615 (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
616 (caddr_t) &resp);
618 if (result != YPERR_SUCCESS)
619 return result;
621 *outname = strdup (resp.peer);
622 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
624 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
626 libnsl_hidden_def (yp_master)
629 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
631 struct ypreq_nokey req;
632 struct ypresp_order resp;
633 enum clnt_stat result;
635 if (indomain == NULL || indomain[0] == '\0' ||
636 inmap == NULL || inmap[0] == '\0')
637 return YPERR_BADARGS;
639 req.domain = (char *) indomain;
640 req.map = (char *) inmap;
642 memset (&resp, '\0', sizeof (resp));
644 result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
645 (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
646 (caddr_t) &resp);
648 if (result != YPERR_SUCCESS)
649 return result;
651 *outorder = resp.ordernum;
652 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
654 return result;
657 struct ypresp_all_data
659 unsigned long status;
660 void *data;
661 int (*foreach) (int status, char *key, int keylen,
662 char *val, int vallen, char *data);
665 static bool_t
666 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
668 while (1)
670 struct ypresp_all resp;
672 memset (&resp, '\0', sizeof (struct ypresp_all));
673 if (!xdr_ypresp_all (xdrs, &resp))
675 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
676 objp->status = YP_YPERR;
677 return FALSE;
679 if (resp.more == 0)
681 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
682 objp->status = YP_NOMORE;
683 return TRUE;
686 switch (resp.ypresp_all_u.val.stat)
688 case YP_TRUE:
690 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
691 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
692 int keylen = resp.ypresp_all_u.val.key.keydat_len;
693 int vallen = resp.ypresp_all_u.val.val.valdat_len;
695 /* We are not allowed to modify the key and val data.
696 But we are allowed to add data behind the buffer,
697 if we don't modify the length. So add an extra NUL
698 character to avoid trouble with broken code. */
699 objp->status = YP_TRUE;
700 *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
701 keylen)) = '\0';
702 *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
703 vallen)) = '\0';
704 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
705 if ((*objp->foreach) (objp->status, key, keylen,
706 val, vallen, objp->data))
707 return TRUE;
709 break;
710 default:
711 objp->status = resp.ypresp_all_u.val.stat;
712 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
713 /* Sun says we don't need to make this call, but must return
714 immediately. Since Solaris makes this call, we will call
715 the callback function, too. */
716 (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
717 return TRUE;
723 yp_all (const char *indomain, const char *inmap,
724 const struct ypall_callback *incallback)
726 struct ypreq_nokey req;
727 dom_binding *ydb = NULL;
728 int try, res;
729 enum clnt_stat result;
730 struct sockaddr_in clnt_sin;
731 CLIENT *clnt;
732 struct ypresp_all_data data;
733 int clnt_sock;
734 int saved_errno = errno;
736 if (indomain == NULL || indomain[0] == '\0'
737 || inmap == NULL || inmap[0] == '\0')
738 return YPERR_BADARGS;
740 try = 0;
741 res = YPERR_YPERR;
743 while (try < MAXTRIES && res != YPERR_SUCCESS)
745 if (__yp_bind (indomain, &ydb) != 0)
747 __set_errno (saved_errno);
748 return YPERR_DOMAIN;
751 clnt_sock = RPC_ANYSOCK;
752 clnt_sin = ydb->dom_server_addr;
753 clnt_sin.sin_port = 0;
755 /* We don't need the UDP connection anymore. */
756 __yp_unbind (ydb);
757 ydb = NULL;
759 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
760 if (clnt == NULL)
762 __set_errno (saved_errno);
763 return YPERR_PMAP;
765 req.domain = (char *) indomain;
766 req.map = (char *) inmap;
768 data.foreach = incallback->foreach;
769 data.data = (void *) incallback->data;
771 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
772 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
773 (caddr_t) &data, RPCTIMEOUT);
775 if (__builtin_expect (result != RPC_SUCCESS, 0))
777 /* Print the error message only on the last try. */
778 if (try == MAXTRIES - 1)
779 clnt_perror (clnt, "yp_all: clnt_call");
780 res = YPERR_RPC;
782 else
783 res = YPERR_SUCCESS;
785 clnt_destroy (clnt);
787 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
789 __set_errno (saved_errno);
790 return ypprot_err (data.status);
792 ++try;
795 __set_errno (saved_errno);
797 return res;
802 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
804 struct ypresp_maplist resp;
805 enum clnt_stat result;
807 if (indomain == NULL || indomain[0] == '\0')
808 return YPERR_BADARGS;
810 memset (&resp, '\0', sizeof (resp));
812 result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
813 (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
814 (caddr_t) &resp);
816 if (__builtin_expect (result == YPERR_SUCCESS, 1))
818 *outmaplist = resp.maps;
819 /* We don't free the list, this will be done by ypserv
820 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
823 return result;
826 const char *
827 yperr_string (const int error)
829 const char *str;
830 switch (error)
832 case YPERR_SUCCESS:
833 str = N_("Success");
834 break;
835 case YPERR_BADARGS:
836 str = N_("Request arguments bad");
837 break;
838 case YPERR_RPC:
839 str = N_("RPC failure on NIS operation");
840 break;
841 case YPERR_DOMAIN:
842 str = N_("Can't bind to server which serves this domain");
843 break;
844 case YPERR_MAP:
845 str = N_("No such map in server's domain");
846 break;
847 case YPERR_KEY:
848 str = N_("No such key in map");
849 break;
850 case YPERR_YPERR:
851 str = N_("Internal NIS error");
852 break;
853 case YPERR_RESRC:
854 str = N_("Local resource allocation failure");
855 break;
856 case YPERR_NOMORE:
857 str = N_("No more records in map database");
858 break;
859 case YPERR_PMAP:
860 str = N_("Can't communicate with portmapper");
861 break;
862 case YPERR_YPBIND:
863 str = N_("Can't communicate with ypbind");
864 break;
865 case YPERR_YPSERV:
866 str = N_("Can't communicate with ypserv");
867 break;
868 case YPERR_NODOM:
869 str = N_("Local domain name not set");
870 break;
871 case YPERR_BADDB:
872 str = N_("NIS map database is bad");
873 break;
874 case YPERR_VERS:
875 str = N_("NIS client/server version mismatch - can't supply service");
876 break;
877 case YPERR_ACCESS:
878 str = N_("Permission denied");
879 break;
880 case YPERR_BUSY:
881 str = N_("Database is busy");
882 break;
883 default:
884 str = N_("Unknown NIS error code");
885 break;
887 return _(str);
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_def (ypprot_err)
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_def (ypbinderr_string)
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;