1 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.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 Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 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 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
24 #include <rpcsvc/nis.h>
25 #include <rpcsvc/yp.h>
26 #include <rpcsvc/ypclnt.h>
27 #include <rpcsvc/ypupd.h>
29 #include <bits/libc-lock.h>
31 /* This should only be defined on systems with a BSD compatible ypbind */
33 # define BINDINGDIR "/var/yp/binding"
38 struct dom_binding *dom_pnext;
39 char dom_domain[YPMAXDOMAIN + 1];
40 struct sockaddr_in dom_server_addr;
45 typedef struct dom_binding dom_binding;
47 static struct timeval RPCTIMEOUT = {25, 0};
48 static struct timeval UDPTIMEOUT = {5, 0};
49 static int const MAXTRIES = 5;
50 static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
51 __libc_lock_define_initialized (static, ypbindlist_lock)
52 static dom_binding *__ypbindlist = NULL;
56 __yp_bind (const char *domain, dom_binding **ypdb)
58 struct sockaddr_in clnt_saddr;
59 struct ypbind_resp ypbr;
60 dom_binding *ysd = NULL;
66 if ((domain == NULL) || (strlen (domain) == 0))
74 if (strcmp (domain, ysd->dom_domain) == 0)
83 ysd = (dom_binding *) calloc (1, sizeof *ysd);
101 if (ysd->dom_vers < 1)
103 char path[sizeof (BINDINGDIR) - 1 + strlen (domain) + 10];
108 sprintf (path, "%s/%s.%ld", BINDINGDIR, domain, YPBINDVERS);
109 fd = open (path, O_RDONLY);
112 /* We have a binding file and could save a RPC call */
113 vec[0].iov_base = &port;
114 vec[0].iov_len = sizeof (port);
115 vec[1].iov_base = &ypbr;
116 vec[1].iov_len = sizeof (ypbr);
118 if (readv (fd, vec, 2) == vec[0].iov_len + vec[1].iov_len)
120 memset (&ysd->dom_server_addr, '\0',
121 sizeof ysd->dom_server_addr);
122 ysd->dom_server_addr.sin_family = AF_INET;
123 memcpy (&ysd->dom_server_addr.sin_port,
124 ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
125 sizeof (ysd->dom_server_addr.sin_port));
126 memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
127 ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
128 sizeof (ysd->dom_server_addr.sin_addr.s_addr));
129 ysd->dom_vers = YPVERS;
130 strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
131 ysd->dom_domain[YPMAXDOMAIN] = '\0';
136 #endif /* USE_BINDINGDIR */
138 if (ysd->dom_vers == -1)
142 clnt_destroy(ysd->dom_client);
143 ysd->dom_client = NULL;
144 ysd->dom_socket = -1;
146 memset (&clnt_saddr, '\0', sizeof clnt_saddr);
147 clnt_saddr.sin_family = AF_INET;
148 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
149 clnt_sock = RPC_ANYSOCK;
150 client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
159 ** Check the port number -- should be < IPPORT_RESERVED.
160 ** If not, it's possible someone has registered a bogus
161 ** ypbind with the portmapper and is trying to trick us.
163 if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
165 clnt_destroy (client);
171 if (clnt_call (client, YPBINDPROC_DOMAIN,
172 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
173 (xdrproc_t) xdr_ypbind_resp,
174 (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
176 clnt_destroy (client);
183 clnt_destroy (client);
186 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
188 fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
189 ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
194 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
195 ysd->dom_server_addr.sin_family = AF_INET;
196 memcpy (&ysd->dom_server_addr.sin_port,
197 ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
198 sizeof (ysd->dom_server_addr.sin_port));
199 memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
200 ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
201 sizeof (ysd->dom_server_addr.sin_addr.s_addr));
202 ysd->dom_vers = YPVERS;
203 strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
204 ysd->dom_domain[YPMAXDOMAIN] = '\0';
209 clnt_destroy (ysd->dom_client);
210 close (ysd->dom_socket);
212 ysd->dom_socket = RPC_ANYSOCK;
213 ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
214 UDPTIMEOUT, &ysd->dom_socket);
215 if (ysd->dom_client == NULL)
219 while (ysd->dom_client == NULL);
221 /* If the program exists, close the socket */
222 if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
223 perror (_("fcntl: F_SETFD"));
225 if (is_new && ypdb != NULL)
227 ysd->dom_pnext = *ypdb;
231 return YPERR_SUCCESS;
235 __yp_unbind (dom_binding *ydb)
237 clnt_destroy (ydb->dom_client);
238 ydb->dom_client = NULL;
239 ydb->dom_socket = -1;
243 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
244 caddr_t req, xdrproc_t xres, caddr_t resp)
246 dom_binding *ydb = NULL;
247 bool_t use_ypbindlist = FALSE;
251 result = YPERR_YPERR;
253 __libc_lock_lock (ypbindlist_lock);
254 if (__ypbindlist != NULL)
259 if (strcmp (domain, ydb->dom_domain) == 0)
261 ydb = ydb->dom_pnext;
264 use_ypbindlist = TRUE;
266 __libc_lock_unlock (ypbindlist_lock);
269 __libc_lock_unlock (ypbindlist_lock);
271 while (try < MAXTRIES && result != RPC_SUCCESS)
273 if (__yp_bind (domain, &ydb) != 0)
276 __libc_lock_unlock (ypbindlist_lock);
280 result = clnt_call (ydb->dom_client, prog,
281 xargs, req, xres, resp, RPCTIMEOUT);
283 if (result != RPC_SUCCESS)
285 clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
299 __libc_lock_unlock (ypbindlist_lock);
300 use_ypbindlist = FALSE;
314 yp_bind (const char *indomain)
318 __libc_lock_lock (ypbindlist_lock);
320 status = __yp_bind (indomain, &__ypbindlist);
322 __libc_lock_unlock (ypbindlist_lock);
328 yp_unbind (const char *indomain)
330 dom_binding *ydbptr, *ydbptr2;
332 __libc_lock_lock (ypbindlist_lock);
335 ydbptr = __ypbindlist;
336 while (ydbptr != NULL)
338 if (strcmp (ydbptr->dom_domain, indomain) == 0)
344 __ypbindlist = __ypbindlist->dom_pnext;
346 ydbptr2 = ydbptr->dom_pnext;
352 ydbptr = ydbptr->dom_pnext;
355 __libc_lock_unlock (ypbindlist_lock);
360 __libc_lock_define_initialized (static, domainname_lock)
363 yp_get_default_domain (char **outdomain)
365 int result = YPERR_SUCCESS;;
368 __libc_lock_lock (domainname_lock);
370 if (__ypdomainname[0] == '\0')
372 if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
373 result = YPERR_NODOM;
375 *outdomain = __ypdomainname;
378 *outdomain = __ypdomainname;
380 __libc_lock_unlock (domainname_lock);
386 __yp_check (char **domain)
390 if (__ypdomainname[0] == '\0')
391 if (yp_get_default_domain (&unused))
393 else if (strcmp (__ypdomainname, "(none)") == 0)
397 *domain = __ypdomainname;
399 if (yp_bind (__ypdomainname) == 0)
405 yp_match (const char *indomain, const char *inmap, const char *inkey,
406 const int inkeylen, char **outval, int *outvallen)
412 if (indomain == NULL || indomain[0] == '\0' ||
413 inmap == NULL || inmap[0] == '\0' ||
414 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
415 return YPERR_BADARGS;
417 req.domain = (char *) indomain;
418 req.map = (char *) inmap;
419 req.key.keydat_val = (char *) inkey;
420 req.key.keydat_len = inkeylen;
424 memset (&resp, '\0', sizeof (resp));
426 result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
427 (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
430 if (result != RPC_SUCCESS)
432 if (resp.stat != YP_TRUE)
433 return ypprot_err (resp.stat);
435 *outvallen = resp.val.valdat_len;
436 *outval = malloc (*outvallen + 1);
437 memcpy (*outval, resp.val.valdat_val, *outvallen);
438 (*outval)[*outvallen] = '\0';
440 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
442 return YPERR_SUCCESS;
446 yp_first (const char *indomain, const char *inmap, char **outkey,
447 int *outkeylen, char **outval, int *outvallen)
453 if (indomain == NULL || indomain[0] == '\0' ||
454 inmap == NULL || inmap[0] == '\0')
455 return YPERR_BADARGS;
457 req.domain = (char *) indomain;
458 req.map = (char *) inmap;
460 *outkey = *outval = NULL;
461 *outkeylen = *outvallen = 0;
462 memset (&resp, '\0', sizeof (resp));
464 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
465 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
468 if (result != RPC_SUCCESS)
470 if (resp.stat != YP_TRUE)
471 return ypprot_err (resp.stat);
473 *outkeylen = resp.key.keydat_len;
474 *outkey = malloc (*outkeylen + 1);
475 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
476 (*outkey)[*outkeylen] = '\0';
477 *outvallen = resp.val.valdat_len;
478 *outval = malloc (*outvallen + 1);
479 memcpy (*outval, resp.val.valdat_val, *outvallen);
480 (*outval)[*outvallen] = '\0';
482 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
484 return YPERR_SUCCESS;
488 yp_next (const char *indomain, const char *inmap, const char *inkey,
489 const int inkeylen, char **outkey, int *outkeylen, char **outval,
496 if (indomain == NULL || indomain[0] == '\0' ||
497 inmap == NULL || inmap[0] == '\0' ||
498 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
499 return YPERR_BADARGS;
501 req.domain = (char *) indomain;
502 req.map = (char *) inmap;
503 req.key.keydat_val = (char *) inkey;
504 req.key.keydat_len = inkeylen;
506 *outkey = *outval = NULL;
507 *outkeylen = *outvallen = 0;
508 memset (&resp, '\0', sizeof (resp));
510 result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
511 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
514 if (result != RPC_SUCCESS)
516 if (resp.stat != YP_TRUE)
517 return ypprot_err (resp.stat);
519 *outkeylen = resp.key.keydat_len;
520 *outkey = malloc (*outkeylen + 1);
521 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
522 (*outkey)[*outkeylen] = '\0';
523 *outvallen = resp.val.valdat_len;
524 *outval = malloc (*outvallen + 1);
525 memcpy (*outval, resp.val.valdat_val, *outvallen);
526 (*outval)[*outvallen] = '\0';
528 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
530 return YPERR_SUCCESS;
534 yp_master (const char *indomain, const char *inmap, char **outname)
540 if (indomain == NULL || indomain[0] == '\0' ||
541 inmap == NULL || inmap[0] == '\0')
542 return YPERR_BADARGS;
544 req.domain = (char *) indomain;
545 req.map = (char *) inmap;
547 memset (&resp, '\0', sizeof (ypresp_master));
549 result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
550 (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
552 if (result != RPC_SUCCESS)
554 if (resp.stat != YP_TRUE)
555 return ypprot_err (resp.stat);
557 *outname = strdup (resp.peer);
558 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
560 return YPERR_SUCCESS;
564 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
566 struct ypreq_nokey req;
567 struct ypresp_order resp;
570 if (indomain == NULL || indomain[0] == '\0' ||
571 inmap == NULL || inmap == '\0')
572 return YPERR_BADARGS;
574 req.domain = (char *) indomain;
575 req.map = (char *) inmap;
577 memset (&resp, '\0', sizeof (resp));
579 result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
580 (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
582 if (result != RPC_SUCCESS)
584 if (resp.stat != YP_TRUE)
585 return ypprot_err (resp.stat);
587 *outorder = resp.ordernum;
588 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
590 return YPERR_SUCCESS;
593 static void *ypall_data;
594 static int (*ypall_foreach) __P ((int status, char *key, int keylen,
595 char *val, int vallen, char *data));
598 __xdr_ypresp_all (XDR * xdrs, u_long * objp)
602 struct ypresp_all resp;
604 memset (&resp, '\0', sizeof (struct ypresp_all));
605 if (!xdr_ypresp_all (xdrs, &resp))
607 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
613 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
618 switch (resp.ypresp_all_u.val.stat)
622 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
623 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
624 int keylen = resp.ypresp_all_u.val.key.keydat_len;
625 int vallen = resp.ypresp_all_u.val.val.valdat_len;
628 memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
630 memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
632 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
633 if ((*ypall_foreach) (*objp, key, keylen,
634 val, vallen, ypall_data))
640 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
644 *objp = resp.ypresp_all_u.val.stat;
645 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
652 yp_all (const char *indomain, const char *inmap,
653 const struct ypall_callback *incallback)
655 struct ypreq_nokey req;
656 dom_binding *ydb = NULL;
658 struct sockaddr_in clnt_sin;
660 unsigned long status;
663 if (indomain == NULL || indomain[0] == '\0' ||
664 inmap == NULL || inmap == '\0')
665 return YPERR_BADARGS;
668 result = YPERR_YPERR;
670 while (try < MAXTRIES && result != RPC_SUCCESS)
672 if (__yp_bind (indomain, &ydb) != 0)
677 /* YPPROC_ALL get its own TCP channel to ypserv */
678 clnt_sock = RPC_ANYSOCK;
679 clnt_sin = ydb->dom_server_addr;
680 clnt_sin.sin_port = 0;
681 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
684 req.domain = (char *) indomain;
685 req.map = (char *) inmap;
687 ypall_foreach = incallback->foreach;
688 ypall_data = (void *) incallback->data;
690 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
691 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
692 (caddr_t) &status, RPCTIMEOUT);
696 if (result != RPC_SUCCESS)
698 clnt_perror (ydb->dom_client, "yp_all: clnt_call");
704 result = YPERR_SUCCESS;
706 if (status != YP_NOMORE)
707 return ypprot_err (status);
715 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
717 struct ypresp_maplist resp;
720 if (indomain == NULL || indomain[0] == '\0')
721 return YPERR_BADARGS;
723 memset (&resp, '\0', sizeof (resp));
725 result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
726 (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
728 if (result != RPC_SUCCESS)
730 if (resp.stat != YP_TRUE)
731 return ypprot_err (resp.stat);
733 *outmaplist = resp.maps;
734 /* We give the list not free, this will be done by ypserv
735 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
737 return YPERR_SUCCESS;
741 yperr_string (const int error)
748 return _("Request arguments bad");
750 return _("RPC failure on NIS operation");
752 return _("Can't bind to server which serves this domain");
754 return _("No such map in server's domain");
756 return _("No such key in map");
758 return _("Internal NIS error");
760 return _("Local resource allocation failure");
762 return _("No more records in map database");
764 return _("Can't communicate with portmapper");
766 return _("Can't communicate with ypbind");
768 return _("Can't communicate with ypserv");
770 return _("Local domain name not set");
772 return _("NIS map database is bad");
774 return _("NIS client/server version mismatch - can't supply service");
776 return _("Permission denied");
778 return _("Database is busy");
780 return _("Unknown NIS error code");
784 ypprot_err (const int code)
789 return YPERR_SUCCESS;
807 return YPERR_BADARGS;
815 ypbinderr_string (const int error)
822 return _("Internal ypbind error");
823 case YPBIND_ERR_NOSERV:
824 return _("Domain not bound");
825 case YPBIND_ERR_RESC:
826 return _("System resource allocation failure");
828 return _("Unknown ypbind error");
836 yp_update (char *domain, char *map, unsigned ypop,
837 char *key, int keylen, char *data, int datalen)
841 ypupdate_args update_args;
842 ypdelete_args delete_args;
845 xdrproc_t xdr_argument;
849 struct sockaddr saddr;
850 char servername[MAXNETNAMELEN + 1];
853 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
854 return YPERR_BADARGS;
856 args.update_args.mapname = map;
857 args.update_args.key.yp_buf_len = keylen;
858 args.update_args.key.yp_buf_val = key;
859 args.update_args.datum.yp_buf_len = datalen;
860 args.update_args.datum.yp_buf_val = data;
862 if ((r = yp_master (domain, map, &master)) != 0)
865 if (!host2netname (servername, master, domain))
867 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
871 if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
873 clnt_pcreateerror ("yp_update: clnt_create");
877 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
879 fputs (_("yp_update: cannot get server address\n"), stderr);
888 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
891 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
894 return YPERR_BADARGS;
898 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
900 if (clnt->cl_auth == NULL)
901 clnt->cl_auth = authunix_create_default ();
904 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
905 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
907 if (r == RPC_AUTHERROR)
909 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
911 clnt->cl_auth = authunix_create_default ();
917 if (r != RPC_SUCCESS)
919 clnt_perror (clnt, "yp_update: clnt_call");