1 /* Copyright (C) 1996, 1997 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. */
23 #include <bits/libc-lock.h>
26 #include <rpcsvc/nis.h>
27 #include <rpcsvc/yp.h>
28 #include <rpcsvc/ypclnt.h>
29 #include <rpcsvc/ypupd.h>
33 struct dom_binding *dom_pnext;
34 char dom_domain[YPMAXDOMAIN + 1];
35 struct sockaddr_in dom_server_addr;
40 typedef struct dom_binding dom_binding;
42 static struct timeval TIMEOUT = {25, 0};
43 static int const MAXTRIES = 5;
44 static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
45 __libc_lock_define_initialized (static, ypbindlist_lock)
46 static dom_binding *__ypbindlist = NULL;
50 __yp_bind (const char *domain, dom_binding ** ypdb)
52 struct sockaddr_in clnt_saddr;
53 struct ypbind_resp ypbr;
63 if ((domain == NULL) || (strlen (domain) == 0))
69 if (strcmp (domain, ysd->dom_domain) == 0)
77 ysd = (dom_binding *) malloc (sizeof *ysd);
78 memset (ysd, '\0', sizeof *ysd);
95 if (ysd->dom_vers == -1)
99 clnt_destroy(ysd->dom_client);
100 ysd->dom_client = NULL;
101 ysd->dom_socket = -1;
103 memset (&clnt_saddr, '\0', sizeof clnt_saddr);
104 clnt_saddr.sin_family = AF_INET;
105 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
106 clnt_sock = RPC_ANYSOCK;
107 client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
116 ** Check the port number -- should be < IPPORT_RESERVED.
117 ** If not, it's possible someone has registered a bogus
118 ** ypbind with the portmapper and is trying to trick us.
120 if (ntohs(clnt_saddr.sin_port) >= IPPORT_RESERVED)
122 clnt_destroy(client);
125 return(YPERR_YPBIND);
128 if (clnt_call (client, YPBINDPROC_DOMAIN,
129 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
130 (xdrproc_t) xdr_ypbind_resp,
131 (caddr_t) &ypbr, TIMEOUT) != RPC_SUCCESS)
133 clnt_destroy (client);
140 clnt_destroy (client);
143 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
145 switch (ypbr.ypbind_resp_u.ypbind_error)
148 fputs (_("YPBINDPROC_DOMAIN: Internal error\n"), stderr);
150 case YPBIND_ERR_NOSERV:
152 _("YPBINDPROC_DOMAIN: No server for domain %s\n"),
155 case YPBIND_ERR_RESC:
156 fputs (_("YPBINDPROC_DOMAIN: Resource allocation failure\n"),
160 fputs (_("YPBINDPROC_DOMAIN: Unknown error\n"), stderr);
167 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
168 ysd->dom_server_addr.sin_family = AF_INET;
169 memcpy (&ysd->dom_server_addr.sin_port,
170 ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
171 sizeof (ysd->dom_server_addr.sin_port));
172 memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
173 ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
174 sizeof (ysd->dom_server_addr.sin_addr.s_addr));
175 ysd->dom_vers = YPVERS;
176 strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
177 ysd->dom_domain[YPMAXDOMAIN] = '\0';
182 clnt_destroy (ysd->dom_client);
183 close (ysd->dom_socket);
185 ysd->dom_socket = RPC_ANYSOCK;
186 ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
187 TIMEOUT, &ysd->dom_socket);
188 if (ysd->dom_client == NULL)
192 while (ysd->dom_client == NULL);
194 /* If the program exists, close the socket */
195 if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
196 perror (_("fcntl: F_SETFD"));
200 ysd->dom_pnext = __ypbindlist;
207 return YPERR_SUCCESS;
211 __yp_unbind (dom_binding *ydb)
213 clnt_destroy (ydb->dom_client);
214 ydb->dom_client = NULL;
215 ydb->dom_socket = -1;
219 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
220 caddr_t req, xdrproc_t xres, caddr_t resp)
222 dom_binding *ydb = NULL;
226 result = YPERR_YPERR;
228 while (try < MAXTRIES && result != RPC_SUCCESS)
230 __libc_lock_lock (ypbindlist_lock);
232 if (__yp_bind (domain, &ydb) != 0)
234 __libc_lock_unlock (ypbindlist_lock);
238 result = clnt_call (ydb->dom_client, prog,
239 xargs, req, xres, resp, TIMEOUT);
241 if (result != RPC_SUCCESS)
243 clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
249 __libc_lock_unlock (ypbindlist_lock);
258 yp_bind (const char *indomain)
262 __libc_lock_lock (ypbindlist_lock);
264 status = __yp_bind (indomain, NULL);
266 __libc_lock_unlock (ypbindlist_lock);
272 yp_unbind (const char *indomain)
274 dom_binding *ydbptr, *ydbptr2;
276 __libc_lock_lock (ypbindlist_lock);
279 ydbptr = __ypbindlist;
280 while (ydbptr != NULL)
282 if (strcmp (ydbptr->dom_domain, indomain) == 0)
288 __ypbindlist = __ypbindlist->dom_pnext;
290 ydbptr2 = ydbptr->dom_pnext;
296 ydbptr = ydbptr->dom_pnext;
299 __libc_lock_unlock (ypbindlist_lock);
304 __libc_lock_define_initialized (static, domainname_lock)
307 yp_get_default_domain (char **outdomain)
309 int result = YPERR_SUCCESS;;
312 __libc_lock_lock (domainname_lock);
314 if (__ypdomainname[0] == '\0')
316 if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
317 result = YPERR_NODOM;
319 *outdomain = __ypdomainname;
322 *outdomain = __ypdomainname;
324 __libc_lock_unlock (domainname_lock);
330 __yp_check (char **domain)
334 if (__ypdomainname[0] == '\0')
335 if (yp_get_default_domain (&unused))
337 else if (strcmp (__ypdomainname, "(none)") == 0)
341 *domain = __ypdomainname;
343 if (yp_bind (__ypdomainname) == 0)
349 yp_match (const char *indomain, const char *inmap, const char *inkey,
350 const int inkeylen, char **outval, int *outvallen)
356 if (indomain == NULL || indomain[0] == '\0' ||
357 inmap == NULL || inmap[0] == '\0' ||
358 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
359 return YPERR_BADARGS;
361 req.domain = (char *) indomain;
362 req.map = (char *) inmap;
363 req.key.keydat_val = (char *) inkey;
364 req.key.keydat_len = inkeylen;
368 memset (&resp, '\0', sizeof (resp));
370 result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
371 (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
374 if (result != RPC_SUCCESS)
376 if (resp.stat != YP_TRUE)
377 return ypprot_err (resp.stat);
379 *outvallen = resp.val.valdat_len;
380 *outval = malloc (*outvallen + 1);
381 memcpy (*outval, resp.val.valdat_val, *outvallen);
382 (*outval)[*outvallen] = '\0';
384 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
386 return YPERR_SUCCESS;
390 yp_first (const char *indomain, const char *inmap, char **outkey,
391 int *outkeylen, char **outval, int *outvallen)
397 if (indomain == NULL || indomain[0] == '\0' ||
398 inmap == NULL || inmap[0] == '\0')
399 return YPERR_BADARGS;
401 req.domain = (char *) indomain;
402 req.map = (char *) inmap;
404 *outkey = *outval = NULL;
405 *outkeylen = *outvallen = 0;
406 memset (&resp, '\0', sizeof (resp));
408 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
409 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
412 if (result != RPC_SUCCESS)
414 if (resp.stat != YP_TRUE)
415 return ypprot_err (resp.stat);
417 *outkeylen = resp.key.keydat_len;
418 *outkey = malloc (*outkeylen + 1);
419 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
420 (*outkey)[*outkeylen] = '\0';
421 *outvallen = resp.val.valdat_len;
422 *outval = malloc (*outvallen + 1);
423 memcpy (*outval, resp.val.valdat_val, *outvallen);
424 (*outval)[*outvallen] = '\0';
426 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
428 return YPERR_SUCCESS;
432 yp_next (const char *indomain, const char *inmap, const char *inkey,
433 const int inkeylen, char **outkey, int *outkeylen, char **outval,
440 if (indomain == NULL || indomain[0] == '\0' ||
441 inmap == NULL || inmap[0] == '\0' ||
442 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
443 return YPERR_BADARGS;
445 req.domain = (char *) indomain;
446 req.map = (char *) inmap;
447 req.key.keydat_val = (char *) inkey;
448 req.key.keydat_len = inkeylen;
450 *outkey = *outval = NULL;
451 *outkeylen = *outvallen = 0;
452 memset (&resp, '\0', sizeof (resp));
454 result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
455 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
458 if (result != RPC_SUCCESS)
460 if (resp.stat != YP_TRUE)
461 return ypprot_err (resp.stat);
463 *outkeylen = resp.key.keydat_len;
464 *outkey = malloc (*outkeylen + 1);
465 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
466 (*outkey)[*outkeylen] = '\0';
467 *outvallen = resp.val.valdat_len;
468 *outval = malloc (*outvallen + 1);
469 memcpy (*outval, resp.val.valdat_val, *outvallen);
470 (*outval)[*outvallen] = '\0';
472 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
474 return YPERR_SUCCESS;
478 yp_master (const char *indomain, const char *inmap, char **outname)
484 if (indomain == NULL || indomain[0] == '\0' ||
485 inmap == NULL || inmap[0] == '\0')
486 return YPERR_BADARGS;
488 req.domain = (char *) indomain;
489 req.map = (char *) inmap;
491 memset (&resp, '\0', sizeof (ypresp_master));
493 result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
494 (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
496 if (result != RPC_SUCCESS)
498 if (resp.stat != YP_TRUE)
499 return ypprot_err (resp.stat);
501 *outname = strdup (resp.peer);
502 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
504 return YPERR_SUCCESS;
508 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
510 struct ypreq_nokey req;
511 struct ypresp_order resp;
514 if (indomain == NULL || indomain[0] == '\0' ||
515 inmap == NULL || inmap == '\0')
516 return YPERR_BADARGS;
518 req.domain = (char *) indomain;
519 req.map = (char *) inmap;
521 memset (&resp, '\0', sizeof (resp));
523 result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
524 (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
526 if (result != RPC_SUCCESS)
528 if (resp.stat != YP_TRUE)
529 return ypprot_err (resp.stat);
531 *outorder = resp.ordernum;
532 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
534 return YPERR_SUCCESS;
537 static void *ypall_data;
538 static int (*ypall_foreach) __P ((int status, char *key, int keylen,
539 char *val, int vallen, char *data));
542 __xdr_ypresp_all (XDR * xdrs, u_long * objp)
546 struct ypresp_all resp;
548 memset (&resp, '\0', sizeof (struct ypresp_all));
549 if (!xdr_ypresp_all (xdrs, &resp))
551 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
557 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
562 switch (resp.ypresp_all_u.val.stat)
566 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
567 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
568 int keylen = resp.ypresp_all_u.val.key.keydat_len;
569 int vallen = resp.ypresp_all_u.val.val.valdat_len;
572 memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
574 memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
576 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
577 if ((*ypall_foreach) (*objp, key, keylen,
578 val, vallen, ypall_data))
584 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
588 *objp = resp.ypresp_all_u.val.stat;
589 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
596 yp_all (const char *indomain, const char *inmap,
597 const struct ypall_callback *incallback)
599 struct ypreq_nokey req;
602 struct sockaddr_in clnt_sin;
604 unsigned long status;
607 if (indomain == NULL || indomain[0] == '\0' ||
608 inmap == NULL || inmap == '\0')
609 return YPERR_BADARGS;
612 result = YPERR_YPERR;
614 while (try < MAXTRIES && result != RPC_SUCCESS)
616 __libc_lock_lock (ypbindlist_lock);
618 if (__yp_bind (indomain, &ydb) != 0)
620 __libc_lock_unlock (ypbindlist_lock);
624 /* YPPROC_ALL get its own TCP channel to ypserv */
625 clnt_sock = RPC_ANYSOCK;
626 clnt_sin = ydb->dom_server_addr;
627 clnt_sin.sin_port = 0;
628 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
631 puts (_("yp_all: clnttcp_create failed"));
632 __libc_lock_unlock (ypbindlist_lock);
635 req.domain = (char *) indomain;
636 req.map = (char *) inmap;
638 ypall_foreach = incallback->foreach;
639 ypall_data = (void *) incallback->data;
641 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
642 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
643 (caddr_t) &status, TIMEOUT);
647 if (result != RPC_SUCCESS)
649 clnt_perror (ydb->dom_client, "yp_all: clnt_call");
654 result = YPERR_SUCCESS;
656 __libc_lock_unlock (ypbindlist_lock);
658 if (status != YP_NOMORE)
659 return ypprot_err (status);
667 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
669 struct ypresp_maplist resp;
672 if (indomain == NULL || indomain[0] == '\0')
673 return YPERR_BADARGS;
675 memset (&resp, '\0', sizeof (resp));
677 result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
678 (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
680 if (result != RPC_SUCCESS)
682 if (resp.stat != YP_TRUE)
683 return ypprot_err (resp.stat);
685 *outmaplist = resp.maps;
686 /* We give the list not free, this will be done by ypserv
687 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
689 return YPERR_SUCCESS;
693 yperr_string (const int error)
700 return _("Request arguments bad");
702 return _("RPC failure on NIS operation");
704 return _("Can't bind to server which serves this domain");
706 return _("No such map in server's domain");
708 return _("No such key in map");
710 return _("Internal NIS error");
712 return _("Local resource allocation failure");
714 return _("No more records in map database");
716 return _("Can't communicate with portmapper");
718 return _("Can't communicate with ypbind");
720 return _("Can't communicate with ypserv");
722 return _("Local domain name not set");
724 return _("NIS map data base is bad");
726 return _("NIS client/server version mismatch - can't supply service");
728 return _("Permission denied");
730 return _("Database is busy");
732 return _("Unknown NIS error code");
736 ypprot_err (const int code)
741 return YPERR_SUCCESS;
759 return YPERR_BADARGS;
767 ypbinderr_string (const int error)
774 return _("Internal ypbind error");
775 case YPBIND_ERR_NOSERV:
776 return _("Domain not bound");
777 case YPBIND_ERR_RESC:
778 return _("System resource allocation failure");
780 return _("Unknown ypbind error");
788 yp_update (char *domain, char *map, unsigned ypop,
789 char *key, int keylen, char *data, int datalen)
793 ypupdate_args update_args;
794 ypdelete_args delete_args;
797 xdrproc_t xdr_argument;
801 struct sockaddr saddr;
802 char servername[MAXNETNAMELEN + 1];
805 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
806 return YPERR_BADARGS;
808 args.update_args.mapname = map;
809 args.update_args.key.yp_buf_len = keylen;
810 args.update_args.key.yp_buf_val = key;
811 args.update_args.datum.yp_buf_len = datalen;
812 args.update_args.datum.yp_buf_val = data;
814 if ((r = yp_master (domain, map, &master)) != 0)
817 if (!host2netname (servername, master, domain))
819 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
823 if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
825 clnt_pcreateerror ("yp_update: clnt_create");
829 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
831 fputs (_("yp_update: cannot get server address\n"), stderr);
840 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
843 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
846 return YPERR_BADARGS;
850 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
852 if (clnt->cl_auth == NULL)
853 clnt->cl_auth = authunix_create_default ();
856 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
857 (xdrproc_t) xdr_u_int, (caddr_t) &res, TIMEOUT);
859 if (r == RPC_AUTHERROR)
861 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
863 clnt->cl_auth = authunix_create_default ();
869 if (r != RPC_SUCCESS)
871 clnt_perror (clnt, "yp_update: clnt_call");