2006-03-05 Roland McGrath <roland@frob.com>
[glibc/history.git] / nis / ypclnt.c
blob78adf6aeec19f16c5c33aa757a38e56d8a0af532
1 /* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005
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/uio.h>
32 #include <bits/libc-lock.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 = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
73 UDPTIMEOUT, &ysd->dom_socket);
75 if (ysd->dom_client != NULL)
77 /* If the program exits, close the socket */
78 if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
79 perror ("fcntl: F_SETFD");
83 #if USE_BINDINGDIR
84 static void
85 yp_bind_file (const char *domain, dom_binding *ysd)
87 char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
89 snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
90 int fd = open (path, O_RDONLY);
91 if (fd >= 0)
93 /* We have a binding file and could save a RPC call. The file
94 contains a port number and the YPBIND_RESP record. The port
95 number (16 bits) can be ignored. */
96 struct ypbind_resp ypbr;
98 if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
99 yp_bind_client_create (domain, ysd, &ypbr);
101 close (fd);
104 #endif
106 static int
107 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
109 struct sockaddr_in clnt_saddr;
110 struct ypbind_resp ypbr;
111 int clnt_sock;
112 CLIENT *client;
114 clnt_saddr.sin_family = AF_INET;
115 clnt_saddr.sin_port = 0;
116 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
117 clnt_sock = RPC_ANYSOCK;
118 client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
119 &clnt_sock, 0, 0);
120 if (client == NULL)
121 return YPERR_YPBIND;
123 /* Check the port number -- should be < IPPORT_RESERVED.
124 If not, it's possible someone has registered a bogus
125 ypbind with the portmapper and is trying to trick us. */
126 if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
128 clnt_destroy (client);
129 return YPERR_YPBIND;
132 if (clnt_call (client, YPBINDPROC_DOMAIN,
133 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
134 (xdrproc_t) xdr_ypbind_resp,
135 (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
137 clnt_destroy (client);
138 return YPERR_YPBIND;
141 clnt_destroy (client);
143 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
145 fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
146 ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
147 return YPERR_DOMAIN;
149 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
151 yp_bind_client_create (domain, ysd, &ypbr);
153 return YPERR_SUCCESS;
156 static int
157 __yp_bind (const char *domain, dom_binding **ypdb)
159 dom_binding *ysd = NULL;
160 int is_new = 0;
162 if (domain == NULL || domain[0] == '\0')
163 return YPERR_BADARGS;
165 ysd = *ypdb;
166 while (ysd != NULL)
168 if (strcmp (domain, ysd->dom_domain) == 0)
169 break;
170 ysd = ysd->dom_pnext;
173 if (ysd == NULL)
175 is_new = 1;
176 ysd = (dom_binding *) calloc (1, sizeof *ysd);
177 if (__builtin_expect (ysd == NULL, 0))
178 return YPERR_RESRC;
181 #if USE_BINDINGDIR
182 /* Try binding dir at first if we have no binding */
183 if (ysd->dom_client == NULL)
184 yp_bind_file (domain, ysd);
185 #endif /* USE_BINDINGDIR */
187 if (ysd->dom_client == NULL)
189 int retval = yp_bind_ypbindprog (domain, ysd);
190 if (retval != YPERR_SUCCESS)
192 if (is_new)
193 free (ysd);
194 return retval;
198 if (ysd->dom_client == NULL)
200 if (is_new)
201 free (ysd);
202 return YPERR_YPSERV;
205 if (is_new)
207 ysd->dom_pnext = *ypdb;
208 *ypdb = ysd;
211 return YPERR_SUCCESS;
214 static void
215 __yp_unbind (dom_binding *ydb)
217 clnt_destroy (ydb->dom_client);
218 free (ydb);
222 yp_bind (const char *indomain)
224 int status;
226 __libc_lock_lock (ypbindlist_lock);
228 status = __yp_bind (indomain, &ypbindlist);
230 __libc_lock_unlock (ypbindlist_lock);
232 return status;
234 libnsl_hidden_def (yp_bind)
236 static void
237 yp_unbind_locked (const char *indomain)
239 dom_binding *ydbptr, *ydbptr2;
241 ydbptr2 = NULL;
242 ydbptr = ypbindlist;
244 while (ydbptr != NULL)
246 if (strcmp (ydbptr->dom_domain, indomain) == 0)
248 dom_binding *work;
250 work = ydbptr;
251 if (ydbptr2 == NULL)
252 ypbindlist = ypbindlist->dom_pnext;
253 else
254 ydbptr2 = ydbptr->dom_pnext;
255 __yp_unbind (work);
256 break;
258 ydbptr2 = ydbptr;
259 ydbptr = ydbptr->dom_pnext;
263 void
264 yp_unbind (const char *indomain)
266 __libc_lock_lock (ypbindlist_lock);
268 yp_unbind_locked (indomain);
270 __libc_lock_unlock (ypbindlist_lock);
272 return;
275 static int
276 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
277 caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
278 int print_error)
280 enum clnt_stat result;
282 result = clnt_call ((*ydb)->dom_client, prog,
283 xargs, req, xres, resp, RPCTIMEOUT);
285 if (result != RPC_SUCCESS)
287 /* We don't print an error message, if we try our old,
288 cached data. Only print this for data, which should work. */
289 if (print_error)
290 clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
292 return YPERR_RPC;
295 return YPERR_SUCCESS;
298 static int
299 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
300 caddr_t req, xdrproc_t xres, caddr_t resp)
302 dom_binding *ydb;
303 int status;
304 int saved_errno = errno;
306 status = YPERR_YPERR;
308 __libc_lock_lock (ypbindlist_lock);
309 ydb = ypbindlist;
310 while (ydb != NULL)
312 if (strcmp (domain, ydb->dom_domain) == 0)
314 if (__yp_bind (domain, &ydb) == 0)
316 /* Call server, print no error message, do not unbind. */
317 status = __ypclnt_call (domain, prog, xargs, req, xres,
318 resp, &ydb, 0);
319 if (status == YPERR_SUCCESS)
321 __libc_lock_unlock (ypbindlist_lock);
322 __set_errno (saved_errno);
323 return status;
326 /* We use ypbindlist, and the old cached data is
327 invalid. unbind now and create a new binding */
328 yp_unbind_locked (domain);
330 break;
332 ydb = ydb->dom_pnext;
334 __libc_lock_unlock (ypbindlist_lock);
336 /* First try with cached data failed. Now try to get
337 current data from the system. */
338 ydb = NULL;
339 if (__yp_bind (domain, &ydb) == 0)
341 status = __ypclnt_call (domain, prog, xargs, req, xres,
342 resp, &ydb, 1);
343 __yp_unbind (ydb);
346 #if USE_BINDINGDIR
347 /* If we support binding dir data, we have a third chance:
348 Ask ypbind. */
349 if (status != YPERR_SUCCESS)
351 ydb = calloc (1, sizeof (dom_binding));
352 if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
354 status = __ypclnt_call (domain, prog, xargs, req, xres,
355 resp, &ydb, 1);
356 __yp_unbind (ydb);
358 else
359 free (ydb);
361 #endif
363 __set_errno (saved_errno);
365 return status;
368 /* Like do_ypcall, but translate the status value if necessary. */
369 static int
370 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
371 caddr_t req, xdrproc_t xres, caddr_t resp)
373 int status = do_ypcall (domain, prog, xargs, req, xres, resp);
374 if (status == YPERR_SUCCESS)
375 /* We cast to ypresp_val although the pointer could also be of
376 type ypresp_key_val or ypresp_master or ypresp_order or
377 ypresp_maplist. But the stat element is in a common prefix so
378 this does not matter. */
379 status = ypprot_err (((struct ypresp_val *) resp)->stat);
380 return status;
384 __libc_lock_define_initialized (static, domainname_lock)
387 yp_get_default_domain (char **outdomain)
389 int result = YPERR_SUCCESS;;
390 *outdomain = NULL;
392 __libc_lock_lock (domainname_lock);
394 if (ypdomainname[0] == '\0')
396 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
397 result = YPERR_NODOM;
398 else if (strcmp (ypdomainname, "(none)") == 0)
400 /* If domainname is not set, some systems will return "(none)" */
401 ypdomainname[0] = '\0';
402 result = YPERR_NODOM;
404 else
405 *outdomain = ypdomainname;
407 else
408 *outdomain = ypdomainname;
410 __libc_lock_unlock (domainname_lock);
412 return result;
414 libnsl_hidden_def (yp_get_default_domain)
417 __yp_check (char **domain)
419 char *unused;
421 if (ypdomainname[0] == '\0')
422 if (yp_get_default_domain (&unused))
423 return 0;
425 if (domain)
426 *domain = ypdomainname;
428 if (yp_bind (ypdomainname) == 0)
429 return 1;
430 return 0;
434 yp_match (const char *indomain, const char *inmap, const char *inkey,
435 const int inkeylen, char **outval, int *outvallen)
437 ypreq_key req;
438 ypresp_val resp;
439 enum clnt_stat result;
441 if (indomain == NULL || indomain[0] == '\0' ||
442 inmap == NULL || inmap[0] == '\0' ||
443 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
444 return YPERR_BADARGS;
446 req.domain = (char *) indomain;
447 req.map = (char *) inmap;
448 req.key.keydat_val = (char *) inkey;
449 req.key.keydat_len = inkeylen;
451 *outval = NULL;
452 *outvallen = 0;
453 memset (&resp, '\0', sizeof (resp));
455 result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
456 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
457 (caddr_t) &resp);
459 if (result != YPERR_SUCCESS)
460 return result;
462 *outvallen = resp.val.valdat_len;
463 *outval = malloc (*outvallen + 1);
464 int status = YPERR_RESRC;
465 if (__builtin_expect (*outval != NULL, 1))
467 memcpy (*outval, resp.val.valdat_val, *outvallen);
468 (*outval)[*outvallen] = '\0';
469 status = YPERR_SUCCESS;
472 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
474 return status;
478 yp_first (const char *indomain, const char *inmap, char **outkey,
479 int *outkeylen, char **outval, int *outvallen)
481 ypreq_nokey req;
482 ypresp_key_val resp;
483 enum clnt_stat result;
485 if (indomain == NULL || indomain[0] == '\0' ||
486 inmap == NULL || inmap[0] == '\0')
487 return YPERR_BADARGS;
489 req.domain = (char *) indomain;
490 req.map = (char *) inmap;
492 *outkey = *outval = NULL;
493 *outkeylen = *outvallen = 0;
494 memset (&resp, '\0', sizeof (resp));
496 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
497 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
498 (caddr_t) &resp);
500 if (result != RPC_SUCCESS)
501 return YPERR_RPC;
502 if (resp.stat != YP_TRUE)
503 return ypprot_err (resp.stat);
505 int status;
506 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
507 && (*outval = malloc (resp.val.valdat_len
508 + 1)) != NULL, 1))
510 *outkeylen = resp.key.keydat_len;
511 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
512 (*outkey)[*outkeylen] = '\0';
514 *outvallen = resp.val.valdat_len;
515 memcpy (*outval, resp.val.valdat_val, *outvallen);
516 (*outval)[*outvallen] = '\0';
518 status = YPERR_SUCCESS;
520 else
522 free (*outkey);
523 status = YPERR_RESRC;
526 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
528 return status;
532 yp_next (const char *indomain, const char *inmap, const char *inkey,
533 const int inkeylen, char **outkey, int *outkeylen, char **outval,
534 int *outvallen)
536 ypreq_key req;
537 ypresp_key_val resp;
538 enum clnt_stat result;
540 if (indomain == NULL || indomain[0] == '\0' ||
541 inmap == NULL || inmap[0] == '\0' ||
542 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
543 return YPERR_BADARGS;
545 req.domain = (char *) indomain;
546 req.map = (char *) inmap;
547 req.key.keydat_val = (char *) inkey;
548 req.key.keydat_len = inkeylen;
550 *outkey = *outval = NULL;
551 *outkeylen = *outvallen = 0;
552 memset (&resp, '\0', sizeof (resp));
554 result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
555 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
556 (caddr_t) &resp);
558 if (result != YPERR_SUCCESS)
559 return result;
561 int status;
562 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
563 && (*outval = malloc (resp.val.valdat_len
564 + 1)) != NULL, 1))
566 *outkeylen = resp.key.keydat_len;
567 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
568 (*outkey)[*outkeylen] = '\0';
570 *outvallen = resp.val.valdat_len;
571 memcpy (*outval, resp.val.valdat_val, *outvallen);
572 (*outval)[*outvallen] = '\0';
574 status = YPERR_SUCCESS;
576 else
578 free (*outkey);
579 status = YPERR_RESRC;
582 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
584 return status;
588 yp_master (const char *indomain, const char *inmap, char **outname)
590 ypreq_nokey req;
591 ypresp_master resp;
592 enum clnt_stat result;
594 if (indomain == NULL || indomain[0] == '\0' ||
595 inmap == NULL || inmap[0] == '\0')
596 return YPERR_BADARGS;
598 req.domain = (char *) indomain;
599 req.map = (char *) inmap;
601 memset (&resp, '\0', sizeof (ypresp_master));
603 result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
604 (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
605 (caddr_t) &resp);
607 if (result != YPERR_SUCCESS)
608 return result;
610 *outname = strdup (resp.peer);
611 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
613 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
615 libnsl_hidden_def (yp_master)
618 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
620 struct ypreq_nokey req;
621 struct ypresp_order resp;
622 enum clnt_stat result;
624 if (indomain == NULL || indomain[0] == '\0' ||
625 inmap == NULL || inmap[0] == '\0')
626 return YPERR_BADARGS;
628 req.domain = (char *) indomain;
629 req.map = (char *) inmap;
631 memset (&resp, '\0', sizeof (resp));
633 result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
634 (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
635 (caddr_t) &resp);
637 if (result == YPERR_SUCCESS)
638 return result;
640 *outorder = resp.ordernum;
641 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
643 return result;
646 struct ypresp_all_data
648 unsigned long status;
649 void *data;
650 int (*foreach) (int status, char *key, int keylen,
651 char *val, int vallen, char *data);
654 static bool_t
655 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
657 while (1)
659 struct ypresp_all resp;
661 memset (&resp, '\0', sizeof (struct ypresp_all));
662 if (!xdr_ypresp_all (xdrs, &resp))
664 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
665 objp->status = YP_YPERR;
666 return FALSE;
668 if (resp.more == 0)
670 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
671 objp->status = YP_NOMORE;
672 return TRUE;
675 switch (resp.ypresp_all_u.val.stat)
677 case YP_TRUE:
679 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
680 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
681 int keylen = resp.ypresp_all_u.val.key.keydat_len;
682 int vallen = resp.ypresp_all_u.val.val.valdat_len;
684 /* We are not allowed to modify the key and val data.
685 But we are allowed to add data behind the buffer,
686 if we don't modify the length. So add an extra NUL
687 character to avoid trouble with broken code. */
688 objp->status = YP_TRUE;
689 memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
690 key[keylen] = '\0';
691 memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
692 val[vallen] = '\0';
693 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
694 if ((*objp->foreach) (objp->status, key, keylen,
695 val, vallen, objp->data))
696 return TRUE;
698 break;
699 default:
700 objp->status = resp.ypresp_all_u.val.stat;
701 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
702 /* Sun says we don't need to make this call, but must return
703 immediatly. Since Solaris makes this call, we will call
704 the callback function, too. */
705 (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
706 return TRUE;
712 yp_all (const char *indomain, const char *inmap,
713 const struct ypall_callback *incallback)
715 struct ypreq_nokey req;
716 dom_binding *ydb = NULL;
717 int try, res;
718 enum clnt_stat result;
719 struct sockaddr_in clnt_sin;
720 CLIENT *clnt;
721 struct ypresp_all_data data;
722 int clnt_sock;
723 int saved_errno = errno;
725 if (indomain == NULL || indomain[0] == '\0'
726 || inmap == NULL || inmap[0] == '\0')
727 return YPERR_BADARGS;
729 try = 0;
730 res = YPERR_YPERR;
732 while (try < MAXTRIES && res != YPERR_SUCCESS)
734 if (__yp_bind (indomain, &ydb) != 0)
736 __set_errno (saved_errno);
737 return YPERR_DOMAIN;
740 clnt_sock = RPC_ANYSOCK;
741 clnt_sin = ydb->dom_server_addr;
742 clnt_sin.sin_port = 0;
744 /* We don't need the UDP connection anymore. */
745 __yp_unbind (ydb);
746 ydb = NULL;
748 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
749 if (clnt == NULL)
751 __set_errno (saved_errno);
752 return YPERR_PMAP;
754 req.domain = (char *) indomain;
755 req.map = (char *) inmap;
757 data.foreach = incallback->foreach;
758 data.data = (void *) incallback->data;
760 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
761 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
762 (caddr_t) &data, RPCTIMEOUT);
764 if (__builtin_expect (result != RPC_SUCCESS, 0))
766 /* Print the error message only on the last try. */
767 if (try == MAXTRIES - 1)
768 clnt_perror (clnt, "yp_all: clnt_call");
769 res = YPERR_RPC;
771 else
772 res = YPERR_SUCCESS;
774 clnt_destroy (clnt);
776 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
778 __set_errno (saved_errno);
779 return ypprot_err (data.status);
781 ++try;
784 __set_errno (saved_errno);
786 return res;
791 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
793 struct ypresp_maplist resp;
794 enum clnt_stat result;
796 if (indomain == NULL || indomain[0] == '\0')
797 return YPERR_BADARGS;
799 memset (&resp, '\0', sizeof (resp));
801 result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
802 (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
803 (caddr_t) &resp);
805 if (__builtin_expect (result == YPERR_SUCCESS, 1))
807 *outmaplist = resp.maps;
808 /* We don't free the list, this will be done by ypserv
809 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
812 return result;
815 const char *
816 yperr_string (const int error)
818 const char *str;
819 switch (error)
821 case YPERR_SUCCESS:
822 str = N_("Success");
823 break;
824 case YPERR_BADARGS:
825 str = N_("Request arguments bad");
826 break;
827 case YPERR_RPC:
828 str = N_("RPC failure on NIS operation");
829 break;
830 case YPERR_DOMAIN:
831 str = N_("Can't bind to server which serves this domain");
832 break;
833 case YPERR_MAP:
834 str = N_("No such map in server's domain");
835 break;
836 case YPERR_KEY:
837 str = N_("No such key in map");
838 break;
839 case YPERR_YPERR:
840 str = N_("Internal NIS error");
841 break;
842 case YPERR_RESRC:
843 str = N_("Local resource allocation failure");
844 break;
845 case YPERR_NOMORE:
846 str = N_("No more records in map database");
847 break;
848 case YPERR_PMAP:
849 str = N_("Can't communicate with portmapper");
850 break;
851 case YPERR_YPBIND:
852 str = N_("Can't communicate with ypbind");
853 break;
854 case YPERR_YPSERV:
855 str = N_("Can't communicate with ypserv");
856 break;
857 case YPERR_NODOM:
858 str = N_("Local domain name not set");
859 break;
860 case YPERR_BADDB:
861 str = N_("NIS map database is bad");
862 break;
863 case YPERR_VERS:
864 str = N_("NIS client/server version mismatch - can't supply service");
865 break;
866 case YPERR_ACCESS:
867 str = N_("Permission denied");
868 break;
869 case YPERR_BUSY:
870 str = N_("Database is busy");
871 break;
872 default:
873 str = N_("Unknown NIS error code");
874 break;
876 return _(str);
879 static const int8_t yp_2_yperr[] =
881 #define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
882 YP2YPERR (TRUE, SUCCESS),
883 YP2YPERR (NOMORE, NOMORE),
884 YP2YPERR (FALSE, YPERR),
885 YP2YPERR (NOMAP, MAP),
886 YP2YPERR (NODOM, DOMAIN),
887 YP2YPERR (NOKEY, KEY),
888 YP2YPERR (BADOP, YPERR),
889 YP2YPERR (BADDB, BADDB),
890 YP2YPERR (YPERR, YPERR),
891 YP2YPERR (BADARGS, BADARGS),
892 YP2YPERR (VERS, VERS)
895 ypprot_err (const int code)
897 if (code < YP_VERS || code > YP_NOMORE)
898 return YPERR_YPERR;
899 return yp_2_yperr[code - YP_VERS];
901 libnsl_hidden_def (ypprot_err)
903 const char *
904 ypbinderr_string (const int error)
906 const char *str;
907 switch (error)
909 case 0:
910 str = N_("Success");
911 break;
912 case YPBIND_ERR_ERR:
913 str = N_("Internal ypbind error");
914 break;
915 case YPBIND_ERR_NOSERV:
916 str = N_("Domain not bound");
917 break;
918 case YPBIND_ERR_RESC:
919 str = N_("System resource allocation failure");
920 break;
921 default:
922 str = N_("Unknown ypbind error");
923 break;
925 return _(str);
927 libnsl_hidden_def (ypbinderr_string)
929 #define WINDOW 60
932 yp_update (char *domain, char *map, unsigned ypop,
933 char *key, int keylen, char *data, int datalen)
935 union
937 ypupdate_args update_args;
938 ypdelete_args delete_args;
940 args;
941 xdrproc_t xdr_argument;
942 unsigned res = 0;
943 CLIENT *clnt;
944 char *master;
945 struct sockaddr saddr;
946 char servername[MAXNETNAMELEN + 1];
947 int r;
949 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
950 return YPERR_BADARGS;
952 args.update_args.mapname = map;
953 args.update_args.key.yp_buf_len = keylen;
954 args.update_args.key.yp_buf_val = key;
955 args.update_args.datum.yp_buf_len = datalen;
956 args.update_args.datum.yp_buf_val = data;
958 if ((r = yp_master (domain, map, &master)) != 0)
959 return r;
961 if (!host2netname (servername, master, domain))
963 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
964 return YPERR_YPERR;
967 if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
969 clnt_pcreateerror ("yp_update: clnt_create");
970 return YPERR_RPC;
973 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
975 fputs (_("yp_update: cannot get server address\n"), stderr);
976 return YPERR_RPC;
979 switch (ypop)
981 case YPOP_CHANGE:
982 case YPOP_INSERT:
983 case YPOP_STORE:
984 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
985 break;
986 case YPOP_DELETE:
987 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
988 break;
989 default:
990 return YPERR_BADARGS;
991 break;
994 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
996 if (clnt->cl_auth == NULL)
997 clnt->cl_auth = authunix_create_default ();
999 again:
1000 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
1001 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
1003 if (r == RPC_AUTHERROR)
1005 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1007 auth_destroy (clnt->cl_auth);
1008 clnt->cl_auth = authunix_create_default ();
1009 goto again;
1011 else
1012 return YPERR_ACCESS;
1014 if (r != RPC_SUCCESS)
1016 clnt_perror (clnt, "yp_update: clnt_call");
1017 return YPERR_RPC;
1019 return res;