2005-01-14 GOTO Masanori <gotom@debian.or.jp>
[glibc/history.git] / nis / ypclnt.c
blob6230cb84dcbb9aaf3fe776af3241657598387ddf
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 struct timeval RPCTIMEOUT = {25, 0};
50 static struct timeval UDPTIMEOUT = {5, 0};
51 static int const MAXTRIES = 2;
52 static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
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 memset (&clnt_saddr, '\0', sizeof clnt_saddr);
115 clnt_saddr.sin_family = AF_INET;
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 (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;
369 __libc_lock_define_initialized (static, domainname_lock)
372 yp_get_default_domain (char **outdomain)
374 int result = YPERR_SUCCESS;;
375 *outdomain = NULL;
377 __libc_lock_lock (domainname_lock);
379 if (__ypdomainname[0] == '\0')
381 if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
382 result = YPERR_NODOM;
383 else if (strcmp (__ypdomainname, "(none)") == 0)
385 /* If domainname is not set, some systems will return "(none)" */
386 __ypdomainname[0] = '\0';
387 result = YPERR_NODOM;
389 else
390 *outdomain = __ypdomainname;
392 else
393 *outdomain = __ypdomainname;
395 __libc_lock_unlock (domainname_lock);
397 return result;
399 libnsl_hidden_def (yp_get_default_domain)
402 __yp_check (char **domain)
404 char *unused;
406 if (__ypdomainname[0] == '\0')
407 if (yp_get_default_domain (&unused))
408 return 0;
410 if (domain)
411 *domain = __ypdomainname;
413 if (yp_bind (__ypdomainname) == 0)
414 return 1;
415 return 0;
419 yp_match (const char *indomain, const char *inmap, const char *inkey,
420 const int inkeylen, char **outval, int *outvallen)
422 ypreq_key req;
423 ypresp_val resp;
424 enum clnt_stat result;
426 if (indomain == NULL || indomain[0] == '\0' ||
427 inmap == NULL || inmap[0] == '\0' ||
428 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
429 return YPERR_BADARGS;
431 req.domain = (char *) indomain;
432 req.map = (char *) inmap;
433 req.key.keydat_val = (char *) inkey;
434 req.key.keydat_len = inkeylen;
436 *outval = NULL;
437 *outvallen = 0;
438 memset (&resp, '\0', sizeof (resp));
440 result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
441 (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
442 (caddr_t) & resp);
444 if (result != YPERR_SUCCESS)
445 return result;
446 if (resp.stat != YP_TRUE)
447 return ypprot_err (resp.stat);
449 *outvallen = resp.val.valdat_len;
450 *outval = malloc (*outvallen + 1);
451 if (__builtin_expect (*outval == NULL, 0))
452 return YPERR_RESRC;
453 memcpy (*outval, resp.val.valdat_val, *outvallen);
454 (*outval)[*outvallen] = '\0';
456 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
458 return YPERR_SUCCESS;
462 yp_first (const char *indomain, const char *inmap, char **outkey,
463 int *outkeylen, char **outval, int *outvallen)
465 ypreq_nokey req;
466 ypresp_key_val resp;
467 enum clnt_stat result;
469 if (indomain == NULL || indomain[0] == '\0' ||
470 inmap == NULL || inmap[0] == '\0')
471 return YPERR_BADARGS;
473 req.domain = (char *) indomain;
474 req.map = (char *) inmap;
476 *outkey = *outval = NULL;
477 *outkeylen = *outvallen = 0;
478 memset (&resp, '\0', sizeof (resp));
480 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
481 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
482 (caddr_t) & resp);
484 if (result != RPC_SUCCESS)
485 return YPERR_RPC;
486 if (resp.stat != YP_TRUE)
487 return ypprot_err (resp.stat);
489 *outkeylen = resp.key.keydat_len;
490 *outkey = malloc (*outkeylen + 1);
491 if (__builtin_expect (*outkey == NULL, 0))
492 return YPERR_RESRC;
493 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
494 (*outkey)[*outkeylen] = '\0';
495 *outvallen = resp.val.valdat_len;
496 *outval = malloc (*outvallen + 1);
497 if (__builtin_expect (*outval == NULL, 0))
498 return YPERR_RESRC;
499 memcpy (*outval, resp.val.valdat_val, *outvallen);
500 (*outval)[*outvallen] = '\0';
502 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
504 return YPERR_SUCCESS;
508 yp_next (const char *indomain, const char *inmap, const char *inkey,
509 const int inkeylen, char **outkey, int *outkeylen, char **outval,
510 int *outvallen)
512 ypreq_key req;
513 ypresp_key_val resp;
514 enum clnt_stat result;
516 if (indomain == NULL || indomain[0] == '\0' ||
517 inmap == NULL || inmap[0] == '\0' ||
518 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
519 return YPERR_BADARGS;
521 req.domain = (char *) indomain;
522 req.map = (char *) inmap;
523 req.key.keydat_val = (char *) inkey;
524 req.key.keydat_len = inkeylen;
526 *outkey = *outval = NULL;
527 *outkeylen = *outvallen = 0;
528 memset (&resp, '\0', sizeof (resp));
530 result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
531 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
532 (caddr_t) & resp);
534 if (result != YPERR_SUCCESS)
535 return result;
536 if (resp.stat != YP_TRUE)
537 return ypprot_err (resp.stat);
539 *outkeylen = resp.key.keydat_len;
540 *outkey = malloc (*outkeylen + 1);
541 if (__builtin_expect (*outkey == NULL, 0))
542 return YPERR_RESRC;
543 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
544 (*outkey)[*outkeylen] = '\0';
545 *outvallen = resp.val.valdat_len;
546 *outval = malloc (*outvallen + 1);
547 if (__builtin_expect (*outval == NULL, 0))
548 return YPERR_RESRC;
549 memcpy (*outval, resp.val.valdat_val, *outvallen);
550 (*outval)[*outvallen] = '\0';
552 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
554 return YPERR_SUCCESS;
558 yp_master (const char *indomain, const char *inmap, char **outname)
560 ypreq_nokey req;
561 ypresp_master resp;
562 enum clnt_stat result;
564 if (indomain == NULL || indomain[0] == '\0' ||
565 inmap == NULL || inmap[0] == '\0')
566 return YPERR_BADARGS;
568 req.domain = (char *) indomain;
569 req.map = (char *) inmap;
571 memset (&resp, '\0', sizeof (ypresp_master));
573 result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
574 (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
576 if (result != YPERR_SUCCESS)
577 return result;
578 if (resp.stat != YP_TRUE)
579 return ypprot_err (resp.stat);
581 *outname = strdup (resp.peer);
582 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
584 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
586 libnsl_hidden_def (yp_master)
589 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
591 struct ypreq_nokey req;
592 struct ypresp_order resp;
593 enum clnt_stat result;
595 if (indomain == NULL || indomain[0] == '\0' ||
596 inmap == NULL || inmap == '\0')
597 return YPERR_BADARGS;
599 req.domain = (char *) indomain;
600 req.map = (char *) inmap;
602 memset (&resp, '\0', sizeof (resp));
604 result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
605 (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
607 if (result != YPERR_SUCCESS)
608 return result;
609 if (resp.stat != YP_TRUE)
610 return ypprot_err (resp.stat);
612 *outorder = resp.ordernum;
613 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
615 return YPERR_SUCCESS;
618 struct ypresp_all_data
620 unsigned long status;
621 void *data;
622 int (*foreach) (int status, char *key, int keylen,
623 char *val, int vallen, char *data);
626 static bool_t
627 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
629 while (1)
631 struct ypresp_all resp;
633 memset (&resp, '\0', sizeof (struct ypresp_all));
634 if (!xdr_ypresp_all (xdrs, &resp))
636 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
637 objp->status = YP_YPERR;
638 return FALSE;
640 if (resp.more == 0)
642 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
643 objp->status = YP_NOMORE;
644 return TRUE;
647 switch (resp.ypresp_all_u.val.stat)
649 case YP_TRUE:
651 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
652 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
653 int keylen = resp.ypresp_all_u.val.key.keydat_len;
654 int vallen = resp.ypresp_all_u.val.val.valdat_len;
656 /* We are not allowed to modify the key and val data.
657 But we are allowed to add data behind the buffer,
658 if we don't modify the length. So add an extra NUL
659 character to avoid trouble with broken code. */
660 objp->status = YP_TRUE;
661 memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
662 key[keylen] = '\0';
663 memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
664 val[vallen] = '\0';
665 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
666 if ((*objp->foreach) (objp->status, key, keylen,
667 val, vallen, objp->data))
668 return TRUE;
670 break;
671 default:
672 objp->status = resp.ypresp_all_u.val.stat;
673 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
674 /* Sun says we don't need to make this call, but must return
675 immediatly. Since Solaris makes this call, we will call
676 the callback function, too. */
677 (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
678 return TRUE;
684 yp_all (const char *indomain, const char *inmap,
685 const struct ypall_callback *incallback)
687 struct ypreq_nokey req;
688 dom_binding *ydb = NULL;
689 int try, res;
690 enum clnt_stat result;
691 struct sockaddr_in clnt_sin;
692 CLIENT *clnt;
693 struct ypresp_all_data data;
694 int clnt_sock;
695 int saved_errno = errno;
697 if (indomain == NULL || indomain[0] == '\0' ||
698 inmap == NULL || inmap == '\0')
699 return YPERR_BADARGS;
701 try = 0;
702 res = YPERR_YPERR;
704 while (try < MAXTRIES && res != YPERR_SUCCESS)
706 if (__yp_bind (indomain, &ydb) != 0)
708 __set_errno (saved_errno);
709 return YPERR_DOMAIN;
712 clnt_sock = RPC_ANYSOCK;
713 clnt_sin = ydb->dom_server_addr;
714 clnt_sin.sin_port = 0;
716 /* We don't need the UDP connection anymore. */
717 __yp_unbind (ydb);
718 ydb = NULL;
720 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
721 if (clnt == NULL)
723 __set_errno (saved_errno);
724 return YPERR_PMAP;
726 req.domain = (char *) indomain;
727 req.map = (char *) inmap;
729 data.foreach = incallback->foreach;
730 data.data = (void *) incallback->data;
732 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
733 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
734 (caddr_t) &data, RPCTIMEOUT);
736 if (result != RPC_SUCCESS)
738 /* Print the error message only on the last try */
739 if (try == MAXTRIES - 1)
740 clnt_perror (clnt, "yp_all: clnt_call");
741 res = YPERR_RPC;
743 else
744 res = YPERR_SUCCESS;
746 clnt_destroy (clnt);
748 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
750 __set_errno (saved_errno);
751 return ypprot_err (data.status);
753 ++try;
756 __set_errno (saved_errno);
758 return res;
762 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
764 struct ypresp_maplist resp;
765 enum clnt_stat result;
767 if (indomain == NULL || indomain[0] == '\0')
768 return YPERR_BADARGS;
770 memset (&resp, '\0', sizeof (resp));
772 result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
773 (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
775 if (result != YPERR_SUCCESS)
776 return result;
777 if (resp.stat != YP_TRUE)
778 return ypprot_err (resp.stat);
780 *outmaplist = resp.maps;
781 /* We give the list not free, this will be done by ypserv
782 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
784 return YPERR_SUCCESS;
787 const char *
788 yperr_string (const int error)
790 switch (error)
792 case YPERR_SUCCESS:
793 return _("Success");
794 case YPERR_BADARGS:
795 return _("Request arguments bad");
796 case YPERR_RPC:
797 return _("RPC failure on NIS operation");
798 case YPERR_DOMAIN:
799 return _("Can't bind to server which serves this domain");
800 case YPERR_MAP:
801 return _("No such map in server's domain");
802 case YPERR_KEY:
803 return _("No such key in map");
804 case YPERR_YPERR:
805 return _("Internal NIS error");
806 case YPERR_RESRC:
807 return _("Local resource allocation failure");
808 case YPERR_NOMORE:
809 return _("No more records in map database");
810 case YPERR_PMAP:
811 return _("Can't communicate with portmapper");
812 case YPERR_YPBIND:
813 return _("Can't communicate with ypbind");
814 case YPERR_YPSERV:
815 return _("Can't communicate with ypserv");
816 case YPERR_NODOM:
817 return _("Local domain name not set");
818 case YPERR_BADDB:
819 return _("NIS map database is bad");
820 case YPERR_VERS:
821 return _("NIS client/server version mismatch - can't supply service");
822 case YPERR_ACCESS:
823 return _("Permission denied");
824 case YPERR_BUSY:
825 return _("Database is busy");
827 return _("Unknown NIS error code");
830 static const int8_t yp_2_yperr[] =
832 #define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
833 YP2YPERR (TRUE, SUCCESS),
834 YP2YPERR (NOMORE, NOMORE),
835 YP2YPERR (FALSE, YPERR),
836 YP2YPERR (NOMAP, MAP),
837 YP2YPERR (NODOM, DOMAIN),
838 YP2YPERR (NOKEY, KEY),
839 YP2YPERR (BADOP, YPERR),
840 YP2YPERR (BADDB, BADDB),
841 YP2YPERR (YPERR, YPERR),
842 YP2YPERR (BADARGS, BADARGS),
843 YP2YPERR (VERS, VERS)
846 ypprot_err (const int code)
848 if (code < YP_VERS || code > YP_NOMORE)
849 return YPERR_YPERR;
850 return yp_2_yperr[code - YP_VERS];
852 libnsl_hidden_def (ypprot_err)
854 const char *
855 ypbinderr_string (const int error)
857 switch (error)
859 case 0:
860 return _("Success");
861 case YPBIND_ERR_ERR:
862 return _("Internal ypbind error");
863 case YPBIND_ERR_NOSERV:
864 return _("Domain not bound");
865 case YPBIND_ERR_RESC:
866 return _("System resource allocation failure");
867 default:
868 return _("Unknown ypbind error");
871 libnsl_hidden_def (ypbinderr_string)
873 #define WINDOW 60
876 yp_update (char *domain, char *map, unsigned ypop,
877 char *key, int keylen, char *data, int datalen)
879 union
881 ypupdate_args update_args;
882 ypdelete_args delete_args;
884 args;
885 xdrproc_t xdr_argument;
886 unsigned res = 0;
887 CLIENT *clnt;
888 char *master;
889 struct sockaddr saddr;
890 char servername[MAXNETNAMELEN + 1];
891 int r;
893 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
894 return YPERR_BADARGS;
896 args.update_args.mapname = map;
897 args.update_args.key.yp_buf_len = keylen;
898 args.update_args.key.yp_buf_val = key;
899 args.update_args.datum.yp_buf_len = datalen;
900 args.update_args.datum.yp_buf_val = data;
902 if ((r = yp_master (domain, map, &master)) != 0)
903 return r;
905 if (!host2netname (servername, master, domain))
907 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
908 return YPERR_YPERR;
911 if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
913 clnt_pcreateerror ("yp_update: clnt_create");
914 return YPERR_RPC;
917 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
919 fputs (_("yp_update: cannot get server address\n"), stderr);
920 return YPERR_RPC;
923 switch (ypop)
925 case YPOP_CHANGE:
926 case YPOP_INSERT:
927 case YPOP_STORE:
928 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
929 break;
930 case YPOP_DELETE:
931 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
932 break;
933 default:
934 return YPERR_BADARGS;
935 break;
938 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
940 if (clnt->cl_auth == NULL)
941 clnt->cl_auth = authunix_create_default ();
943 again:
944 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
945 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
947 if (r == RPC_AUTHERROR)
949 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
951 clnt->cl_auth = authunix_create_default ();
952 goto again;
954 else
955 return YPERR_ACCESS;
957 if (r != RPC_SUCCESS)
959 clnt_perror (clnt, "yp_update: clnt_call");
960 return YPERR_RPC;
962 return res;