summaryrefslogtreecommitdiffstats
path: root/usr.sbin/rpcbind
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2001-03-19 12:50:13 +0000
committeralfred <alfred@FreeBSD.org>2001-03-19 12:50:13 +0000
commitf67e4a8fc7fc95c74bd6c09d3453200de47faea5 (patch)
tree98b613188d263fdcef5f2d020e5e8c374db1f5b6 /usr.sbin/rpcbind
parent6f24d923a7fa9d1679753d77cc982ec72c22a197 (diff)
downloadFreeBSD-src-f67e4a8fc7fc95c74bd6c09d3453200de47faea5.zip
FreeBSD-src-f67e4a8fc7fc95c74bd6c09d3453200de47faea5.tar.gz
Bring in a hybrid of SunSoft's transport-independent RPC (TI-RPC) and
associated changes that had to happen to make this possible as well as bugs fixed along the way. Bring in required TLI library routines to support this. Since we don't support TLI we've essentially copied what NetBSD has done, adding a thin layer to emulate direct the TLI calls into BSD socket calls. This is mostly from Sun's tirpc release that was made in 1994, however some fixes were backported from the 1999 release (supposedly only made available after this porting effort was underway). The submitter has agreed to continue on and bring us up to the 1999 release. Several key features are introduced with this update: Client calls are thread safe. (1999 code has server side thread safe) Updated, a more modern interface. Many userland updates were done to bring the code up to par with the recent RPC API. There is an update to the pthreads library, a function pthread_main_np() was added to emulate a function of Sun's threads library. While we're at it, bring in NetBSD's lockd, it's been far too long of a wait. New rpcbind(8) replaces portmap(8) (supporting communication over an authenticated Unix-domain socket, and by default only allowing set and unset requests over that channel). It's much more secure than the old portmapper. Umount(8), mountd(8), mount_nfs(8), nfsd(8) have also been upgraded to support TI-RPC and to support IPV6. Umount(8) is also fixed to unmount pathnames longer than 80 chars, which are currently truncated by the Kernel statfs structure. Submitted by: Martin Blapp <mb@imp.ch> Manpage review: ru Secure RPC implemented by: wpaul
Diffstat (limited to 'usr.sbin/rpcbind')
-rw-r--r--usr.sbin/rpcbind/Makefile21
-rw-r--r--usr.sbin/rpcbind/check_bound.c229
-rw-r--r--usr.sbin/rpcbind/pmap_svc.c368
-rw-r--r--usr.sbin/rpcbind/rpcb_stat.c208
-rw-r--r--usr.sbin/rpcbind/rpcb_svc.c233
-rw-r--r--usr.sbin/rpcbind/rpcb_svc_4.c454
-rw-r--r--usr.sbin/rpcbind/rpcb_svc_com.c1457
-rw-r--r--usr.sbin/rpcbind/rpcbind.8112
-rw-r--r--usr.sbin/rpcbind/rpcbind.c568
-rw-r--r--usr.sbin/rpcbind/rpcbind.h144
-rw-r--r--usr.sbin/rpcbind/security.c283
-rw-r--r--usr.sbin/rpcbind/util.c381
-rw-r--r--usr.sbin/rpcbind/warmstart.c179
13 files changed, 4637 insertions, 0 deletions
diff --git a/usr.sbin/rpcbind/Makefile b/usr.sbin/rpcbind/Makefile
new file mode 100644
index 0000000..fb73b23
--- /dev/null
+++ b/usr.sbin/rpcbind/Makefile
@@ -0,0 +1,21 @@
+# $NetBSD: Makefile,v 1.3 2000/06/20 13:56:43 fvdl Exp $
+# $FreeBSD$
+
+PROG= rpcbind
+CFLAGS+= -I${LIBCRPCDIR} -I${LIBCINCLUDE} -DPORTMAP -DINET6 -DLIBWRAP
+MAN8= rpcbind.8
+SRCS= check_bound.c rpcb_stat.c rpcb_svc_4.c rpcbind.c pmap_svc.c \
+ rpcb_svc.c rpcb_svc_com.c security.c warmstart.c util.c \
+ rpc_generic.c
+
+LIBCDIR= ${.CURDIR}/../../lib/libc
+LIBCRPCDIR= ${LIBCDIR}/rpc
+LIBCINCLUDE= ${LIBCDIR}/include
+
+
+LDADD+= -lwrap -lutil
+DPADD+= ${LIBWRAP} ${LIBUTIL}
+
+.PATH: ${LIBCRPCDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rpcbind/check_bound.c b/usr.sbin/rpcbind/check_bound.c
new file mode 100644
index 0000000..fe503d7
--- /dev/null
+++ b/usr.sbin/rpcbind/check_bound.c
@@ -0,0 +1,229 @@
+/* $NetBSD: check_bound.c,v 1.2 2000/06/22 08:09:26 fvdl Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/* #ident "@(#)check_bound.c 1.15 93/07/05 SMI" */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)check_bound.c 1.11 89/04/21 Copyr 1989 Sun Micro";
+#endif
+#endif
+
+/*
+ * check_bound.c
+ * Checks to see whether the program is still bound to the
+ * claimed address and returns the univeral merged address
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <stdio.h>
+#include <netconfig.h>
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "rpcbind.h"
+
+struct fdlist {
+ int fd;
+ struct netconfig *nconf;
+ struct fdlist *next;
+ int check_binding;
+};
+
+static struct fdlist *fdhead; /* Link list of the check fd's */
+static struct fdlist *fdtail;
+static char *nullstring = "";
+
+static bool_t check_bound __P((struct fdlist *, char *uaddr));
+
+/*
+ * Returns 1 if the given address is bound for the given addr & transport
+ * For all error cases, we assume that the address is bound
+ * Returns 0 for success.
+ */
+static bool_t
+check_bound(struct fdlist *fdl, char *uaddr)
+{
+ int fd;
+ struct netbuf *na;
+ int ans;
+
+ if (fdl->check_binding == FALSE)
+ return (TRUE);
+
+ na = uaddr2taddr(fdl->nconf, uaddr);
+ if (!na)
+ return (TRUE); /* punt, should never happen */
+
+ fd = __rpc_nconf2fd(fdl->nconf);
+ if (fd < 0) {
+ free(na);
+ return (TRUE);
+ }
+
+ ans = bind(fd, (struct sockaddr *)na->buf, na->len);
+
+ close(fd);
+ free(na);
+
+ return (ans == 0 ? FALSE : TRUE);
+}
+
+int
+add_bndlist(struct netconfig *nconf, struct netbuf *baddr)
+{
+ struct fdlist *fdl;
+ struct netconfig *newnconf;
+
+ newnconf = getnetconfigent(nconf->nc_netid);
+ if (newnconf == NULL)
+ return (-1);
+ fdl = (struct fdlist *)malloc((u_int)sizeof (struct fdlist));
+ if (fdl == NULL) {
+ freenetconfigent(newnconf);
+ syslog(LOG_ERR, "no memory!");
+ return (-1);
+ }
+ fdl->nconf = newnconf;
+ fdl->next = NULL;
+ if (fdhead == NULL) {
+ fdhead = fdl;
+ fdtail = fdl;
+ } else {
+ fdtail->next = fdl;
+ fdtail = fdl;
+ }
+ /* XXX no bound checking for now */
+ fdl->check_binding = FALSE;
+
+ return 0;
+}
+
+bool_t
+is_bound(char *netid, char *uaddr)
+{
+ struct fdlist *fdl;
+
+ for (fdl = fdhead; fdl; fdl = fdl->next)
+ if (strcmp(fdl->nconf->nc_netid, netid) == 0)
+ break;
+ if (fdl == NULL)
+ return (TRUE);
+ return (check_bound(fdl, uaddr));
+}
+
+/*
+ * Returns NULL if there was some system error.
+ * Returns "" if the address was not bound, i.e the server crashed.
+ * Returns the merged address otherwise.
+ */
+char *
+mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
+{
+ struct fdlist *fdl;
+ char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;
+
+ for (fdl = fdhead; fdl; fdl = fdl->next)
+ if (strcmp(fdl->nconf->nc_netid, netid) == 0)
+ break;
+ if (fdl == NULL)
+ return (NULL);
+ if (check_bound(fdl, uaddr) == FALSE)
+ /* that server died */
+ return (nullstring);
+ /*
+ * If saddr is not NULL, the remote client may have included the
+ * address by which it contacted us. Use that for the "client" uaddr,
+ * otherwise use the info from the SVCXPRT.
+ */
+ if (saddr != NULL) {
+ c_uaddr = saddr;
+ } else {
+ c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
+ if (c_uaddr == NULL) {
+ syslog(LOG_ERR, "taddr2uaddr failed for %s",
+ fdl->nconf->nc_netid);
+ return (NULL);
+ }
+ allocated_uaddr = c_uaddr;
+ }
+
+#ifdef ND_DEBUG
+ if (debugging) {
+ if (saddr == NULL) {
+ fprintf(stderr, "mergeaddr: client uaddr = %s\n",
+ c_uaddr);
+ } else {
+ fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
+ c_uaddr);
+ }
+ }
+#endif
+ s_uaddr = uaddr;
+ /*
+ * This is all we should need for IP 4 and 6
+ */
+ m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
+#ifdef ND_DEBUG
+ if (debugging)
+ fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
+ uaddr, m_uaddr);
+#endif
+ if (allocated_uaddr != NULL)
+ free(allocated_uaddr);
+ return (m_uaddr);
+}
+
+/*
+ * Returns a netconf structure from its internal list. This
+ * structure should not be freed.
+ */
+struct netconfig *
+rpcbind_get_conf(char *netid)
+{
+ struct fdlist *fdl;
+
+ for (fdl = fdhead; fdl; fdl = fdl->next)
+ if (strcmp(fdl->nconf->nc_netid, netid) == 0)
+ break;
+ if (fdl == NULL)
+ return (NULL);
+ return (fdl->nconf);
+}
diff --git a/usr.sbin/rpcbind/pmap_svc.c b/usr.sbin/rpcbind/pmap_svc.c
new file mode 100644
index 0000000..b2cedd9
--- /dev/null
+++ b/usr.sbin/rpcbind/pmap_svc.c
@@ -0,0 +1,368 @@
+/* $NetBSD: pmap_svc.c,v 1.2 2000/10/20 11:49:40 fvdl Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
+ */
+
+/* #ident "@(#)pmap_svc.c 1.14 93/07/05 SMI" */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)pmap_svc.c 1.23 89/04/05 Copyr 1984 Sun Micro";
+#endif
+#endif
+
+/*
+ * pmap_svc.c
+ * The server procedure for the version 2 portmaper.
+ * All the portmapper related interface from the portmap side.
+ */
+
+#ifdef PORTMAP
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/rpcb_prot.h>
+#ifdef RPCBIND_DEBUG
+#include <stdlib.h>
+#endif
+#include "rpcbind.h"
+
+static struct pmaplist *find_service_pmap __P((rpcprog_t, rpcvers_t,
+ rpcprot_t));
+static bool_t pmapproc_change __P((struct svc_req *, SVCXPRT *, u_long));
+static bool_t pmapproc_getport __P((struct svc_req *, SVCXPRT *));
+static bool_t pmapproc_dump __P((struct svc_req *, SVCXPRT *));
+
+/*
+ * Called for all the version 2 inquiries.
+ */
+void
+pmap_service(struct svc_req *rqstp, SVCXPRT *xprt)
+{
+ rpcbs_procinfo(RPCBVERS_2_STAT, rqstp->rq_proc);
+ switch (rqstp->rq_proc) {
+ case PMAPPROC_NULL:
+ /*
+ * Null proc call
+ */
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "PMAPPROC_NULL\n");
+#endif
+ check_access(xprt, rqstp->rq_proc, NULL, PMAPVERS);
+ if ((!svc_sendreply(xprt, (xdrproc_t) xdr_void, NULL)) &&
+ debugging) {
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+ break;
+
+ case PMAPPROC_SET:
+ /*
+ * Set a program, version to port mapping
+ */
+ pmapproc_change(rqstp, xprt, rqstp->rq_proc);
+ break;
+
+ case PMAPPROC_UNSET:
+ /*
+ * Remove a program, version to port mapping.
+ */
+ pmapproc_change(rqstp, xprt, rqstp->rq_proc);
+ break;
+
+ case PMAPPROC_GETPORT:
+ /*
+ * Lookup the mapping for a program, version and return its
+ * port number.
+ */
+ pmapproc_getport(rqstp, xprt);
+ break;
+
+ case PMAPPROC_DUMP:
+ /*
+ * Return the current set of mapped program, version
+ */
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "PMAPPROC_DUMP\n");
+#endif
+ pmapproc_dump(rqstp, xprt);
+ break;
+
+ case PMAPPROC_CALLIT:
+ /*
+ * Calls a procedure on the local machine. If the requested
+ * procedure is not registered this procedure does not return
+ * error information!!
+ * This procedure is only supported on rpc/udp and calls via
+ * rpc/udp. It passes null authentication parameters.
+ */
+ rpcbproc_callit_com(rqstp, xprt, PMAPPROC_CALLIT, PMAPVERS);
+ break;
+
+ default:
+ svcerr_noproc(xprt);
+ break;
+ }
+}
+
+/*
+ * returns the item with the given program, version number. If that version
+ * number is not found, it returns the item with that program number, so that
+ * the port number is now returned to the caller. The caller when makes a
+ * call to this program, version number, the call will fail and it will
+ * return with PROGVERS_MISMATCH. The user can then determine the highest
+ * and the lowest version number for this program using clnt_geterr() and
+ * use those program version numbers.
+ */
+static struct pmaplist *
+find_service_pmap(rpcprog_t prog, rpcvers_t vers, rpcprot_t prot)
+{
+ register struct pmaplist *hit = NULL;
+ register struct pmaplist *pml;
+
+ for (pml = list_pml; pml != NULL; pml = pml->pml_next) {
+ if ((pml->pml_map.pm_prog != prog) ||
+ (pml->pml_map.pm_prot != prot))
+ continue;
+ hit = pml;
+ if (pml->pml_map.pm_vers == vers)
+ break;
+ }
+ return (hit);
+}
+
+static bool_t
+pmapproc_change(struct svc_req *rqstp, SVCXPRT *xprt, unsigned long op)
+{
+ struct pmap reg;
+ RPCB rpcbreg;
+ long ans;
+ struct sockaddr_in *who;
+ struct cmsgcred *cmcred;
+ char uidbuf[32];
+
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "%s request for (%lu, %lu) : ",
+ op == PMAPPROC_SET ? "PMAP_SET" : "PMAP_UNSET",
+ reg.pm_prog, reg.pm_vers);
+#endif
+
+ if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)&reg)) {
+ svcerr_decode(xprt);
+ return (FALSE);
+ }
+
+ if (!check_access(xprt, op, &reg, PMAPVERS)) {
+ svcerr_weakauth(xprt);
+ return FALSE;
+ }
+
+ who = svc_getcaller(xprt);
+ cmcred = __svc_getcallercreds(xprt);
+
+ /*
+ * Can't use getpwnam here. We might end up calling ourselves
+ * and looping.
+ */
+ if (cmcred == NULL)
+ rpcbreg.r_owner = "unknown";
+ else if (cmcred->cmcred_uid == 0)
+ rpcbreg.r_owner = "superuser";
+ else {
+ /* r_owner will be strdup-ed later */
+ snprintf(uidbuf, sizeof uidbuf, "%d", cmcred->cmcred_uid);
+ rpcbreg.r_owner = uidbuf;
+ }
+
+ rpcbreg.r_prog = reg.pm_prog;
+ rpcbreg.r_vers = reg.pm_vers;
+
+ if (op == PMAPPROC_SET) {
+ char buf[32];
+
+ sprintf(buf, "0.0.0.0.%d.%d", (int)((reg.pm_port >> 8) & 0xff),
+ (int)(reg.pm_port & 0xff));
+ rpcbreg.r_addr = buf;
+ if (reg.pm_prot == IPPROTO_UDP) {
+ rpcbreg.r_netid = udptrans;
+ } else if (reg.pm_prot == IPPROTO_TCP) {
+ rpcbreg.r_netid = tcptrans;
+ } else {
+ ans = FALSE;
+ goto done_change;
+ }
+ ans = map_set(&rpcbreg, rpcbreg.r_owner);
+ } else if (op == PMAPPROC_UNSET) {
+ bool_t ans1, ans2;
+
+ rpcbreg.r_addr = NULL;
+ rpcbreg.r_netid = tcptrans;
+ ans1 = map_unset(&rpcbreg, rpcbreg.r_owner);
+ rpcbreg.r_netid = udptrans;
+ ans2 = map_unset(&rpcbreg, rpcbreg.r_owner);
+ ans = ans1 || ans2;
+ } else {
+ ans = FALSE;
+ }
+done_change:
+ if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t) &ans)) &&
+ debugging) {
+ fprintf(stderr, "portmap: svc_sendreply\n");
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
+#endif
+ if (op == PMAPPROC_SET)
+ rpcbs_set(RPCBVERS_2_STAT, ans);
+ else
+ rpcbs_unset(RPCBVERS_2_STAT, ans);
+ return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+pmapproc_getport(struct svc_req *rqstp, SVCXPRT *xprt)
+{
+ struct pmap reg;
+ long lport;
+ int port = 0;
+ struct pmaplist *fnd;
+#ifdef RPCBIND_DEBUG
+ char *uaddr;
+#endif
+
+ if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (char *)&reg)) {
+ svcerr_decode(xprt);
+ return (FALSE);
+ }
+
+ if (!check_access(xprt, PMAPPROC_GETPORT, &reg, PMAPVERS)) {
+ svcerr_weakauth(xprt);
+ return FALSE;
+ }
+
+#ifdef RPCBIND_DEBUG
+ if (debugging) {
+ uaddr = taddr2uaddr(rpcbind_get_conf(xprt->xp_netid),
+ svc_getrpccaller(xprt));
+ fprintf(stderr, "PMAP_GETPORT req for (%lu, %lu, %s) from %s :",
+ reg.pm_prog, reg.pm_vers,
+ reg.pm_prot == IPPROTO_UDP ? "udp" : "tcp", uaddr);
+ free(uaddr);
+ }
+#endif
+ fnd = find_service_pmap(reg.pm_prog, reg.pm_vers, reg.pm_prot);
+ if (fnd) {
+ char serveuaddr[32], *ua;
+ int h1, h2, h3, h4, p1, p2;
+ char *netid;
+
+ if (reg.pm_prot == IPPROTO_UDP) {
+ ua = udp_uaddr;
+ netid = udptrans;
+ } else {
+ ua = tcp_uaddr; /* To get the len */
+ netid = tcptrans;
+ }
+ if (ua == NULL) {
+ goto sendreply;
+ }
+ if (sscanf(ua, "%d.%d.%d.%d.%d.%d", &h1, &h2, &h3,
+ &h4, &p1, &p2) == 6) {
+ p1 = (fnd->pml_map.pm_port >> 8) & 0xff;
+ p2 = (fnd->pml_map.pm_port) & 0xff;
+ sprintf(serveuaddr, "%d.%d.%d.%d.%d.%d",
+ h1, h2, h3, h4, p1, p2);
+ if (is_bound(netid, serveuaddr)) {
+ port = fnd->pml_map.pm_port;
+ } else { /* this service is dead; delete it */
+ delete_prog(reg.pm_prog);
+ }
+ }
+ }
+sendreply:
+ lport = port;
+ if ((!svc_sendreply(xprt, (xdrproc_t) xdr_long, (caddr_t)&lport)) &&
+ debugging) {
+ (void) fprintf(stderr, "portmap: svc_sendreply\n");
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "port = %d\n", port);
+#endif
+ rpcbs_getaddr(RPCBVERS_2_STAT, reg.pm_prog, reg.pm_vers,
+ reg.pm_prot == IPPROTO_UDP ? udptrans : tcptrans,
+ port ? udptrans : "");
+
+ return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+pmapproc_dump(struct svc_req *rqstp, SVCXPRT *xprt)
+{
+ if (!svc_getargs(xprt, (xdrproc_t)xdr_void, NULL)) {
+ svcerr_decode(xprt);
+ return (FALSE);
+ }
+
+ if (!check_access(xprt, PMAPPROC_DUMP, NULL, PMAPVERS)) {
+ svcerr_weakauth(xprt);
+ return FALSE;
+ }
+
+ if ((!svc_sendreply(xprt, (xdrproc_t) xdr_pmaplist_ptr,
+ (caddr_t)&list_pml)) && debugging) {
+ if (debugging)
+ (void) fprintf(stderr, "portmap: svc_sendreply\n");
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+ return (TRUE);
+}
+
+#endif /* PORTMAP */
diff --git a/usr.sbin/rpcbind/rpcb_stat.c b/usr.sbin/rpcbind/rpcb_stat.c
new file mode 100644
index 0000000..0555493
--- /dev/null
+++ b/usr.sbin/rpcbind/rpcb_stat.c
@@ -0,0 +1,208 @@
+/*
+ * $NetBSD: rpcb_stat.c,v 1.2 2000/07/04 20:27:40 matt Exp $
+ * $FreeBSD$
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/* #pragma ident "@(#)rpcb_stat.c 1.7 94/04/25 SMI" */
+
+/*
+ * rpcb_stat.c
+ * Allows for gathering of statistics
+ *
+ * Copyright (c) 1990 by Sun Microsystems, Inc.
+ */
+
+#include <stdio.h>
+#include <netconfig.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcb_prot.h>
+#include <sys/stat.h>
+#ifdef PORTMAP
+#include <rpc/pmap_prot.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include "rpcbind.h"
+
+static rpcb_stat_byvers inf;
+
+void
+rpcbs_init()
+{
+
+}
+
+void
+rpcbs_procinfo(rpcvers_t rtype, rpcproc_t proc)
+{
+ switch (rtype + 2) {
+#ifdef PORTMAP
+ case PMAPVERS: /* version 2 */
+ if (proc > rpcb_highproc_2)
+ return;
+ break;
+#endif
+ case RPCBVERS: /* version 3 */
+ if (proc > rpcb_highproc_3)
+ return;
+ break;
+ case RPCBVERS4: /* version 4 */
+ if (proc > rpcb_highproc_4)
+ return;
+ break;
+ default: return;
+ }
+ inf[rtype].info[proc]++;
+ return;
+}
+
+void
+rpcbs_set(rpcvers_t rtype, bool_t success)
+{
+ if ((rtype >= RPCBVERS_STAT) || (success == FALSE))
+ return;
+ inf[rtype].setinfo++;
+ return;
+}
+
+void
+rpcbs_unset(rpcvers_t rtype, bool_t success)
+{
+ if ((rtype >= RPCBVERS_STAT) || (success == FALSE))
+ return;
+ inf[rtype].unsetinfo++;
+ return;
+}
+
+void
+rpcbs_getaddr(rpcvers_t rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
+ char *uaddr)
+{
+ rpcbs_addrlist *al;
+ struct netconfig *nconf;
+
+ if (rtype >= RPCBVERS_STAT)
+ return;
+ for (al = inf[rtype].addrinfo; al; al = al->next) {
+
+ if(al->netid == NULL)
+ return;
+ if ((al->prog == prog) && (al->vers == vers) &&
+ (strcmp(al->netid, netid) == 0)) {
+ if ((uaddr == NULL) || (uaddr[0] == NULL))
+ al->failure++;
+ else
+ al->success++;
+ return;
+ }
+ }
+ nconf = rpcbind_get_conf(netid);
+ if (nconf == NULL) {
+ return;
+ }
+ al = (rpcbs_addrlist *) malloc(sizeof (rpcbs_addrlist));
+ if (al == NULL) {
+ return;
+ }
+ al->prog = prog;
+ al->vers = vers;
+ al->netid = nconf->nc_netid;
+ if ((uaddr == NULL) || (uaddr[0] == NULL)) {
+ al->failure = 1;
+ al->success = 0;
+ } else {
+ al->failure = 0;
+ al->success = 1;
+ }
+ al->next = inf[rtype].addrinfo;
+ inf[rtype].addrinfo = al;
+}
+
+void
+rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog,
+ rpcvers_t vers, rpcproc_t proc, char *netid, rpcblist_ptr rbl)
+{
+ rpcbs_rmtcalllist *rl;
+ struct netconfig *nconf;
+
+ if (rtype > RPCBVERS_STAT)
+ return;
+ for (rl = inf[rtype].rmtinfo; rl; rl = rl->next) {
+
+ if(rl->netid == NULL)
+ return;
+
+ if ((rl->prog == prog) && (rl->vers == vers) &&
+ (rl->proc == proc) &&
+ (strcmp(rl->netid, netid) == 0)) {
+ if ((rbl == NULL) ||
+ (rbl->rpcb_map.r_vers != vers))
+ rl->failure++;
+ else
+ rl->success++;
+ if (rpcbproc == RPCBPROC_INDIRECT)
+ rl->indirect++;
+ return;
+ }
+ }
+ nconf = rpcbind_get_conf(netid);
+ if (nconf == NULL) {
+ return;
+ }
+ rl = (rpcbs_rmtcalllist *) malloc(sizeof (rpcbs_rmtcalllist));
+ if (rl == NULL) {
+ return;
+ }
+ rl->prog = prog;
+ rl->vers = vers;
+ rl->proc = proc;
+ rl->netid = nconf->nc_netid;
+ if ((rbl == NULL) ||
+ (rbl->rpcb_map.r_vers != vers)) {
+ rl->failure = 1;
+ rl->success = 0;
+ } else {
+ rl->failure = 0;
+ rl->success = 1;
+ }
+ rl->indirect = 1;
+ rl->next = inf[rtype].rmtinfo;
+ inf[rtype].rmtinfo = rl;
+ return;
+}
+
+/*
+ */
+void *
+rpcbproc_getstat(void *arg, struct svc_req *req, SVCXPRT *xprt,
+ rpcvers_t versnum)
+{
+ return (void *)&inf;
+}
diff --git a/usr.sbin/rpcbind/rpcb_svc.c b/usr.sbin/rpcbind/rpcb_svc.c
new file mode 100644
index 0000000..b01e9ac
--- /dev/null
+++ b/usr.sbin/rpcbind/rpcb_svc.c
@@ -0,0 +1,233 @@
+/* $NetBSD: rpcb_svc.c,v 1.1 2000/06/02 23:15:41 fvdl Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/* #ident "@(#)rpcb_svc.c 1.16 93/07/05 SMI" */
+
+/*
+ * rpcb_svc.c
+ * The server procedure for the version 3 rpcbind (TLI).
+ *
+ * It maintains a separate list of all the registered services with the
+ * version 3 of rpcbind.
+ */
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcb_prot.h>
+#include <netconfig.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "rpcbind.h"
+
+static void *rpcbproc_getaddr_3_local __P((void *, struct svc_req *, SVCXPRT *,
+ rpcvers_t));
+static void *rpcbproc_dump_3_local __P((void *, struct svc_req *, SVCXPRT *,
+ rpcvers_t));
+
+/*
+ * Called by svc_getreqset. There is a separate server handle for
+ * every transport that it waits on.
+ */
+void
+rpcb_service_3(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ union {
+ RPCB rpcbproc_set_3_arg;
+ RPCB rpcbproc_unset_3_arg;
+ RPCB rpcbproc_getaddr_3_local_arg;
+ struct rpcb_rmtcallargs rpcbproc_callit_3_arg;
+ char *rpcbproc_uaddr2taddr_3_arg;
+ struct netbuf rpcbproc_taddr2uaddr_3_arg;
+ } argument;
+ char *result;
+ xdrproc_t xdr_argument, xdr_result;
+ void *(*local) __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+
+ rpcbs_procinfo(RPCBVERS_3_STAT, rqstp->rq_proc);
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ /*
+ * Null proc call
+ */
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_NULL\n");
+#endif
+ /* This call just logs, no actual checks */
+ check_access(transp, rqstp->rq_proc, NULL, RPCBVERS);
+ (void) svc_sendreply(transp, (xdrproc_t)xdr_void, (char *)NULL);
+ return;
+
+ case RPCBPROC_SET:
+ xdr_argument = (xdrproc_t )xdr_rpcb;
+ xdr_result = (xdrproc_t )xdr_bool;
+ local = rpcbproc_set_com;
+ break;
+
+ case RPCBPROC_UNSET:
+ xdr_argument = (xdrproc_t)xdr_rpcb;
+ xdr_result = (xdrproc_t)xdr_bool;
+ local = rpcbproc_unset_com;
+ break;
+
+ case RPCBPROC_GETADDR:
+ xdr_argument = (xdrproc_t)xdr_rpcb;
+ xdr_result = (xdrproc_t)xdr_wrapstring;
+ local = rpcbproc_getaddr_3_local;
+ break;
+
+ case RPCBPROC_DUMP:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_DUMP\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_void;
+ xdr_result = (xdrproc_t)xdr_rpcblist_ptr;
+ local = rpcbproc_dump_3_local;
+ break;
+
+ case RPCBPROC_CALLIT:
+ rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS);
+ return;
+
+ case RPCBPROC_GETTIME:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_GETTIME\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_void;
+ xdr_result = (xdrproc_t)xdr_u_long;
+ local = rpcbproc_gettime_com;
+ break;
+
+ case RPCBPROC_UADDR2TADDR:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_UADDR2TADDR\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_wrapstring;
+ xdr_result = (xdrproc_t)xdr_netbuf;
+ local = rpcbproc_uaddr2taddr_com;
+ break;
+
+ case RPCBPROC_TADDR2UADDR:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_TADDR2UADDR\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_netbuf;
+ xdr_result = (xdrproc_t)xdr_wrapstring;
+ local = rpcbproc_taddr2uaddr_com;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ (void) memset((char *)&argument, 0, sizeof (argument));
+ if (!svc_getargs(transp, (xdrproc_t) xdr_argument,
+ (char *) &argument)) {
+ svcerr_decode(transp);
+ if (debugging)
+ (void) fprintf(stderr, "rpcbind: could not decode\n");
+ return;
+ }
+ if (!check_access(transp, rqstp->rq_proc, &argument, RPCBVERS)) {
+ svcerr_weakauth(transp);
+ goto done;
+ }
+ result = (*local)(&argument, rqstp, transp, RPCBVERS);
+ if (result != NULL && !svc_sendreply(transp, (xdrproc_t)xdr_result,
+ result)) {
+ svcerr_systemerr(transp);
+ if (debugging) {
+ (void) fprintf(stderr, "rpcbind: svc_sendreply\n");
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+ }
+done:
+ if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (char *)
+ &argument)) {
+ if (debugging) {
+ (void) fprintf(stderr, "unable to free arguments\n");
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+ }
+}
+
+/*
+ * Lookup the mapping for a program, version and return its
+ * address. Assuming that the caller wants the address of the
+ * server running on the transport on which the request came.
+ *
+ * We also try to resolve the universal address in terms of
+ * address of the caller.
+ */
+/* ARGSUSED */
+static void *
+rpcbproc_getaddr_3_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t versnum)
+{
+ RPCB *regp = (RPCB *)arg;
+#ifdef RPCBIND_DEBUG
+ if (debugging) {
+ char *uaddr;
+
+ uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
+ svc_getrpccaller(transp));
+ fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ",
+ (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
+ regp->r_netid, uaddr);
+ free(uaddr);
+ }
+#endif
+ return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS,
+ RPCB_ALLVERS));
+}
+
+/* ARGSUSED */
+static void *
+rpcbproc_dump_3_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t versnum)
+{
+ return ((void *)&list_rbl);
+}
diff --git a/usr.sbin/rpcbind/rpcb_svc_4.c b/usr.sbin/rpcbind/rpcb_svc_4.c
new file mode 100644
index 0000000..5f14474
--- /dev/null
+++ b/usr.sbin/rpcbind/rpcb_svc_4.c
@@ -0,0 +1,454 @@
+/*
+ * $NetBSD: rpcb_svc_4.c,v 1.1 2000/06/02 23:15:41 fvdl Exp $
+ * $FreeBSD$
+ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/* #ident "@(#)rpcb_svc_4.c 1.8 93/07/05 SMI" */
+
+/*
+ * rpcb_svc_4.c
+ * The server procedure for the version 4 rpcbind.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netconfig.h>
+#include <syslog.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rpcbind.h"
+
+static void *rpcbproc_getaddr_4_local __P((void *, struct svc_req *, SVCXPRT *,
+ rpcvers_t));
+static void *rpcbproc_getversaddr_4_local __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+static void *rpcbproc_getaddrlist_4_local
+ __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+static void free_rpcb_entry_list __P((rpcb_entry_list_ptr *));
+static void *rpcbproc_dump_4_local __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+
+/*
+ * Called by svc_getreqset. There is a separate server handle for
+ * every transport that it waits on.
+ */
+void
+rpcb_service_4(struct svc_req *rqstp, SVCXPRT *transp)
+{
+ union {
+ rpcb rpcbproc_set_4_arg;
+ rpcb rpcbproc_unset_4_arg;
+ rpcb rpcbproc_getaddr_4_local_arg;
+ char *rpcbproc_uaddr2taddr_4_arg;
+ struct netbuf rpcbproc_taddr2uaddr_4_arg;
+ } argument;
+ char *result;
+ xdrproc_t xdr_argument, xdr_result;
+ void *(*local) __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+
+ rpcbs_procinfo(RPCBVERS_4_STAT, rqstp->rq_proc);
+
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ /*
+ * Null proc call
+ */
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_NULL\n");
+#endif
+ check_access(transp, rqstp->rq_proc, NULL, RPCBVERS4);
+ (void) svc_sendreply(transp, (xdrproc_t) xdr_void,
+ (char *)NULL);
+ return;
+
+ case RPCBPROC_SET:
+ /*
+ * Check to see whether the message came from
+ * loopback transports (for security reasons)
+ */
+ xdr_argument = (xdrproc_t)xdr_rpcb;
+ xdr_result = (xdrproc_t)xdr_bool;
+ local = rpcbproc_set_com;
+ break;
+
+ case RPCBPROC_UNSET:
+ /*
+ * Check to see whether the message came from
+ * loopback transports (for security reasons)
+ */
+ xdr_argument = (xdrproc_t)xdr_rpcb;
+ xdr_result = (xdrproc_t)xdr_bool;
+ local = rpcbproc_unset_com;
+ break;
+
+ case RPCBPROC_GETADDR:
+ xdr_argument = (xdrproc_t)xdr_rpcb;
+ xdr_result = (xdrproc_t)xdr_wrapstring;
+ local = rpcbproc_getaddr_4_local;
+ break;
+
+ case RPCBPROC_GETVERSADDR:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_GETVERSADDR\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_rpcb;
+ xdr_result = (xdrproc_t)xdr_wrapstring;
+ local = rpcbproc_getversaddr_4_local;
+ break;
+
+ case RPCBPROC_DUMP:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_DUMP\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_void;
+ xdr_result = (xdrproc_t)xdr_rpcblist_ptr;
+ local = rpcbproc_dump_4_local;
+ break;
+
+ case RPCBPROC_INDIRECT:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_INDIRECT\n");
+#endif
+ rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
+ return;
+
+/* case RPCBPROC_CALLIT: */
+ case RPCBPROC_BCAST:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_BCAST\n");
+#endif
+ rpcbproc_callit_com(rqstp, transp, rqstp->rq_proc, RPCBVERS4);
+ return;
+
+ case RPCBPROC_GETTIME:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_GETTIME\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_void;
+ xdr_result = (xdrproc_t)xdr_u_long;
+ local = rpcbproc_gettime_com;
+ break;
+
+ case RPCBPROC_UADDR2TADDR:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_UADDR2TADDR\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_wrapstring;
+ xdr_result = (xdrproc_t)xdr_netbuf;
+ local = rpcbproc_uaddr2taddr_com;
+ break;
+
+ case RPCBPROC_TADDR2UADDR:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_TADDR2UADDR\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_netbuf;
+ xdr_result = (xdrproc_t)xdr_wrapstring;
+ local = rpcbproc_taddr2uaddr_com;
+ break;
+
+ case RPCBPROC_GETADDRLIST:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_GETADDRLIST\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_rpcb;
+ xdr_result = (xdrproc_t)xdr_rpcb_entry_list_ptr;
+ local = rpcbproc_getaddrlist_4_local;
+ break;
+
+ case RPCBPROC_GETSTAT:
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCBPROC_GETSTAT\n");
+#endif
+ xdr_argument = (xdrproc_t)xdr_void;
+ xdr_result = (xdrproc_t)xdr_rpcb_stat_byvers;
+ local = rpcbproc_getstat;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ memset((char *)&argument, 0, sizeof (argument));
+ if (!svc_getargs(transp, (xdrproc_t) xdr_argument,
+ (char *)&argument)) {
+ svcerr_decode(transp);
+ if (debugging)
+ (void) fprintf(stderr, "rpcbind: could not decode\n");
+ return;
+ }
+ if (!check_access(transp, rqstp->rq_proc, &argument, RPCBVERS4)) {
+ svcerr_weakauth(transp);
+ goto done;
+ }
+ result = (*local)(&argument, rqstp, transp, RPCBVERS4);
+ if (result != NULL && !svc_sendreply(transp, (xdrproc_t) xdr_result,
+ result)) {
+ svcerr_systemerr(transp);
+ if (debugging) {
+ (void) fprintf(stderr, "rpcbind: svc_sendreply\n");
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+ }
+done:
+ if (!svc_freeargs(transp, (xdrproc_t) xdr_argument,
+ (char *)&argument)) {
+ if (debugging) {
+ (void) fprintf(stderr, "unable to free arguments\n");
+ if (doabort) {
+ rpcbind_abort();
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * Lookup the mapping for a program, version and return its
+ * address. Assuming that the caller wants the address of the
+ * server running on the transport on which the request came.
+ * Even if a service with a different version number is available,
+ * it will return that address. The client should check with an
+ * clnt_call to verify whether the service is the one that is desired.
+ * We also try to resolve the universal address in terms of
+ * address of the caller.
+ */
+/* ARGSUSED */
+static void *
+rpcbproc_getaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t rpcbversnum)
+{
+ RPCB *regp = (RPCB *)arg;
+#ifdef RPCBIND_DEBUG
+ if (debugging) {
+ char *uaddr;
+
+ uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
+ svc_getrpccaller(transp));
+ fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ",
+ (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
+ regp->r_netid, uaddr);
+ free(uaddr);
+ }
+#endif
+ return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
+ RPCB_ALLVERS));
+}
+
+/*
+ * Lookup the mapping for a program, version and return its
+ * address. Assuming that the caller wants the address of the
+ * server running on the transport on which the request came.
+ *
+ * We also try to resolve the universal address in terms of
+ * address of the caller.
+ */
+/* ARGSUSED */
+static void *
+rpcbproc_getversaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t versnum)
+{
+ RPCB *regp = (RPCB *)arg;
+#ifdef RPCBIND_DEBUG
+ if (debugging) {
+ char *uaddr;
+
+ uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
+ svc_getrpccaller(transp));
+ fprintf(stderr, "RPCB_GETVERSADDR rqst for (%lu, %lu, %s)"
+ " from %s : ",
+ (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
+ regp->r_netid, uaddr);
+ free(uaddr);
+ }
+#endif
+ return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
+ RPCB_ONEVERS));
+}
+
+/*
+ * Lookup the mapping for a program, version and return the
+ * addresses for all transports in the current transport family.
+ * We return a merged address.
+ */
+/* ARGSUSED */
+static void *
+rpcbproc_getaddrlist_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t versnum)
+{
+ RPCB *regp = (RPCB *)arg;
+ static rpcb_entry_list_ptr rlist;
+ register rpcblist_ptr rbl;
+ rpcb_entry_list_ptr rp, tail;
+ rpcprog_t prog;
+ rpcvers_t vers;
+ rpcb_entry *a;
+ struct netconfig *nconf;
+ struct netconfig *reg_nconf;
+ char *saddr, *maddr = NULL;
+
+ free_rpcb_entry_list(&rlist);
+ prog = regp->r_prog;
+ vers = regp->r_vers;
+ reg_nconf = rpcbind_get_conf(transp->xp_netid);
+ if (reg_nconf == NULL)
+ return (NULL);
+ if (*(regp->r_addr) != '\0') {
+ saddr = regp->r_addr;
+ } else {
+ saddr = NULL;
+ }
+#ifdef RPCBIND_DEBUG
+ if (debugging) {
+ fprintf(stderr, "r_addr: %s r_netid: %s nc_protofmly: %s\n",
+ regp->r_addr, regp->r_netid, reg_nconf->nc_protofmly);
+ }
+#endif
+ for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
+ if ((rbl->rpcb_map.r_prog == prog) &&
+ (rbl->rpcb_map.r_vers == vers)) {
+ nconf = rpcbind_get_conf(rbl->rpcb_map.r_netid);
+ if (nconf == NULL)
+ goto fail;
+ if (strcmp(nconf->nc_protofmly, reg_nconf->nc_protofmly)
+ != 0) {
+ continue; /* not same proto family */
+ }
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "\tmerge with: %s", rbl->rpcb_map.r_addr);
+#endif
+ if ((maddr = mergeaddr(transp, rbl->rpcb_map.r_netid,
+ rbl->rpcb_map.r_addr, saddr)) == NULL) {
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, " FAILED\n");
+#endif
+ continue;
+ } else if (!maddr[0]) {
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, " SUCCEEDED, but port died - maddr: nullstring\n");
+#endif
+ /* The server died. Unset this combination */
+ delete_prog(regp->r_prog);
+ continue;
+ }
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, " SUCCEEDED maddr: %s\n", maddr);
+#endif
+ /*
+ * Add it to rlist.
+ */
+ rp = (rpcb_entry_list_ptr)
+ malloc((u_int)sizeof (rpcb_entry_list));
+ if (rp == NULL)
+ goto fail;
+ a = &rp->rpcb_entry_map;
+ a->r_maddr = maddr;
+ a->r_nc_netid = nconf->nc_netid;
+ a->r_nc_semantics = nconf->nc_semantics;
+ a->r_nc_protofmly = nconf->nc_protofmly;
+ a->r_nc_proto = nconf->nc_proto;
+ rp->rpcb_entry_next = NULL;
+ if (rlist == NULL) {
+ rlist = rp;
+ tail = rp;
+ } else {
+ tail->rpcb_entry_next = rp;
+ tail = rp;
+ }
+ rp = NULL;
+ }
+ }
+#ifdef RPCBIND_DEBUG
+ if (debugging) {
+ for (rp = rlist; rp; rp = rp->rpcb_entry_next) {
+ fprintf(stderr, "\t%s %s\n", rp->rpcb_entry_map.r_maddr,
+ rp->rpcb_entry_map.r_nc_proto);
+ }
+ }
+#endif
+ /*
+ * XXX: getaddrlist info is also being stuffed into getaddr.
+ * Perhaps wrong, but better than it not getting counted at all.
+ */
+ rpcbs_getaddr(RPCBVERS4 - 2, prog, vers, transp->xp_netid, maddr);
+ return (void *)&rlist;
+
+fail: free_rpcb_entry_list(&rlist);
+ return (NULL);
+}
+
+/*
+ * Free only the allocated structure, rest is all a pointer to some
+ * other data somewhere else.
+ */
+static void
+free_rpcb_entry_list(rpcb_entry_list_ptr *rlistp)
+{
+ register rpcb_entry_list_ptr rbl, tmp;
+
+ for (rbl = *rlistp; rbl != NULL; ) {
+ tmp = rbl;
+ rbl = rbl->rpcb_entry_next;
+ free((char *)tmp->rpcb_entry_map.r_maddr);
+ free((char *)tmp);
+ }
+ *rlistp = NULL;
+}
+
+/* ARGSUSED */
+static void *
+rpcbproc_dump_4_local(void *arg, struct svc_req *req, SVCXPRT *xprt,
+ rpcvers_t versnum)
+{
+ return ((void *)&list_rbl);
+}
diff --git a/usr.sbin/rpcbind/rpcb_svc_com.c b/usr.sbin/rpcbind/rpcb_svc_com.c
new file mode 100644
index 0000000..e0c7487
--- /dev/null
+++ b/usr.sbin/rpcbind/rpcb_svc_com.c
@@ -0,0 +1,1457 @@
+/* $NetBSD: rpcb_svc_com.c,v 1.6 2000/08/03 00:07:22 fvdl Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/* #ident "@(#)rpcb_svc_com.c 1.18 94/05/02 SMI" */
+
+/*
+ * rpcb_svc_com.c
+ * The commom server procedure for the rpcbind.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcb_prot.h>
+#include <rpc/svc_dg.h>
+#include <netconfig.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdio.h>
+#ifdef PORTMAP
+#include <netinet/in.h>
+#include <rpc/pmap_prot.h>
+#endif /* PORTMAP */
+#include <string.h>
+#include <stdlib.h>
+
+#include "rpcbind.h"
+
+#define RPC_BUF_MAX 65536 /* can be raised if required */
+
+static char *nullstring = "";
+static int rpcb_rmtcalls;
+
+struct rmtcallfd_list {
+ int fd;
+ SVCXPRT *xprt;
+ char *netid;
+ struct rmtcallfd_list *next;
+};
+
+#define NFORWARD 64
+#define MAXTIME_OFF 300 /* 5 minutes */
+
+struct finfo {
+ int flag;
+#define FINFO_ACTIVE 0x1
+ u_int32_t caller_xid;
+ struct netbuf *caller_addr;
+ u_int32_t forward_xid;
+ int forward_fd;
+ char *uaddr;
+ rpcproc_t reply_type;
+ rpcvers_t versnum;
+ time_t time;
+};
+static struct finfo FINFO[NFORWARD];
+
+
+static bool_t xdr_encap_parms __P((XDR *, struct encap_parms *));
+static bool_t xdr_rmtcall_args __P((XDR *, struct r_rmtcall_args *));
+static bool_t xdr_rmtcall_result __P((XDR *, struct r_rmtcall_args *));
+static bool_t xdr_opaque_parms __P((XDR *, struct r_rmtcall_args *));
+static int find_rmtcallfd_by_netid __P((char *));
+static SVCXPRT *find_rmtcallxprt_by_fd __P((int));
+static u_int32_t forward_register __P((u_int32_t, struct netbuf *, int, char *,
+ rpcproc_t, rpcvers_t));
+static struct finfo *forward_find __P((u_int32_t));
+static int free_slot_by_xid __P((u_int32_t));
+static int free_slot_by_index __P((int));
+static int netbufcmp __P((struct netbuf *, struct netbuf *));
+static struct netbuf *netbufdup __P((struct netbuf *));
+static void netbuffree __P((struct netbuf *));
+static int check_rmtcalls __P((struct pollfd *, int));
+static void xprt_set_caller __P((SVCXPRT *, struct finfo *));
+static void send_svcsyserr __P((SVCXPRT *, struct finfo *));
+static void handle_reply __P((int, SVCXPRT *));
+static void find_versions __P((rpcprog_t, char *, rpcvers_t *, rpcvers_t *));
+static rpcblist_ptr find_service __P((rpcprog_t, rpcvers_t, char *));
+static char *getowner __P((SVCXPRT *, char *, size_t));
+static int add_pmaplist __P((RPCB *));
+static int del_pmaplist __P((RPCB *));
+
+/*
+ * Set a mapping of program, version, netid
+ */
+/* ARGSUSED */
+void *
+rpcbproc_set_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t rpcbversnum)
+{
+ RPCB *regp = (RPCB *)arg;
+ static bool_t ans;
+ char owner[64];
+
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ",
+ (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
+ regp->r_netid, regp->r_addr);
+#endif
+ ans = map_set(regp, getowner(transp, owner, sizeof owner));
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
+#endif
+ /* XXX: should have used some defined constant here */
+ rpcbs_set(rpcbversnum - 2, ans);
+ return (void *)&ans;
+}
+
+bool_t
+map_set(RPCB *regp, char *owner)
+{
+ RPCB reg, *a;
+ rpcblist_ptr rbl, fnd;
+
+ reg = *regp;
+ /*
+ * check to see if already used
+ * find_service returns a hit even if
+ * the versions don't match, so check for it
+ */
+ fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid);
+ if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) {
+ if (!strcmp(fnd->rpcb_map.r_addr, reg.r_addr))
+ /*
+ * if these match then it is already
+ * registered so just say "OK".
+ */
+ return (TRUE);
+ else
+ return (FALSE);
+ }
+ /*
+ * add to the end of the list
+ */
+ rbl = (rpcblist_ptr) malloc((u_int)sizeof (RPCBLIST));
+ if (rbl == (rpcblist_ptr)NULL) {
+ return (FALSE);
+ }
+ a = &(rbl->rpcb_map);
+ a->r_prog = reg.r_prog;
+ a->r_vers = reg.r_vers;
+ a->r_netid = strdup(reg.r_netid);
+ a->r_addr = strdup(reg.r_addr);
+ a->r_owner = strdup(owner);
+ if (!a->r_addr || !a->r_netid || !a->r_owner) {
+ if (a->r_netid)
+ free((void *) a->r_netid);
+ if (a->r_addr)
+ free((void *) a->r_addr);
+ if (a->r_owner)
+ free((void *) a->r_owner);
+ free((void *)rbl);
+ return (FALSE);
+ }
+ rbl->rpcb_next = (rpcblist_ptr)NULL;
+ if (list_rbl == NULL) {
+ list_rbl = rbl;
+ } else {
+ for (fnd = list_rbl; fnd->rpcb_next;
+ fnd = fnd->rpcb_next)
+ ;
+ fnd->rpcb_next = rbl;
+ }
+#ifdef PORTMAP
+ (void) add_pmaplist(regp);
+#endif
+ return (TRUE);
+}
+
+/*
+ * Unset a mapping of program, version, netid
+ */
+/* ARGSUSED */
+void *
+rpcbproc_unset_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t rpcbversnum)
+{
+ RPCB *regp = (RPCB *)arg;
+ static bool_t ans;
+ char owner[64];
+
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ",
+ (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
+ regp->r_netid);
+#endif
+ ans = map_unset(regp, getowner(transp, owner, sizeof owner));
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
+#endif
+ /* XXX: should have used some defined constant here */
+ rpcbs_unset(rpcbversnum - 2, ans);
+ return (void *)&ans;
+}
+
+bool_t
+map_unset(RPCB *regp, char *owner)
+{
+ int ans = 0;
+ rpcblist_ptr rbl, prev, tmp;
+
+ if (owner == NULL)
+ return (0);
+
+ for (prev = NULL, rbl = list_rbl; rbl; /* cstyle */) {
+ if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
+ (rbl->rpcb_map.r_vers != regp->r_vers) ||
+ (regp->r_netid[0] && strcasecmp(regp->r_netid,
+ rbl->rpcb_map.r_netid))) {
+ /* both rbl & prev move forwards */
+ prev = rbl;
+ rbl = rbl->rpcb_next;
+ continue;
+ }
+ /*
+ * Check whether appropriate uid. Unset only
+ * if superuser or the owner itself.
+ */
+ if (strcmp(owner, "superuser") &&
+ strcmp(rbl->rpcb_map.r_owner, owner))
+ return (0);
+ /* found it; rbl moves forward, prev stays */
+ ans = 1;
+ tmp = rbl;
+ rbl = rbl->rpcb_next;
+ if (prev == NULL)
+ list_rbl = rbl;
+ else
+ prev->rpcb_next = rbl;
+ free((void *) tmp->rpcb_map.r_addr);
+ free((void *) tmp->rpcb_map.r_netid);
+ free((void *) tmp->rpcb_map.r_owner);
+ free((void *) tmp);
+ }
+#ifdef PORTMAP
+ if (ans)
+ (void) del_pmaplist(regp);
+#endif
+ /*
+ * We return 1 either when the entry was not there or it
+ * was able to unset it. It can come to this point only if
+ * atleast one of the conditions is true.
+ */
+ return (1);
+}
+
+void
+delete_prog(int prog)
+{
+ RPCB reg;
+ register rpcblist_ptr rbl;
+
+ for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
+ if ((rbl->rpcb_map.r_prog != prog))
+ continue;
+ if (is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr))
+ continue;
+ reg.r_prog = rbl->rpcb_map.r_prog;
+ reg.r_vers = rbl->rpcb_map.r_vers;
+ reg.r_netid = strdup(rbl->rpcb_map.r_netid);
+ (void) map_unset(&reg, "superuser");
+ free(reg.r_netid);
+ }
+}
+
+void *
+rpcbproc_getaddr_com(RPCB *regp, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t rpcbversnum, rpcvers_t verstype)
+{
+ static char *uaddr;
+ char *saddr = NULL;
+ rpcblist_ptr fnd;
+
+ if (uaddr && uaddr[0])
+ free((void *) uaddr);
+ fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
+ if (fnd && ((verstype == RPCB_ALLVERS) ||
+ (regp->r_vers == fnd->rpcb_map.r_vers))) {
+ if (*(regp->r_addr) != '\0') { /* may contain a hint about */
+ saddr = regp->r_addr; /* the interface that we */
+ } /* should use */
+ if (!(uaddr = mergeaddr(transp, transp->xp_netid,
+ fnd->rpcb_map.r_addr, saddr))) {
+ /* Try whatever we have */
+ uaddr = strdup(fnd->rpcb_map.r_addr);
+ } else if (!uaddr[0]) {
+ /*
+ * The server died. Unset all versions of this prog.
+ */
+ delete_prog(regp->r_prog);
+ uaddr = nullstring;
+ }
+ } else {
+ uaddr = nullstring;
+ }
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "getaddr: %s\n", uaddr);
+#endif
+ /* XXX: should have used some defined constant here */
+ rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers,
+ transp->xp_netid, uaddr);
+ return (void *)&uaddr;
+}
+
+/* ARGSUSED */
+void *
+rpcbproc_gettime_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t rpcbversnum)
+{
+ static time_t curtime;
+
+ (void) time(&curtime);
+ return (void *)&curtime;
+}
+
+/*
+ * Convert uaddr to taddr. Should be used only by
+ * local servers/clients. (kernel level stuff only)
+ */
+/* ARGSUSED */
+void *
+rpcbproc_uaddr2taddr_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t rpcbversnum)
+{
+ char **uaddrp = (char **)arg;
+ struct netconfig *nconf;
+ static struct netbuf nbuf;
+ static struct netbuf *taddr;
+
+ if (taddr) {
+ free((void *) taddr->buf);
+ free((void *) taddr);
+ }
+ if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
+ ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
+ (void) memset((char *)&nbuf, 0, sizeof (struct netbuf));
+ return (void *)&nbuf;
+ }
+ return (void *)taddr;
+}
+
+/*
+ * Convert taddr to uaddr. Should be used only by
+ * local servers/clients. (kernel level stuff only)
+ */
+/* ARGSUSED */
+void *
+rpcbproc_taddr2uaddr_com(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
+ rpcvers_t rpcbversnum)
+{
+ struct netbuf *taddr = (struct netbuf *)arg;
+ static char *uaddr;
+ struct netconfig *nconf;
+
+#ifdef CHEW_FDS
+ int fd;
+
+ if ((fd = open("/dev/null", O_RDONLY)) == -1) {
+ uaddr = (char *)strerror(errno);
+ return (&uaddr);
+ }
+#endif /* CHEW_FDS */
+ if (uaddr && !uaddr[0])
+ free((void *) uaddr);
+ if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
+ ((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) {
+ uaddr = nullstring;
+ }
+ return (void *)&uaddr;
+}
+
+
+static bool_t
+xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
+{
+ return (xdr_bytes(xdrs, &(epp->args), (u_int *) &(epp->arglen), ~0));
+}
+
+/*
+ * XDR remote call arguments. It ignores the address part.
+ * written for XDR_DECODE direction only
+ */
+static bool_t
+xdr_rmtcall_args(XDR *xdrs, struct r_rmtcall_args *cap)
+{
+ /* does not get the address or the arguments */
+ if (xdr_u_int32_t(xdrs, &(cap->rmt_prog)) &&
+ xdr_u_int32_t(xdrs, &(cap->rmt_vers)) &&
+ xdr_u_int32_t(xdrs, &(cap->rmt_proc))) {
+ return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
+ }
+ return (FALSE);
+}
+
+/*
+ * XDR remote call results along with the address. Ignore
+ * program number, version number and proc number.
+ * Written for XDR_ENCODE direction only.
+ */
+static bool_t
+xdr_rmtcall_result(XDR *xdrs, struct r_rmtcall_args *cap)
+{
+ bool_t result;
+
+#ifdef PORTMAP
+ if (cap->rmt_localvers == PMAPVERS) {
+ int h1, h2, h3, h4, p1, p2;
+ u_long port;
+
+ /* interpret the universal address for TCP/IP */
+ if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d",
+ &h1, &h2, &h3, &h4, &p1, &p2) != 6)
+ return (FALSE);
+ port = ((p1 & 0xff) << 8) + (p2 & 0xff);
+ result = xdr_u_long(xdrs, &port);
+ } else
+#endif
+ if ((cap->rmt_localvers == RPCBVERS) ||
+ (cap->rmt_localvers == RPCBVERS4)) {
+ result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr));
+ } else {
+ return (FALSE);
+ }
+ if (result == TRUE)
+ return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
+ return (FALSE);
+}
+
+/*
+ * only worries about the struct encap_parms part of struct r_rmtcall_args.
+ * The arglen must already be set!!
+ */
+static bool_t
+xdr_opaque_parms(XDR *xdrs, struct r_rmtcall_args *cap)
+{
+ return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
+}
+
+static struct rmtcallfd_list *rmthead;
+static struct rmtcallfd_list *rmttail;
+
+int
+create_rmtcall_fd(struct netconfig *nconf)
+{
+ int fd;
+ struct rmtcallfd_list *rmt;
+ SVCXPRT *xprt;
+
+ if ((fd = __rpc_nconf2fd(nconf)) == -1) {
+ if (debugging)
+ fprintf(stderr,
+ "create_rmtcall_fd: couldn't open \"%s\" (errno %d)\n",
+ nconf->nc_device, errno);
+ return (-1);
+ }
+ xprt = svc_tli_create(fd, 0, (struct t_bind *) 0, 0, 0);
+ if (xprt == NULL) {
+ if (debugging)
+ fprintf(stderr,
+ "create_rmtcall_fd: svc_tli_create failed\n");
+ return (-1);
+ }
+ rmt = (struct rmtcallfd_list *)malloc((u_int)
+ sizeof (struct rmtcallfd_list));
+ if (rmt == NULL) {
+ syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
+ return (-1);
+ }
+ rmt->xprt = xprt;
+ rmt->netid = strdup(nconf->nc_netid);
+ xprt->xp_netid = rmt->netid;
+ rmt->fd = fd;
+ rmt->next = NULL;
+ if (rmthead == NULL) {
+ rmthead = rmt;
+ rmttail = rmt;
+ } else {
+ rmttail->next = rmt;
+ rmttail = rmt;
+ }
+ /* XXX not threadsafe */
+ if (fd > svc_maxfd)
+ svc_maxfd = fd;
+ FD_SET(fd, &svc_fdset);
+ return (fd);
+}
+
+static int
+find_rmtcallfd_by_netid(char *netid)
+{
+ struct rmtcallfd_list *rmt;
+
+ for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
+ if (strcmp(netid, rmt->netid) == 0) {
+ return (rmt->fd);
+ }
+ }
+ return (-1);
+}
+
+static SVCXPRT *
+find_rmtcallxprt_by_fd(int fd)
+{
+ struct rmtcallfd_list *rmt;
+
+ for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
+ if (fd == rmt->fd) {
+ return (rmt->xprt);
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * Call a remote procedure service. This procedure is very quiet when things
+ * go wrong. The proc is written to support broadcast rpc. In the broadcast
+ * case, a machine should shut-up instead of complain, lest the requestor be
+ * overrun with complaints at the expense of not hearing a valid reply.
+ * When receiving a request and verifying that the service exists, we
+ *
+ * receive the request
+ *
+ * open a new TLI endpoint on the same transport on which we received
+ * the original request
+ *
+ * remember the original request's XID (which requires knowing the format
+ * of the svc_dg_data structure)
+ *
+ * forward the request, with a new XID, to the requested service,
+ * remembering the XID used to send this request (for later use in
+ * reassociating the answer with the original request), the requestor's
+ * address, the file descriptor on which the forwarded request is
+ * made and the service's address.
+ *
+ * mark the file descriptor on which we anticipate receiving a reply from
+ * the service and one to select for in our private svc_run procedure
+ *
+ * At some time in the future, a reply will be received from the service to
+ * which we forwarded the request. At that time, we detect that the socket
+ * used was for forwarding (by looking through the finfo structures to see
+ * whether the fd corresponds to one of those) and call handle_reply() to
+ *
+ * receive the reply
+ *
+ * bundle the reply, along with the service's universal address
+ *
+ * create a SVCXPRT structure and use a version of svc_sendreply
+ * that allows us to specify the reply XID and destination, send the reply
+ * to the original requestor.
+ */
+
+void
+rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp,
+ rpcproc_t reply_type, rpcvers_t versnum)
+{
+ register rpcblist_ptr rbl;
+ struct netconfig *nconf;
+ struct netbuf *caller;
+ struct r_rmtcall_args a;
+ char *buf_alloc = NULL, *outbufp;
+ char *outbuf_alloc = NULL;
+ char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX];
+ struct netbuf *na = (struct netbuf *) NULL;
+ struct rpc_msg call_msg;
+ int outlen;
+ u_int sendsz;
+ XDR outxdr;
+ AUTH *auth;
+ int fd = -1;
+ char *uaddr, *m_uaddr, *local_uaddr = NULL;
+ u_int32_t *xidp;
+ struct __rpc_sockinfo si;
+ struct sockaddr *localsa;
+ struct netbuf tbuf;
+
+ if (!__rpc_fd2sockinfo(transp->xp_fd, &si)) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ return;
+ }
+ if (si.si_socktype != SOCK_DGRAM)
+ return; /* Only datagram type accepted */
+ sendsz = __rpc_get_t_size(si.si_af, si.si_proto, UDPMSGSIZE);
+ if (sendsz == 0) { /* data transfer not supported */
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ return;
+ }
+ /*
+ * Should be multiple of 4 for XDR.
+ */
+ sendsz = ((sendsz + 3) / 4) * 4;
+ if (sendsz > RPC_BUF_MAX) {
+#ifdef notyet
+ buf_alloc = alloca(sendsz); /* not in IDR2? */
+#else
+ buf_alloc = malloc(sendsz);
+#endif /* notyet */
+ if (buf_alloc == NULL) {
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: No Memory!\n");
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ return;
+ }
+ a.rmt_args.args = buf_alloc;
+ } else {
+ a.rmt_args.args = buf;
+ }
+
+ call_msg.rm_xid = 0; /* For error checking purposes */
+ if (!svc_getargs(transp, (xdrproc_t) xdr_rmtcall_args, (char *) &a)) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_decode(transp);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: svc_getargs failed\n");
+ goto error;
+ }
+
+ if (!check_callit(transp, &a, versnum)) {
+ svcerr_weakauth(transp);
+ goto error;
+ }
+
+ caller = svc_getrpccaller(transp);
+#ifdef RPCBIND_DEBUG
+ if (debugging) {
+ uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller);
+ fprintf(stderr, "%s %s req for (%lu, %lu, %lu, %s) from %s : ",
+ versnum == PMAPVERS ? "pmap_rmtcall" :
+ versnum == RPCBVERS ? "rpcb_rmtcall" :
+ versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
+ reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit",
+ (unsigned long)a.rmt_prog, (unsigned long)a.rmt_vers,
+ (unsigned long)a.rmt_proc, transp->xp_netid,
+ uaddr ? uaddr : "unknown");
+ if (uaddr)
+ free((void *) uaddr);
+ }
+#endif
+
+ rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid);
+
+ rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers,
+ a.rmt_proc, transp->xp_netid, rbl);
+
+ if (rbl == (rpcblist_ptr)NULL) {
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "not found\n");
+#endif
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_noprog(transp);
+ goto error;
+ }
+ if (rbl->rpcb_map.r_vers != a.rmt_vers) {
+ if (reply_type == RPCBPROC_INDIRECT) {
+ rpcvers_t vers_low, vers_high;
+
+ find_versions(a.rmt_prog, transp->xp_netid,
+ &vers_low, &vers_high);
+ svcerr_progvers(transp, vers_low, vers_high);
+ }
+ goto error;
+ }
+
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
+#endif
+ /*
+ * Check whether this entry is valid and a server is present
+ * Mergeaddr() returns NULL if no such entry is present, and
+ * returns "" if the entry was present but the server is not
+ * present (i.e., it crashed).
+ */
+ if (reply_type == RPCBPROC_INDIRECT) {
+ uaddr = mergeaddr(transp, transp->xp_netid,
+ rbl->rpcb_map.r_addr, NULL);
+ if ((uaddr == (char *) NULL) || uaddr[0] == '\0') {
+ svcerr_noprog(transp);
+ if (uaddr != NULL) {
+ free((void *) uaddr);
+ }
+ goto error;
+ }
+ if (uaddr != NULL) {
+ free((void *) uaddr);
+ }
+ }
+ nconf = rpcbind_get_conf(transp->xp_netid);
+ if (nconf == (struct netconfig *)NULL) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: rpcbind_get_conf failed\n");
+ goto error;
+ }
+ localsa = local_sa(((struct sockaddr *)caller->buf)->sa_family);
+ if (localsa == NULL) {
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: no local address\n");
+ goto error;
+ }
+ tbuf.len = tbuf.maxlen = localsa->sa_len;
+ tbuf.buf = localsa;
+ local_uaddr =
+ addrmerge(&tbuf, rbl->rpcb_map.r_addr, NULL, nconf->nc_netid);
+ m_uaddr = addrmerge(caller, rbl->rpcb_map.r_addr, NULL,
+ nconf->nc_netid);
+#ifdef RPCBIND_DEBUG
+ if (debugging)
+ fprintf(stderr, "merged uaddr %s\n", m_uaddr);
+#endif
+ if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ free((void *) m_uaddr);
+ goto error;
+ }
+ xidp = __rpcb_get_dg_xidp(transp);
+ call_msg.rm_xid = forward_register(*xidp,
+ caller, fd, m_uaddr, reply_type, versnum);
+ if (call_msg.rm_xid == 0) {
+ /*
+ * A duplicate request for the slow server. Let's not
+ * beat on it any more.
+ */
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: duplicate request\n");
+ free((void *) m_uaddr);
+ goto error;
+ } else if (call_msg.rm_xid == -1) {
+ /* forward_register failed. Perhaps no memory. */
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: forward_register failed\n");
+ free((void *) m_uaddr);
+ goto error;
+ }
+
+#ifdef DEBUG_RMTCALL
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: original XID %x, new XID %x\n",
+ *xidp, call_msg.rm_xid);
+#endif
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ call_msg.rm_call.cb_prog = a.rmt_prog;
+ call_msg.rm_call.cb_vers = a.rmt_vers;
+ if (sendsz > RPC_BUF_MAX) {
+#ifdef notyet
+ outbuf_alloc = alloca(sendsz); /* not in IDR2? */
+#else
+ outbuf_alloc = malloc(sendsz);
+#endif /* notyet */
+ if (outbuf_alloc == NULL) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: No memory!\n");
+ goto error;
+ }
+ xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
+ } else {
+ xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
+ }
+ if (!xdr_callhdr(&outxdr, &call_msg)) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: xdr_callhdr failed\n");
+ goto error;
+ }
+ if (!xdr_u_int32_t(&outxdr, &(a.rmt_proc))) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: xdr_u_long failed\n");
+ goto error;
+ }
+
+ if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
+ auth = authnone_create();
+ } else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
+ struct authunix_parms *au;
+
+ au = (struct authunix_parms *)rqstp->rq_clntcred;
+ auth = authunix_create(au->aup_machname,
+ au->aup_uid, au->aup_gid,
+ au->aup_len, au->aup_gids);
+ if (auth == NULL) /* fall back */
+ auth = authnone_create();
+ } else {
+ /* we do not support any other authentication scheme */
+ if (debugging)
+ fprintf(stderr,
+"rpcbproc_callit_com: oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n");
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_weakauth(transp); /* XXX too strong.. */
+ goto error;
+ }
+ if (auth == NULL) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: authwhatever_create returned NULL\n");
+ goto error;
+ }
+ if (!AUTH_MARSHALL(auth, &outxdr)) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ AUTH_DESTROY(auth);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: AUTH_MARSHALL failed\n");
+ goto error;
+ }
+ AUTH_DESTROY(auth);
+ if (!xdr_opaque_parms(&outxdr, &a)) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: xdr_opaque_parms failed\n");
+ goto error;
+ }
+ outlen = (int) XDR_GETPOS(&outxdr);
+ if (outbuf_alloc)
+ outbufp = outbuf_alloc;
+ else
+ outbufp = outbuf;
+
+ na = uaddr2taddr(nconf, local_uaddr);
+ if (!na) {
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ goto error;
+ }
+
+ if (sendto(fd, outbufp, outlen, 0, (struct sockaddr *)na->buf, na->len)
+ != outlen) {
+ if (debugging)
+ fprintf(stderr,
+ "rpcbproc_callit_com: sendto failed: errno %d\n", errno);
+ if (reply_type == RPCBPROC_INDIRECT)
+ svcerr_systemerr(transp);
+ goto error;
+ }
+ goto out;
+
+error:
+ if (call_msg.rm_xid != 0)
+ (void) free_slot_by_xid(call_msg.rm_xid);
+out:
+ if (local_uaddr)
+ free(local_uaddr);
+ if (buf_alloc)
+ free((void *) buf_alloc);
+ if (outbuf_alloc)
+ free((void *) outbuf_alloc);
+ if (na) {
+ free(na->buf);
+ free(na);
+ }
+}
+
+/*
+ * Makes an entry into the FIFO for the given request.
+ * If duplicate request, returns a 0, else returns the xid of its call.
+ */
+static u_int32_t
+forward_register(u_int32_t caller_xid, struct netbuf *caller_addr,
+ int forward_fd, char *uaddr, rpcproc_t reply_type,
+ rpcvers_t versnum)
+{
+ int i;
+ int j = 0;
+ time_t min_time, time_now;
+ static u_int32_t lastxid;
+ int entry = -1;
+
+ min_time = FINFO[0].time;
+ time_now = time((time_t *)0);
+ /* initialization */
+ if (lastxid == 0)
+ lastxid = time_now * NFORWARD;
+
+ /*
+ * Check if it is an duplicate entry. Then,
+ * try to find an empty slot. If not available, then
+ * use the slot with the earliest time.
+ */
+ for (i = 0; i < NFORWARD; i++) {
+ if (FINFO[i].flag & FINFO_ACTIVE) {
+ if ((FINFO[i].caller_xid == caller_xid) &&
+ (FINFO[i].reply_type == reply_type) &&
+ (FINFO[i].versnum == versnum) &&
+ (!netbufcmp(FINFO[i].caller_addr,
+ caller_addr))) {
+ FINFO[i].time = time((time_t *)0);
+ return (0); /* Duplicate entry */
+ } else {
+ /* Should we wait any longer */
+ if ((time_now - FINFO[i].time) > MAXTIME_OFF)
+ (void) free_slot_by_index(i);
+ }
+ }
+ if (entry == -1) {
+ if ((FINFO[i].flag & FINFO_ACTIVE) == 0) {
+ entry = i;
+ } else if (FINFO[i].time < min_time) {
+ j = i;
+ min_time = FINFO[i].time;
+ }
+ }
+ }
+ if (entry != -1) {
+ /* use this empty slot */
+ j = entry;
+ } else {
+ (void) free_slot_by_index(j);
+ }
+ if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) {
+ return (-1);
+ }
+ rpcb_rmtcalls++; /* no of pending calls */
+ FINFO[j].flag = FINFO_ACTIVE;
+ FINFO[j].reply_type = reply_type;
+ FINFO[j].versnum = versnum;
+ FINFO[j].time = time_now;
+ FINFO[j].caller_xid = caller_xid;
+ FINFO[j].forward_fd = forward_fd;
+ /*
+ * Though uaddr is not allocated here, it will still be freed
+ * from free_slot_*().
+ */
+ FINFO[j].uaddr = uaddr;
+ lastxid = lastxid + NFORWARD;
+ FINFO[j].forward_xid = lastxid + j; /* encode slot */
+ return (FINFO[j].forward_xid); /* forward on this xid */
+}
+
+static struct finfo *
+forward_find(u_int32_t reply_xid)
+{
+ int i;
+
+ i = reply_xid % NFORWARD;
+ if (i < 0)
+ i += NFORWARD;
+ if ((FINFO[i].flag & FINFO_ACTIVE) &&
+ (FINFO[i].forward_xid == reply_xid)) {
+ return (&FINFO[i]);
+ }
+ return (NULL);
+}
+
+static int
+free_slot_by_xid(u_int32_t xid)
+{
+ int entry;
+
+ entry = xid % NFORWARD;
+ if (entry < 0)
+ entry += NFORWARD;
+ return (free_slot_by_index(entry));
+}
+
+static int
+free_slot_by_index(int index)
+{
+ struct finfo *fi;
+
+ fi = &FINFO[index];
+ if (fi->flag & FINFO_ACTIVE) {
+ netbuffree(fi->caller_addr);
+ /* XXX may be too big, but can't access xprt array here */
+ if (fi->forward_fd >= svc_maxfd)
+ svc_maxfd--;
+ free((void *) fi->uaddr);
+ fi->flag &= ~FINFO_ACTIVE;
+ rpcb_rmtcalls--;
+ return (1);
+ }
+ return (0);
+}
+
+static int
+netbufcmp(struct netbuf *n1, struct netbuf *n2)
+{
+ return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
+}
+
+static struct netbuf *
+netbufdup(struct netbuf *ap)
+{
+ struct netbuf *np;
+
+ np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
+ if (np) {
+ np->maxlen = np->len = ap->len;
+ np->buf = ((char *) np) + sizeof (struct netbuf);
+ (void) memcpy(np->buf, ap->buf, ap->len);
+ }
+ return (np);
+}
+
+static void
+netbuffree(struct netbuf *ap)
+{
+ free((void *) ap);
+}
+
+
+#define MASKVAL (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
+
+void
+my_svc_run()
+{
+ size_t nfds;
+ struct pollfd pollfds[FD_SETSIZE];
+ int poll_ret, check_ret;
+ int n;
+#ifdef SVC_RUN_DEBUG
+ int i;
+#endif
+ register struct pollfd *p;
+
+ for (;;) {
+ p = pollfds;
+ for (n = 0; n <= svc_maxfd; n++) {
+ if (FD_ISSET(n, &svc_fdset)) {
+ p->fd = n;
+ p->events = MASKVAL;
+ p++;
+ }
+ }
+ nfds = p - pollfds;
+ poll_ret = 0;
+#ifdef SVC_RUN_DEBUG
+ if (debugging) {
+ fprintf(stderr, "polling for read on fd < ");
+ for (i = 0, p = pollfds; i < nfds; i++, p++)
+ if (p->events)
+ fprintf(stderr, "%d ", p->fd);
+ fprintf(stderr, ">\n");
+ }
+#endif
+ switch (poll_ret = poll(pollfds, nfds, INFTIM)) {
+ case -1:
+ /*
+ * We ignore all errors, continuing with the assumption
+ * that it was set by the signal handlers (or any
+ * other outside event) and not caused by poll().
+ */
+ case 0:
+ continue;
+ default:
+#ifdef SVC_RUN_DEBUG
+ if (debugging) {
+ fprintf(stderr, "poll returned read fds < ");
+ for (i = 0, p = pollfds; i < nfds; i++, p++)
+ if (p->revents)
+ fprintf(stderr, "%d ", p->fd);
+ fprintf(stderr, ">\n");
+ }
+#endif
+ /*
+ * If we found as many replies on callback fds
+ * as the number of descriptors selectable which
+ * poll() returned, there can be no more so we
+ * don't call svc_getreq_poll. Otherwise, there
+ * must be another so we must call svc_getreq_poll.
+ */
+ if ((check_ret = check_rmtcalls(pollfds, nfds)) ==
+ poll_ret)
+ continue;
+ svc_getreq_poll(pollfds, poll_ret-check_ret);
+ }
+#ifdef SVC_RUN_DEBUG
+ if (debugging) {
+ fprintf(stderr, "svc_maxfd now %u\n", svc_maxfd);
+ }
+#endif
+ }
+}
+
+static int
+check_rmtcalls(struct pollfd *pfds, int nfds)
+{
+ int j, ncallbacks_found = 0, rmtcalls_pending;
+ SVCXPRT *xprt;
+
+ if (rpcb_rmtcalls == 0)
+ return (0);
+
+ rmtcalls_pending = rpcb_rmtcalls;
+ for (j = 0; j < nfds; j++) {
+ if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) {
+ if (pfds[j].revents) {
+ ncallbacks_found++;
+#ifdef DEBUG_RMTCALL
+ if (debugging)
+ fprintf(stderr,
+"my_svc_run: polled on forwarding fd %d, netid %s - calling handle_reply\n",
+ pfds[j].fd, xprt->xp_netid);
+#endif
+ handle_reply(pfds[j].fd, xprt);
+ pfds[j].revents = 0;
+ if (ncallbacks_found >= rmtcalls_pending) {
+ break;
+ }
+ }
+ }
+ }
+ return (ncallbacks_found);
+}
+
+static void
+xprt_set_caller(SVCXPRT *xprt, struct finfo *fi)
+{
+ u_int32_t *xidp;
+
+ *(svc_getrpccaller(xprt)) = *(fi->caller_addr);
+ xidp = __rpcb_get_dg_xidp(xprt);
+ *xidp = fi->caller_xid;
+}
+
+/*
+ * Call svcerr_systemerr() only if RPCBVERS4
+ */
+static void
+send_svcsyserr(SVCXPRT *xprt, struct finfo *fi)
+{
+ if (fi->reply_type == RPCBPROC_INDIRECT) {
+ xprt_set_caller(xprt, fi);
+ svcerr_systemerr(xprt);
+ }
+ return;
+}
+
+static void
+handle_reply(int fd, SVCXPRT *xprt)
+{
+ XDR reply_xdrs;
+ struct rpc_msg reply_msg;
+ struct rpc_err reply_error;
+ char *buffer;
+ struct finfo *fi;
+ int inlen, pos, len;
+ struct r_rmtcall_args a;
+ struct sockaddr_storage ss;
+ socklen_t fromlen;
+#ifdef SVC_RUN_DEBUG
+ char *uaddr;
+#endif
+
+ buffer = malloc(RPC_BUF_MAX);
+ if (buffer == NULL)
+ goto done;
+
+ do {
+ inlen = recvfrom(fd, buffer, RPC_BUF_MAX, 0,
+ (struct sockaddr *)&ss, &fromlen);
+ } while (inlen < 0 && errno == EINTR);
+ if (inlen < 0) {
+ if (debugging)
+ fprintf(stderr,
+ "handle_reply: recvfrom returned %d, errno %d\n", inlen, errno);
+ goto done;
+ }
+
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = 0;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+
+ xdrmem_create(&reply_xdrs, buffer, (u_int)inlen, XDR_DECODE);
+ if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
+ if (debugging)
+ (void) fprintf(stderr,
+ "handle_reply: xdr_replymsg failed\n");
+ goto done;
+ }
+ fi = forward_find(reply_msg.rm_xid);
+#ifdef SVC_RUN_DEBUG
+ if (debugging) {
+ fprintf(stderr, "handle_reply: reply xid: %d fi addr: %p\n",
+ reply_msg.rm_xid, fi);
+ }
+#endif
+ if (fi == NULL) {
+ goto done;
+ }
+ _seterr_reply(&reply_msg, &reply_error);
+ if (reply_error.re_status != RPC_SUCCESS) {
+ if (debugging)
+ (void) fprintf(stderr, "handle_reply: %s\n",
+ clnt_sperrno(reply_error.re_status));
+ send_svcsyserr(xprt, fi);
+ goto done;
+ }
+ pos = XDR_GETPOS(&reply_xdrs);
+ len = inlen - pos;
+ a.rmt_args.args = &buffer[pos];
+ a.rmt_args.arglen = len;
+ a.rmt_uaddr = fi->uaddr;
+ a.rmt_localvers = fi->versnum;
+
+ xprt_set_caller(xprt, fi);
+#ifdef SVC_RUN_DEBUG
+ uaddr = taddr2uaddr(rpcbind_get_conf("udp"),
+ svc_getrpccaller(xprt));
+ if (debugging) {
+ fprintf(stderr, "handle_reply: forwarding address %s to %s\n",
+ a.rmt_uaddr, uaddr ? uaddr : "unknown");
+ }
+ if (uaddr)
+ free((void *) uaddr);
+#endif
+ svc_sendreply(xprt, (xdrproc_t) xdr_rmtcall_result, (char *) &a);
+done:
+ if (buffer)
+ free(buffer);
+
+ if (reply_msg.rm_xid == 0) {
+#ifdef SVC_RUN_DEBUG
+ if (debugging) {
+ fprintf(stderr, "handle_reply: NULL xid on exit!\n");
+ }
+#endif
+ } else
+ (void) free_slot_by_xid(reply_msg.rm_xid);
+ return;
+}
+
+static void
+find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
+{
+ register rpcblist_ptr rbl;
+ int lowv = 0;
+ int highv = 0;
+
+ for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
+ if ((rbl->rpcb_map.r_prog != prog) ||
+ ((rbl->rpcb_map.r_netid != NULL) &&
+ (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
+ continue;
+ if (lowv == 0) {
+ highv = rbl->rpcb_map.r_vers;
+ lowv = highv;
+ } else if (rbl->rpcb_map.r_vers < lowv) {
+ lowv = rbl->rpcb_map.r_vers;
+ } else if (rbl->rpcb_map.r_vers > highv) {
+ highv = rbl->rpcb_map.r_vers;
+ }
+ }
+ *lowvp = lowv;
+ *highvp = highv;
+ return;
+}
+
+/*
+ * returns the item with the given program, version number and netid.
+ * If that version number is not found, it returns the item with that
+ * program number, so that address is now returned to the caller. The
+ * caller when makes a call to this program, version number, the call
+ * will fail and it will return with PROGVERS_MISMATCH. The user can
+ * then determine the highest and the lowest version number for this
+ * program using clnt_geterr() and use those program version numbers.
+ *
+ * Returns the RPCBLIST for the given prog, vers and netid
+ */
+static rpcblist_ptr
+find_service(rpcprog_t prog, rpcvers_t vers, char *netid)
+{
+ register rpcblist_ptr hit = NULL;
+ register rpcblist_ptr rbl;
+
+ for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
+ if ((rbl->rpcb_map.r_prog != prog) ||
+ ((rbl->rpcb_map.r_netid != NULL) &&
+ (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
+ continue;
+ hit = rbl;
+ if (rbl->rpcb_map.r_vers == vers)
+ break;
+ }
+ return (hit);
+}
+
+/*
+ * Copies the name associated with the uid of the caller and returns
+ * a pointer to it. Similar to getwd().
+ */
+static char *
+getowner(SVCXPRT *transp, char *owner, size_t ownersize)
+{
+ struct cmsgcred *cmcred;
+
+ cmcred = __svc_getcallercreds(transp);
+ if (cmcred == NULL)
+ strlcpy(owner, "unknown", ownersize);
+ else if (cmcred->cmcred_uid == 0)
+ strlcpy(owner, "superuser", ownersize);
+ else
+ snprintf(owner, ownersize, "%d", cmcred->cmcred_uid);
+
+ return owner;
+}
+
+#ifdef PORTMAP
+/*
+ * Add this to the pmap list only if it is UDP or TCP.
+ */
+static int
+add_pmaplist(RPCB *arg)
+{
+ struct pmap pmap;
+ struct pmaplist *pml;
+ int h1, h2, h3, h4, p1, p2;
+
+ if (strcmp(arg->r_netid, udptrans) == 0) {
+ /* It is UDP! */
+ pmap.pm_prot = IPPROTO_UDP;
+ } else if (strcmp(arg->r_netid, tcptrans) == 0) {
+ /* It is TCP */
+ pmap.pm_prot = IPPROTO_TCP;
+ } else
+ /* Not a IP protocol */
+ return (0);
+
+ /* interpret the universal address for TCP/IP */
+ if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
+ &h1, &h2, &h3, &h4, &p1, &p2) != 6)
+ return (0);
+ pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
+ pmap.pm_prog = arg->r_prog;
+ pmap.pm_vers = arg->r_vers;
+ /*
+ * add to END of list
+ */
+ pml = (struct pmaplist *) malloc((u_int)sizeof (struct pmaplist));
+ if (pml == NULL) {
+ (void) syslog(LOG_ERR, "rpcbind: no memory!\n");
+ return (1);
+ }
+ pml->pml_map = pmap;
+ pml->pml_next = NULL;
+ if (list_pml == NULL) {
+ list_pml = pml;
+ } else {
+ struct pmaplist *fnd;
+
+ /* Attach to the end of the list */
+ for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
+ ;
+ fnd->pml_next = pml;
+ }
+ return (0);
+}
+
+/*
+ * Delete this from the pmap list only if it is UDP or TCP.
+ */
+static int
+del_pmaplist(RPCB *arg)
+{
+ struct pmaplist *pml;
+ struct pmaplist *prevpml, *fnd;
+ long prot;
+
+ if (strcmp(arg->r_netid, udptrans) == 0) {
+ /* It is UDP! */
+ prot = IPPROTO_UDP;
+ } else if (strcmp(arg->r_netid, tcptrans) == 0) {
+ /* It is TCP */
+ prot = IPPROTO_TCP;
+ } else if (arg->r_netid[0] == NULL) {
+ prot = 0; /* Remove all occurrences */
+ } else {
+ /* Not a IP protocol */
+ return (0);
+ }
+ for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
+ if ((pml->pml_map.pm_prog != arg->r_prog) ||
+ (pml->pml_map.pm_vers != arg->r_vers) ||
+ (prot && (pml->pml_map.pm_prot != prot))) {
+ /* both pml & prevpml move forwards */
+ prevpml = pml;
+ pml = pml->pml_next;
+ continue;
+ }
+ /* found it; pml moves forward, prevpml stays */
+ fnd = pml;
+ pml = pml->pml_next;
+ if (prevpml == NULL)
+ list_pml = pml;
+ else
+ prevpml->pml_next = pml;
+ free((void *) fnd);
+ }
+ return (0);
+}
+#endif /* PORTMAP */
diff --git a/usr.sbin/rpcbind/rpcbind.8 b/usr.sbin/rpcbind/rpcbind.8
new file mode 100644
index 0000000..34fea3df
--- /dev/null
+++ b/usr.sbin/rpcbind/rpcbind.8
@@ -0,0 +1,112 @@
+.\" @(#)rpcbind.1m 1.19 92/09/14 SMI; from SVr4
+.\" Copyright 1989 AT&T
+.\" Copyright 1991 Sun Microsystems, Inc.
+.\" $FreeBSD$
+.Dd September 14, 1992
+.Dt RPCBIND 8
+.Os
+.Sh NAME
+.Nm rpcbind
+.Nd universal addresses to RPC program number mapper
+.Sh SYNOPSIS
+.Nm
+.Op Fl dilLs
+.Sh DESCRIPTION
+.Nm
+is a server that converts
+.Tn RPC
+program numbers into
+universal addresses.
+It must be running on the host to be able to make
+.Tn RPC
+calls
+on a server on that machine.
+.Pp
+When an
+.Tn RPC
+service is started,
+it tells
+.Nm
+the address at which it is listening,
+and the
+.Tn RPC
+program numbers it is prepared to serve.
+When a client wishes to make an
+.Tn RPC
+call to a given program number,
+it first contacts
+.Nm
+on the server machine to determine
+the address where
+.Tn RPC
+requests should be sent.
+.Pp
+.Nm
+should be started before any other RPC service.
+Normally, standard
+.Tn RPC
+servers are started by port monitors, so
+.Nm
+must be started before port monitors are invoked.
+.Pp
+When
+.Nm
+is started, it checks that certain name-to-address
+translation-calls function correctly.
+If they fail, the network configuration databases may be corrupt.
+Since
+.Tn RPC
+services cannot function correctly in this situation,
+.Nm
+reports the condition and terminates.
+.Pp
+.Nm
+can only be started by the super-user.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl d
+Run in debug mode.
+In this mode,
+.Nm
+will not fork when it starts, will print additional information
+during operation, and will abort on certain errors.
+With this option, the name-to-address translation consistency
+checks are shown in detail.
+.It Fl i
+.Dq insecure
+mode.
+Allows calls to SET and UNSET from any host.
+Normally
+.Nm
+accepts these requests only from the loopback interface for security reasons.
+This change is necessary for programs that were compiled with earlier
+versions of the rpc library and do not make those requests using the
+loopback interface.
+.It Fl l
+Turns on libwrap connection logging.
+.It Fl s
+causes
+.Nm
+to change to the user daemon as soon as possible.
+This causes
+.Nm
+to use non-privileged ports for outgoing connections, preventing non-privileged
+clients from using
+.Nm
+to connect to services from a privileged port.
+.It Fl L
+Allow old-style local connections over the loopback interface.
+Without this flag, local connections are only allowed over a local socket,
+.Pa /var/run/rpcbind.sock
+.El
+.Sh NOTES
+All RPC servers must be restarted if
+.Nm
+is restarted.
+.Sh SEE ALSO
+.Xr rpcbind 3 ,
+.Xr rpcinfo 8
+.Sh FILES
+.Bl -tag -width /var/run/rpcbind.sock -compact
+.It Pa /var/run/rpcbind.sock
+.El
diff --git a/usr.sbin/rpcbind/rpcbind.c b/usr.sbin/rpcbind/rpcbind.c
new file mode 100644
index 0000000..2ddf2c0
--- /dev/null
+++ b/usr.sbin/rpcbind/rpcbind.c
@@ -0,0 +1,568 @@
+/* $NetBSD: rpcbind.c,v 1.1 2000/06/02 23:15:42 fvdl Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
+ */
+
+/* #ident "@(#)rpcbind.c 1.19 94/04/25 SMI" */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
+#endif
+#endif
+
+/*
+ * rpcbind.c
+ * Implements the program, version to address mapping for rpc.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <rpc/rpc.h>
+#ifdef PORTMAP
+#include <netinet/in.h>
+#endif
+#include <netdb.h>
+#include <stdio.h>
+#include <netconfig.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <err.h>
+#include <libutil.h>
+#include <pwd.h>
+#include <string.h>
+#include <errno.h>
+#include "rpcbind.h"
+
+/* Global variables */
+int debugging = 0; /* Tell me what's going on */
+int doabort = 0; /* When debugging, do an abort on errors */
+rpcblist_ptr list_rbl; /* A list of version 3/4 rpcbind services */
+
+/* who to suid to if -s is given */
+#define RUN_AS "daemon"
+
+int runasdaemon = 0;
+int insecure = 0;
+int oldstyle_local = 0;
+int verboselog = 0;
+
+#ifdef WARMSTART
+/* Local Variable */
+static int warmstart = 0; /* Grab a old copy of registrations */
+#endif
+
+#ifdef PORTMAP
+struct pmaplist *list_pml; /* A list of version 2 rpcbind services */
+char *udptrans; /* Name of UDP transport */
+char *tcptrans; /* Name of TCP transport */
+char *udp_uaddr; /* Universal UDP address */
+char *tcp_uaddr; /* Universal TCP address */
+#endif
+static char servname[] = "rpcbind";
+static char superuser[] = "superuser";
+
+int main __P((int, char *[]));
+
+static int init_transport __P((struct netconfig *));
+static void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *,
+ struct netbuf *));
+static void terminate __P((int));
+static void parseargs __P((int, char *[]));
+
+int
+main(int argc, char *argv[])
+{
+ struct netconfig *nconf;
+ void *nc_handle; /* Net config handle */
+ struct rlimit rl;
+
+ parseargs(argc, argv);
+
+ getrlimit(RLIMIT_NOFILE, &rl);
+ if (rl.rlim_cur < 128) {
+ if (rl.rlim_max <= 128)
+ rl.rlim_cur = rl.rlim_max;
+ else
+ rl.rlim_cur = 128;
+ setrlimit(RLIMIT_NOFILE, &rl);
+ }
+ openlog("rpcbind", LOG_CONS, LOG_DAEMON);
+ if (geteuid()) { /* This command allowed only to root */
+ fprintf(stderr, "Sorry. You are not superuser\n");
+ exit(1);
+ }
+ nc_handle = setnetconfig(); /* open netconfig file */
+ if (nc_handle == NULL) {
+ syslog(LOG_ERR, "could not read /etc/netconfig");
+ exit(1);
+ }
+#ifdef PORTMAP
+ udptrans = "";
+ tcptrans = "";
+#endif
+
+ nconf = getnetconfigent("unix");
+ if (nconf == NULL) {
+ syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]);
+ exit(1);
+ }
+ init_transport(nconf);
+
+ while ((nconf = getnetconfig(nc_handle))) {
+ if (nconf->nc_flag & NC_VISIBLE)
+ init_transport(nconf);
+ }
+ endnetconfig(nc_handle);
+
+ /* catch the usual termination signals for graceful exit */
+ (void) signal(SIGCHLD, reap);
+ (void) signal(SIGINT, terminate);
+ (void) signal(SIGTERM, terminate);
+ (void) signal(SIGQUIT, terminate);
+ /* ignore others that could get sent */
+ (void) signal(SIGPIPE, SIG_IGN);
+ (void) signal(SIGHUP, SIG_IGN);
+ (void) signal(SIGUSR1, SIG_IGN);
+ (void) signal(SIGUSR2, SIG_IGN);
+#ifdef WARMSTART
+ if (warmstart) {
+ read_warmstart();
+ }
+#endif
+ if (debugging) {
+ printf("rpcbind debugging enabled.");
+ if (doabort) {
+ printf(" Will abort on errors!\n");
+ } else {
+ printf("\n");
+ }
+ } else {
+ if (daemon(0, 0))
+ err(1, "fork failed");
+ }
+
+ if (runasdaemon) {
+ struct passwd *p;
+
+ if((p = getpwnam(RUN_AS)) == NULL) {
+ syslog(LOG_ERR, "cannot get uid of daemon: %m");
+ exit(1);
+ }
+ if (setuid(p->pw_uid) == -1) {
+ syslog(LOG_ERR, "setuid to daemon failed: %m");
+ exit(1);
+ }
+ }
+
+ network_init();
+
+ my_svc_run();
+ syslog(LOG_ERR, "svc_run returned unexpectedly");
+ rpcbind_abort();
+ /* NOTREACHED */
+
+ return 0;
+}
+
+/*
+ * Adds the entry into the rpcbind database.
+ * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
+ * Returns 0 if succeeds, else fails
+ */
+static int
+init_transport(struct netconfig *nconf)
+{
+ int fd;
+ struct t_bind taddr;
+ struct addrinfo hints, *res = NULL;
+ struct __rpc_sockinfo si;
+ SVCXPRT *my_xprt;
+ int status; /* bound checking ? */
+ int aicode;
+ int addrlen;
+ struct sockaddr *sa;
+ struct sockaddr_un sun;
+ mode_t oldmask;
+
+ if ((nconf->nc_semantics != NC_TPI_CLTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS) &&
+ (nconf->nc_semantics != NC_TPI_COTS_ORD))
+ return (1); /* not my type */
+#ifdef ND_DEBUG
+ if (debugging) {
+ int i;
+ char **s;
+
+ (void) fprintf(stderr, "%s: %ld lookup routines :\n",
+ nconf->nc_netid, nconf->nc_nlookups);
+ for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
+ i++, s++)
+ fprintf(stderr, "[%d] - %s\n", i, *s);
+ }
+#endif
+
+ /*
+ * XXX - using RPC library internal functions.
+ */
+ if ((fd = __rpc_nconf2fd(nconf)) < 0) {
+ syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid);
+ return (1);
+ }
+
+ if (!__rpc_nconf2sockinfo(nconf, &si)) {
+ syslog(LOG_ERR, "cannot get information for %s",
+ nconf->nc_netid);
+ return (1);
+ }
+
+ if (!strcmp(nconf->nc_netid, "unix")) {
+ memset(&sun, 0, sizeof sun);
+ sun.sun_family = AF_LOCAL;
+ unlink(_PATH_RPCBINDSOCK);
+ strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
+ sun.sun_len = SUN_LEN(&sun);
+ addrlen = sizeof (struct sockaddr_un);
+ sa = (struct sockaddr *)&sun;
+ } else {
+ /* Get rpcbind's address on this transport */
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = si.si_af;
+ hints.ai_socktype = si.si_socktype;
+ hints.ai_protocol = si.si_proto;
+ if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) {
+ syslog(LOG_ERR, "cannot get local address for %s: %s",
+ nconf->nc_netid, gai_strerror(aicode));
+ return 1;
+ }
+ addrlen = res->ai_addrlen;
+ sa = (struct sockaddr *)res->ai_addr;
+ }
+ oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
+ if (bind(fd, sa, addrlen) < 0) {
+ syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
+ if (res != NULL)
+ freeaddrinfo(res);
+ return 1;
+ }
+ (void) umask(oldmask);
+
+ /* Copy the address */
+ taddr.addr.len = taddr.addr.maxlen = addrlen;
+ taddr.addr.buf = malloc(addrlen);
+ if (taddr.addr.buf == NULL) {
+ syslog(LOG_ERR, "cannot allocate memory for %s address",
+ nconf->nc_netid);
+ if (res != NULL)
+ freeaddrinfo(res);
+ return 1;
+ }
+ memcpy(taddr.addr.buf, sa, addrlen);
+#ifdef ND_DEBUG
+ if (debugging) {
+ /* for debugging print out our universal address */
+ char *uaddr;
+ struct netbuf nb;
+
+ nb.buf = sa;
+ nb.len = nb.maxlen = sa->sa_len;
+ uaddr = taddr2uaddr(nconf, &nb);
+ (void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr);
+ (void) free(uaddr);
+ }
+#endif
+
+ if (res != NULL)
+ freeaddrinfo(res);
+
+ if (nconf->nc_semantics != NC_TPI_CLTS)
+ listen(fd, SOMAXCONN);
+
+ my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0);
+ if (my_xprt == (SVCXPRT *)NULL) {
+ syslog(LOG_ERR, "%s: could not create service",
+ nconf->nc_netid);
+ goto error;
+ }
+
+#ifdef PORTMAP
+ /*
+ * Register both the versions for tcp/ip, udp/ip and local.
+ */
+ if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
+ (strcmp(nconf->nc_proto, NC_TCP) == 0 ||
+ strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
+ strcmp(nconf->nc_netid, "unix") == 0) {
+ struct pmaplist *pml;
+
+ if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
+ pmap_service, NULL)) {
+ syslog(LOG_ERR, "could not register on %s",
+ nconf->nc_netid);
+ goto error;
+ }
+ pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist));
+ if (pml == (struct pmaplist *)NULL) {
+ syslog(LOG_ERR, "no memory!");
+ exit(1);
+ }
+ pml->pml_map.pm_prog = PMAPPROG;
+ pml->pml_map.pm_vers = PMAPVERS;
+ pml->pml_map.pm_port = PMAPPORT;
+ if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
+ if (tcptrans[0]) {
+ syslog(LOG_ERR,
+ "cannot have more than one TCP transport");
+ goto error;
+ }
+ tcptrans = strdup(nconf->nc_netid);
+ pml->pml_map.pm_prot = IPPROTO_TCP;
+
+ /* Let's snarf the universal address */
+ /* "h1.h2.h3.h4.p1.p2" */
+ tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
+ } else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
+ if (udptrans[0]) {
+ syslog(LOG_ERR,
+ "cannot have more than one UDP transport");
+ goto error;
+ }
+ udptrans = strdup(nconf->nc_netid);
+ pml->pml_map.pm_prot = IPPROTO_UDP;
+
+ /* Let's snarf the universal address */
+ /* "h1.h2.h3.h4.p1.p2" */
+ udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
+ } else if (strcmp(nconf->nc_netid, "unix") == 0)
+ pml->pml_map.pm_prot = IPPROTO_ST;
+ pml->pml_next = list_pml;
+ list_pml = pml;
+
+ /* Add version 3 information */
+ pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist));
+ if (pml == (struct pmaplist *)NULL) {
+ syslog(LOG_ERR, "no memory!");
+ exit(1);
+ }
+ pml->pml_map = list_pml->pml_map;
+ pml->pml_map.pm_vers = RPCBVERS;
+ pml->pml_next = list_pml;
+ list_pml = pml;
+
+ /* Add version 4 information */
+ pml = (struct pmaplist *)malloc((u_int)sizeof (struct pmaplist));
+ if (pml == (struct pmaplist *)NULL) {
+ syslog(LOG_ERR, "no memory!");
+ exit(1);
+ }
+ pml->pml_map = list_pml->pml_map;
+ pml->pml_map.pm_vers = RPCBVERS4;
+ pml->pml_next = list_pml;
+ list_pml = pml;
+
+ /* Also add version 2 stuff to rpcbind list */
+ rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
+ }
+#endif
+
+ /* version 3 registration */
+ if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
+ syslog(LOG_ERR, "could not register %s version 3",
+ nconf->nc_netid);
+ goto error;
+ }
+ rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);
+
+ /* version 4 registration */
+ if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
+ syslog(LOG_ERR, "could not register %s version 4",
+ nconf->nc_netid);
+ goto error;
+ }
+ rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);
+
+ /* decide if bound checking works for this transport */
+ status = add_bndlist(nconf, &taddr.addr);
+#ifdef BIND_DEBUG
+ if (debugging) {
+ if (status < 0) {
+ fprintf(stderr, "Error in finding bind status for %s\n",
+ nconf->nc_netid);
+ } else if (status == 0) {
+ fprintf(stderr, "check binding for %s\n",
+ nconf->nc_netid);
+ } else if (status > 0) {
+ fprintf(stderr, "No check binding for %s\n",
+ nconf->nc_netid);
+ }
+ }
+#endif
+ /*
+ * rmtcall only supported on CLTS transports for now.
+ */
+ if (nconf->nc_semantics == NC_TPI_CLTS) {
+ status = create_rmtcall_fd(nconf);
+
+#ifdef BIND_DEBUG
+ if (debugging) {
+ if (status < 0) {
+ fprintf(stderr,
+ "Could not create rmtcall fd for %s\n",
+ nconf->nc_netid);
+ } else {
+ fprintf(stderr, "rmtcall fd for %s is %d\n",
+ nconf->nc_netid, status);
+ }
+ }
+#endif
+ }
+ return (0);
+error:
+ close(fd);
+ return (1);
+}
+
+static void
+rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
+ struct netbuf *addr)
+{
+ rpcblist_ptr rbl;
+
+ rbl = (rpcblist_ptr)malloc((u_int)sizeof (rpcblist));
+ if (rbl == (rpcblist_ptr)NULL) {
+ syslog(LOG_ERR, "no memory!");
+ exit(1);
+ }
+
+ rbl->rpcb_map.r_prog = prog;
+ rbl->rpcb_map.r_vers = vers;
+ rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
+ rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
+ rbl->rpcb_map.r_owner = strdup(superuser);
+ rbl->rpcb_next = list_rbl; /* Attach to global list */
+ list_rbl = rbl;
+}
+
+/*
+ * Catch the signal and die
+ */
+static void
+terminate(int dummy)
+{
+#ifdef WARMSTART
+ syslog(LOG_ERR,
+ "rpcbind terminating on signal. Restart with \"rpcbind -w\"");
+ write_warmstart(); /* Dump yourself */
+#endif
+ exit(2);
+}
+
+void
+rpcbind_abort()
+{
+#ifdef WARMSTART
+ write_warmstart(); /* Dump yourself */
+#endif
+ abort();
+}
+
+/* get command line options */
+static void
+parseargs(int argc, char *argv[])
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "dwailLs")) != -1) {
+ switch (c) {
+ case 'a':
+ doabort = 1; /* when debugging, do an abort on */
+ break; /* errors; for rpcbind developers */
+ /* only! */
+ case 'd':
+ debugging = 1;
+ break;
+ case 'i':
+ insecure = 1;
+ break;
+ case 'L':
+ oldstyle_local = 1;
+ break;
+ case 'l':
+ verboselog = 1;
+ break;
+ case 's':
+ runasdaemon = 1;
+ break;
+#ifdef WARMSTART
+ case 'w':
+ warmstart = 1;
+ break;
+#endif
+ default: /* error */
+ fprintf(stderr, "usage: rpcbind [-Idwils]\n");
+ exit (1);
+ }
+ }
+ if (doabort && !debugging) {
+ fprintf(stderr,
+ "-a (abort) specified without -d (debugging) -- ignored.\n");
+ doabort = 0;
+ }
+}
+
+void
+reap(int dummy)
+{
+ int save_errno = errno;
+
+ while (wait3(NULL, WNOHANG, NULL) > 0)
+ ;
+ errno = save_errno;
+}
+
+void
+toggle_verboselog(int dummy)
+{
+ verboselog = !verboselog;
+}
diff --git a/usr.sbin/rpcbind/rpcbind.h b/usr.sbin/rpcbind/rpcbind.h
new file mode 100644
index 0000000..63cf2d4
--- /dev/null
+++ b/usr.sbin/rpcbind/rpcbind.h
@@ -0,0 +1,144 @@
+/* $NetBSD: rpcbind.h,v 1.1 2000/06/03 00:47:21 fvdl Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/* #ident "@(#)rpcbind.h 1.4 90/04/12 SMI" */
+
+/*
+ * rpcbind.h
+ * The common header declarations
+ */
+
+#ifndef rpcbind_h
+#define rpcbind_h
+
+#ifdef PORTMAP
+#include <rpc/pmap_prot.h>
+#endif
+#include <rpc/rpcb_prot.h>
+
+/*
+ * Stuff for the rmtcall service
+ */
+struct encap_parms {
+ u_int32_t arglen;
+ char *args;
+};
+
+struct r_rmtcall_args {
+ u_int32_t rmt_prog;
+ u_int32_t rmt_vers;
+ u_int32_t rmt_proc;
+ int rmt_localvers; /* whether to send port # or uaddr */
+ char *rmt_uaddr;
+ struct encap_parms rmt_args;
+};
+
+extern int debugging;
+extern int doabort;
+extern int verboselog;
+extern int insecure;
+extern int oldstyle_local;
+extern rpcblist_ptr list_rbl; /* A list of version 3 & 4 rpcbind services */
+
+#ifdef PORTMAP
+extern struct pmaplist *list_pml; /* A list of version 2 rpcbind services */
+extern char *udptrans; /* Name of UDP transport */
+extern char *tcptrans; /* Name of TCP transport */
+extern char *udp_uaddr; /* Universal UDP address */
+extern char *tcp_uaddr; /* Universal TCP address */
+#endif
+
+int add_bndlist __P((struct netconfig *, struct netbuf *));
+bool_t is_bound __P((char *, char *));
+char *mergeaddr __P((SVCXPRT *, char *, char *, char *));
+struct netconfig *rpcbind_get_conf __P((char *));
+
+void rpcbs_init __P((void));
+void rpcbs_procinfo __P((rpcvers_t, rpcproc_t));
+void rpcbs_set __P((rpcvers_t, bool_t));
+void rpcbs_unset __P((rpcvers_t, bool_t));
+void rpcbs_getaddr __P((rpcvers_t, rpcprog_t, rpcvers_t, char *, char *));
+void rpcbs_rmtcall __P((rpcvers_t, rpcproc_t, rpcprog_t, rpcvers_t, rpcproc_t,
+ char *, rpcblist_ptr));
+void *rpcbproc_getstat __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+
+void rpcb_service_3 __P((struct svc_req *, SVCXPRT *));
+void rpcb_service_4 __P((struct svc_req *, SVCXPRT *));
+
+/* Common functions shared between versions */
+void *rpcbproc_set_com __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+void *rpcbproc_unset_com __P((void *, struct svc_req *, SVCXPRT *, rpcvers_t));
+bool_t map_set __P((RPCB *, char *));
+bool_t map_unset __P((RPCB *, char *));
+void delete_prog __P((int));
+void *rpcbproc_getaddr_com __P((RPCB *, struct svc_req *, SVCXPRT *, rpcvers_t,
+ rpcvers_t));
+void *rpcbproc_gettime_com __P((void *, struct svc_req *, SVCXPRT *,
+ rpcvers_t));
+void *rpcbproc_uaddr2taddr_com __P((void *, struct svc_req *,
+ SVCXPRT *, rpcvers_t));
+void *rpcbproc_taddr2uaddr_com __P((void *, struct svc_req *, SVCXPRT *,
+ rpcvers_t));
+int create_rmtcall_fd __P((struct netconfig *));
+void rpcbproc_callit_com __P((struct svc_req *, SVCXPRT *, rpcvers_t,
+ rpcvers_t));
+void my_svc_run __P((void));
+
+void rpcbind_abort __P((void));
+void reap __P((int));
+void toggle_verboselog __P((int));
+
+int check_access __P((SVCXPRT *, rpcproc_t, void *, int));
+int check_callit __P((SVCXPRT *, struct r_rmtcall_args *, int));
+void logit __P((int, struct sockaddr *, rpcproc_t, rpcprog_t, const char *));
+int is_loopback __P((struct netbuf *));
+
+#ifdef PORTMAP
+extern void pmap_service __P((struct svc_req *, SVCXPRT *));
+#endif
+
+void write_warmstart __P((void));
+void read_warmstart __P((void));
+
+char *addrmerge __P((struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
+ char *netid));
+void network_init __P((void));
+struct sockaddr *local_sa __P((int));
+
+/* For different getaddr semantics */
+#define RPCB_ALLVERS 0
+#define RPCB_ONEVERS 1
+
+#endif /* rpcbind_h */
diff --git a/usr.sbin/rpcbind/security.c b/usr.sbin/rpcbind/security.c
new file mode 100644
index 0000000..8d784d6
--- /dev/null
+++ b/usr.sbin/rpcbind/security.c
@@ -0,0 +1,283 @@
+/* $NetBSD: security.c,v 1.5 2000/06/08 09:01:05 fvdl Exp $ */
+/* $FreeBSD$ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcb_prot.h>
+#include <rpc/pmap_prot.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libutil.h>
+#include <syslog.h>
+#include <netdb.h>
+
+/*
+ * XXX for special case checks in check_callit.
+ */
+#include <rpcsvc/mount.h>
+#include <rpcsvc/rquota.h>
+#include <rpcsvc/nfs_prot.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+
+#include "rpcbind.h"
+
+#ifdef LIBWRAP
+# include <tcpd.h>
+#ifndef LIBWRAP_ALLOW_FACILITY
+# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
+#endif
+#ifndef LIBWRAP_ALLOW_SEVERITY
+# define LIBWRAP_ALLOW_SEVERITY LOG_INFO
+#endif
+#ifndef LIBWRAP_DENY_FACILITY
+# define LIBWRAP_DENY_FACILITY LOG_AUTH
+#endif
+#ifndef LIBWRAP_DENY_SEVERITY
+# define LIBWRAP_DENY_SEVERITY LOG_WARNING
+#endif
+int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
+int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
+#endif
+
+#ifndef PORTMAP_LOG_FACILITY
+# define PORTMAP_LOG_FACILITY LOG_AUTH
+#endif
+#ifndef PORTMAP_LOG_SEVERITY
+# define PORTMAP_LOG_SEVERITY LOG_INFO
+#endif
+int log_severity = PORTMAP_LOG_FACILITY|PORTMAP_LOG_SEVERITY;
+
+extern int verboselog;
+
+int
+check_access(SVCXPRT *xprt, rpcproc_t proc, void *args, int rpcbvers)
+{
+ struct netbuf *caller = svc_getrpccaller(xprt);
+ struct sockaddr *addr = (struct sockaddr *)caller->buf;
+#ifdef LIBWRAP
+ struct request_info req;
+#endif
+ rpcprog_t prog = 0;
+ rpcb *rpcbp;
+ struct pmap *pmap;
+
+ /*
+ * The older PMAP_* equivalents have the same numbers, so
+ * they are accounted for here as well.
+ */
+ switch (proc) {
+ case RPCBPROC_GETADDR:
+ case RPCBPROC_SET:
+ case RPCBPROC_UNSET:
+ if (rpcbvers > PMAPVERS) {
+ rpcbp = (rpcb *)args;
+ prog = rpcbp->r_prog;
+ } else {
+ pmap = (struct pmap *)args;
+ prog = pmap->pm_prog;
+ }
+ if (proc == RPCBPROC_GETADDR)
+ break;
+ if (!insecure && !is_loopback(caller)) {
+ if (verboselog)
+ logit(log_severity, addr, proc, prog,
+ " declined (non-loopback sender)");
+ return 0;
+ }
+ break;
+ case RPCBPROC_CALLIT:
+ case RPCBPROC_INDIRECT:
+ case RPCBPROC_DUMP:
+ case RPCBPROC_GETTIME:
+ case RPCBPROC_UADDR2TADDR:
+ case RPCBPROC_TADDR2UADDR:
+ case RPCBPROC_GETVERSADDR:
+ case RPCBPROC_GETADDRLIST:
+ case RPCBPROC_GETSTAT:
+ default:
+ }
+
+#ifdef LIBWRAP
+ if (addr->sa_family == AF_LOCAL)
+ return 1;
+ request_init(&req, RQ_DAEMON, "rpcbind", RQ_CLIENT_SIN, addr, 0);
+ sock_methods(&req);
+ if(!hosts_access(&req)) {
+ logit(deny_severity, addr, proc, prog, ": request from unauthorized host");
+ return 0;
+ }
+#endif
+ if (verboselog)
+ logit(log_severity, addr, proc, prog, "");
+ return 1;
+}
+
+int
+is_loopback(struct netbuf *nbuf)
+{
+ struct sockaddr *addr = (struct sockaddr *)nbuf->buf;
+ struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ if (!oldstyle_local)
+ return 0;
+ sin = (struct sockaddr_in *)addr;
+ return ((sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
+ (ntohs(sin->sin_port) < IPPORT_RESERVED));
+#ifdef INET6
+ case AF_INET6:
+ if (!oldstyle_local)
+ return 0;
+ sin6 = (struct sockaddr_in6 *)addr;
+ return (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) &&
+ (ntohs(sin6->sin6_port) < IPV6PORT_RESERVED));
+#endif
+ case AF_LOCAL:
+ return 1;
+ default:
+ }
+
+ return 0;
+}
+
+
+/* logit - report events of interest via the syslog daemon */
+void
+logit(int severity, struct sockaddr *addr, rpcproc_t procnum, rpcprog_t prognum,
+ const char *text)
+{
+ const char *procname;
+ char procbuf[32];
+ char *progname;
+ char progbuf[32];
+ char fromname[NI_MAXHOST];
+ struct rpcent *rpc;
+ static const char *procmap[] = {
+ /* RPCBPROC_NULL */ "null",
+ /* RPCBPROC_SET */ "set",
+ /* RPCBPROC_UNSET */ "unset",
+ /* RPCBPROC_GETADDR */ "getport/addr",
+ /* RPCBPROC_DUMP */ "dump",
+ /* RPCBPROC_CALLIT */ "callit",
+ /* RPCBPROC_GETTIME */ "gettime",
+ /* RPCBPROC_UADDR2TADDR */ "uaddr2taddr",
+ /* RPCBPROC_TADDR2UADDR */ "taddr2uaddr",
+ /* RPCBPROC_GETVERSADDR */ "getversaddr",
+ /* RPCBPROC_INDIRECT */ "indirect",
+ /* RPCBPROC_GETADDRLIST */ "getaddrlist",
+ /* RPCBPROC_GETSTAT */ "getstat"
+ };
+
+ /*
+ * Fork off a process or the portmap daemon might hang while
+ * getrpcbynumber() or syslog() does its thing.
+ */
+
+ if (fork() == 0) {
+ setproctitle("logit");
+
+ /* Try to map program number to name. */
+
+ if (prognum == 0) {
+ progname = "";
+ } else if ((rpc = getrpcbynumber((int) prognum))) {
+ progname = rpc->r_name;
+ } else {
+ snprintf(progname = progbuf, sizeof(progbuf), "%u",
+ (unsigned)prognum);
+ }
+
+ /* Try to map procedure number to name. */
+
+ if (procnum > (sizeof procmap / sizeof (char *))) {
+ snprintf(procbuf, sizeof procbuf, "%u",
+ (unsigned)procnum);
+ procname = procbuf;
+ } else
+ procname = procmap[procnum];
+
+ /* Write syslog record. */
+
+ if (addr->sa_family == AF_LOCAL)
+ strcpy(fromname, "unix");
+ else
+ getnameinfo(addr, addr->sa_len, fromname,
+ sizeof fromname, NULL, 0, NI_NUMERICHOST);
+
+ syslog(severity, "connect from %s to %s(%s)%s",
+ fromname, procname, progname, text);
+ _exit(0);
+ }
+}
+
+int
+check_callit(SVCXPRT *xprt, struct r_rmtcall_args *args, int versnum)
+{
+ struct sockaddr *sa = (struct sockaddr *)svc_getrpccaller(xprt)->buf;
+
+ /*
+ * Always allow calling NULLPROC
+ */
+ if (args->rmt_proc == 0)
+ return 1;
+
+ /*
+ * XXX - this special casing sucks.
+ */
+ switch (args->rmt_prog) {
+ case RPCBPROG:
+ /*
+ * Allow indirect calls to ourselves in insecure mode.
+ * The is_loopback checks aren't useful then anyway.
+ */
+ if (!insecure)
+ goto deny;
+ break;
+ case MOUNTPROG:
+ if (args->rmt_proc != MOUNTPROC_MNT &&
+ args->rmt_proc != MOUNTPROC_UMNT)
+ break;
+ goto deny;
+ case YPBINDPROG:
+ if (args->rmt_proc != YPBINDPROC_SETDOM)
+ break;
+ /* FALLTHROUGH */
+ case YPPASSWDPROG:
+ case NFS_PROGRAM:
+ case RQUOTAPROG:
+ goto deny;
+ case YPPROG:
+ switch (args->rmt_proc) {
+ case YPPROC_ALL:
+ case YPPROC_MATCH:
+ case YPPROC_FIRST:
+ case YPPROC_NEXT:
+ goto deny;
+ default:
+ }
+ default:
+ }
+
+ return 1;
+deny:
+#ifdef LIBWRAP
+ logit(deny_severity, sa, args->rmt_proc, args->rmt_prog,
+ ": indirect call not allowed");
+#else
+ logit(0, sa, args->rmt_proc, args->rmt_prog,
+ ": indirect call not allowed");
+#endif
+ return 0;
+}
diff --git a/usr.sbin/rpcbind/util.c b/usr.sbin/rpcbind/util.c
new file mode 100644
index 0000000..bf20019
--- /dev/null
+++ b/usr.sbin/rpcbind/util.c
@@ -0,0 +1,381 @@
+/*
+ * $NetBSD: util.c,v 1.4 2000/08/03 00:04:30 fvdl Exp $
+ * $FreeBSD$
+ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Frank van der Linden.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+#include <sys/poll.h>
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netconfig.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+
+#include "rpcbind.h"
+
+static struct sockaddr_in *local_in4;
+#ifdef INET6
+static struct sockaddr_in6 *local_in6;
+#endif
+
+static int bitmaskcmp __P((void *, void *, void *, int));
+#ifdef INET6
+static void in6_fillscopeid __P((struct sockaddr_in6 *));
+#endif
+
+/*
+ * For all bits set in "mask", compare the corresponding bits in
+ * "dst" and "src", and see if they match.
+ */
+static int
+bitmaskcmp(void *dst, void *src, void *mask, int bytelen)
+{
+ int i, j;
+ u_int8_t *p1 = dst, *p2 = src, *netmask = mask;
+ u_int8_t bitmask;
+
+ for (i = 0; i < bytelen; i++) {
+ for (j = 0; j < 8; j++) {
+ bitmask = 1 << j;
+ if (!(netmask[i] & bitmask))
+ continue;
+ if ((p1[i] & bitmask) != (p2[i] & bitmask))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Taken from ifconfig.c
+ */
+#ifdef INET6
+static void
+in6_fillscopeid(struct sockaddr_in6 *sin6)
+{
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ sin6->sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
+ sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
+ }
+}
+#endif
+
+char *
+addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
+ char *netid)
+{
+ struct ifaddrs *ifap, *ifp, *bestif;
+#ifdef INET6
+ struct sockaddr_in6 *servsin6, *sin6mask, *clntsin6, *ifsin6, *realsin6;
+ struct sockaddr_in6 *newsin6;
+#endif
+ struct sockaddr_in *servsin, *sinmask, *clntsin, *newsin, *ifsin;
+ struct netbuf *serv_nbp, *clnt_nbp = NULL, tbuf;
+ struct sockaddr *serv_sa;
+ struct sockaddr *clnt_sa;
+ struct sockaddr_storage ss;
+ struct netconfig *nconf;
+ struct sockaddr *clnt = caller->buf;
+ char *ret = NULL;
+
+#ifdef ND_DEBUG
+ if (debugging)
+ fprintf(stderr, "addrmerge(caller, %s, %s, %s\n", serv_uaddr,
+ clnt_uaddr, netid);
+#endif
+ nconf = getnetconfigent(netid);
+ if (nconf == NULL)
+ return NULL;
+
+ /*
+ * Local merge, just return a duplicate.
+ */
+ if (clnt_uaddr != NULL && strncmp(clnt_uaddr, "0.0.0.0.", 8) == 0)
+ return strdup(clnt_uaddr);
+
+ serv_nbp = uaddr2taddr(nconf, serv_uaddr);
+ if (serv_nbp == NULL)
+ return NULL;
+
+ serv_sa = (struct sockaddr *)serv_nbp->buf;
+ if (clnt_uaddr != NULL) {
+ clnt_nbp = uaddr2taddr(nconf, clnt_uaddr);
+ clnt_sa = (struct sockaddr *)clnt_nbp->buf;
+ } else {
+ clnt_sa = (struct sockaddr *)
+ malloc(sizeof (struct sockaddr_storage));
+ memcpy(clnt_sa, clnt, clnt->sa_len);
+ }
+
+ if (getifaddrs(&ifp) < 0)
+ return 0;
+
+ /*
+ * Loop through all interfaces. For each interface, see if the
+ * network portion of its address is equal to that of the client.
+ * If so, we have found the interface that we want to use.
+ */
+ for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
+ if (ifap->ifa_addr->sa_family != clnt->sa_family ||
+ !(ifap->ifa_flags & IFF_UP))
+ continue;
+
+ switch (clnt->sa_family) {
+ case AF_INET:
+ /*
+ * realsin: address that recvfrom gave us.
+ * ifsin: address of interface being examined.
+ * clntsin: address that client want us to contact
+ * it on
+ * servsin: local address of RPC service.
+ * sinmask: netmask of this interface
+ * newsin: initially a copy of clntsin, eventually
+ * the merged address
+ */
+ servsin = (struct sockaddr_in *)serv_sa;
+ clntsin = (struct sockaddr_in *)clnt_sa;
+ sinmask = (struct sockaddr_in *)ifap->ifa_netmask;
+ newsin = (struct sockaddr_in *)&ss;
+ ifsin = (struct sockaddr_in *)ifap->ifa_addr;
+ if (!bitmaskcmp(&ifsin->sin_addr, &clntsin->sin_addr,
+ &sinmask->sin_addr, sizeof (struct in_addr))) {
+ /*
+ * Found it.
+ */
+ memcpy(newsin, ifap->ifa_addr,
+ clnt_sa->sa_len);
+ newsin->sin_port = servsin->sin_port;
+ tbuf.len = clnt_sa->sa_len;
+ tbuf.maxlen = sizeof (struct sockaddr_storage);
+ tbuf.buf = newsin;
+ goto found;
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ /*
+ * realsin6: address that recvfrom gave us.
+ * ifsin6: address of interface being examined.
+ * clntsin6: address that client want us to contact
+ * it on
+ * servsin6: local address of RPC service.
+ * sin6mask: netmask of this interface
+ * newsin6: initially a copy of clntsin, eventually
+ * the merged address
+ *
+ * For v6 link local addresses, if the client contacted
+ * us via a link-local address, and wants us to reply
+ * to one, use the scope id to see which one.
+ */
+ realsin6 = (struct sockaddr_in6 *)clnt;
+ ifsin6 = (struct sockaddr_in6 *)ifap->ifa_addr;
+ in6_fillscopeid(ifsin6);
+ clntsin6 = (struct sockaddr_in6 *)clnt_sa;
+ servsin6 = (struct sockaddr_in6 *)serv_sa;
+ sin6mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
+ newsin6 = (struct sockaddr_in6 *)&ss;
+ if (IN6_IS_ADDR_LINKLOCAL(&ifsin6->sin6_addr) &&
+ IN6_IS_ADDR_LINKLOCAL(&realsin6->sin6_addr) &&
+ IN6_IS_ADDR_LINKLOCAL(&clntsin6->sin6_addr)) {
+ if (ifsin6->sin6_scope_id !=
+ realsin6->sin6_scope_id)
+ continue;
+match:
+ memcpy(newsin6, ifsin6, clnt_sa->sa_len);
+ newsin6->sin6_port = servsin6->sin6_port;
+ tbuf.maxlen = sizeof (struct sockaddr_storage);
+ tbuf.len = clnt_sa->sa_len;
+ tbuf.buf = newsin6;
+ goto found;
+ }
+ if (!bitmaskcmp(&ifsin6->sin6_addr,
+ &clntsin6->sin6_addr, &sin6mask->sin6_addr,
+ sizeof (struct in6_addr)))
+ goto match;
+ break;
+#endif
+ default:
+ goto freeit;
+ }
+ }
+ /*
+ * Didn't find anything. Get the first possibly useful interface,
+ * preferring "normal" interfaces to point-to-point and loopback
+ * ones.
+ */
+ bestif = NULL;
+ for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
+ if (ifap->ifa_addr->sa_family != clnt->sa_family ||
+ !(ifap->ifa_flags & IFF_UP))
+ continue;
+ if (!(ifap->ifa_flags & IFF_LOOPBACK) &&
+ !(ifap->ifa_flags & IFF_POINTOPOINT)) {
+ bestif = ifap;
+ break;
+ }
+ if (bestif == NULL)
+ bestif = ifap;
+ else if ((bestif->ifa_flags & IFF_LOOPBACK) &&
+ !(ifap->ifa_flags & IFF_LOOPBACK))
+ bestif = ifap;
+ }
+ ifap = bestif;
+found:
+ if (ifap != NULL)
+ ret = taddr2uaddr(nconf, &tbuf);
+freeit:
+ freenetconfigent(nconf);
+ free(serv_sa);
+ free(serv_nbp);
+ if (clnt_sa != NULL)
+ free(clnt_sa);
+ if (clnt_nbp != NULL)
+ free(clnt_nbp);
+ freeifaddrs(ifp);
+
+#ifdef ND_DEBUG
+ if (debugging)
+ fprintf(stderr, "addrmerge: returning %s\n", ret);
+#endif
+ return ret;
+}
+
+void
+network_init()
+{
+#ifdef INET6
+ struct ifaddrs *ifap, *ifp;
+ struct ipv6_mreq mreq6;
+ int ifindex, s;
+#endif
+ int ecode;
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_INET;
+ if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) {
+ if (debugging)
+ fprintf(stderr, "can't get local ip4 address: %s\n",
+ gai_strerror(ecode));
+ } else {
+ local_in4 = (struct sockaddr_in *)malloc(sizeof *local_in4);
+ if (local_in4 == NULL) {
+ if (debugging)
+ fprintf(stderr, "can't alloc local ip4 addr\n");
+ }
+ memcpy(local_in4, res->ai_addr, sizeof *local_in4);
+ }
+
+#ifdef INET6
+ hints.ai_family = AF_INET6;
+ if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) {
+ if (debugging)
+ fprintf(stderr, "can't get local ip6 address: %s\n",
+ gai_strerror(ecode));
+ } else {
+ local_in6 = (struct sockaddr_in6 *)malloc(sizeof *local_in6);
+ if (local_in6 == NULL) {
+ if (debugging)
+ fprintf(stderr, "can't alloc local ip6 addr\n");
+ }
+ memcpy(local_in6, res->ai_addr, sizeof *local_in6);
+ }
+
+ /*
+ * Now join the RPC ipv6 multicast group on all interfaces.
+ */
+ if (getifaddrs(&ifp) < 0)
+ return;
+
+ mreq6.ipv6mr_interface = 0;
+ inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, &mreq6.ipv6mr_multiaddr);
+
+ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+
+ /*
+ * Loop through all interfaces. For each interface, see if the
+ * network portion of its address is equal to that of the client.
+ * If so, we have found the interface that we want to use.
+ */
+ for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
+ if (ifap->ifa_addr->sa_family != AF_INET6 ||
+ !(ifap->ifa_flags & IFF_MULTICAST))
+ continue;
+ ifindex = if_nametoindex(ifap->ifa_name);
+ if (ifindex == mreq6.ipv6mr_interface)
+ /*
+ * Already did this one.
+ */
+ continue;
+ mreq6.ipv6mr_interface = ifindex;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
+ sizeof mreq6) < 0)
+ if (debugging)
+ perror("setsockopt v6 multicast");
+ }
+#endif
+
+ /* close(s); */
+}
+
+struct sockaddr *
+local_sa(int af)
+{
+ switch (af) {
+ case AF_INET:
+ return (struct sockaddr *)local_in4;
+#ifdef INET6
+ case AF_INET6:
+ return (struct sockaddr *)local_in6;
+#endif
+ default:
+ return NULL;
+ }
+}
diff --git a/usr.sbin/rpcbind/warmstart.c b/usr.sbin/rpcbind/warmstart.c
new file mode 100644
index 0000000..fea2789
--- /dev/null
+++ b/usr.sbin/rpcbind/warmstart.c
@@ -0,0 +1,179 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * warmstart.c
+ * Allows for gathering of registrations from a earlier dumped file.
+ *
+ * Copyright (c) 1990 by Sun Microsystems, Inc.
+ */
+
+/*
+ * #ident "@(#)warmstart.c 1.7 93/07/05 SMI"
+ * $FreeBSD$/
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/rpcb_prot.h>
+#include <rpc/xdr.h>
+#ifdef PORTMAP
+#include <netinet/in.h>
+#include <rpc/pmap_prot.h>
+#endif
+#include <syslog.h>
+#include <unistd.h>
+
+#include "rpcbind.h"
+
+/*
+ * XXX this code is unsafe and is not used. It should be made safe.
+ */
+
+
+/* These files keep the pmap_list and rpcb_list in XDR format */
+#define RPCBFILE "/tmp/rpcbind.file"
+#ifdef PORTMAP
+#define PMAPFILE "/tmp/portmap.file"
+#endif
+
+static bool_t write_struct __P((char *, xdrproc_t, void *));
+static bool_t read_struct __P((char *, xdrproc_t, void *));
+
+static bool_t
+write_struct(char *filename, xdrproc_t structproc, void *list)
+{
+ FILE *fp;
+ XDR xdrs;
+ mode_t omask;
+
+ omask = umask(077);
+ fp = fopen(filename, "w");
+ if (fp == NULL) {
+ int i;
+
+ for (i = 0; i < 10; i++)
+ close(i);
+ fp = fopen(filename, "w");
+ if (fp == NULL) {
+ syslog(LOG_ERR,
+ "cannot open file = %s for writing", filename);
+ syslog(LOG_ERR, "cannot save any registration");
+ return (FALSE);
+ }
+ }
+ (void) umask(omask);
+ xdrstdio_create(&xdrs, fp, XDR_ENCODE);
+
+ if (structproc(&xdrs, list) == FALSE) {
+ syslog(LOG_ERR, "rpcbind: xdr_%s: failed", filename);
+ fclose(fp);
+ return (FALSE);
+ }
+ XDR_DESTROY(&xdrs);
+ fclose(fp);
+ return (TRUE);
+}
+
+static bool_t
+read_struct(char *filename, xdrproc_t structproc, void *list)
+{
+ FILE *fp;
+ XDR xdrs;
+ struct stat sbuf;
+
+ if (stat(filename, &sbuf) != 0) {
+ fprintf(stderr,
+ "rpcbind: cannot stat file = %s for reading\n", filename);
+ goto error;
+ }
+ if ((sbuf.st_uid != 0) || (sbuf.st_mode & S_IRWXG) ||
+ (sbuf.st_mode & S_IRWXO)) {
+ fprintf(stderr,
+ "rpcbind: invalid permissions on file = %s for reading\n",
+ filename);
+ goto error;
+ }
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ fprintf(stderr,
+ "rpcbind: cannot open file = %s for reading\n", filename);
+ goto error;
+ }
+ xdrstdio_create(&xdrs, fp, XDR_DECODE);
+
+ if (structproc(&xdrs, list) == FALSE) {
+ fprintf(stderr, "rpcbind: xdr_%s: failed\n", filename);
+ fclose(fp);
+ goto error;
+ }
+ XDR_DESTROY(&xdrs);
+ fclose(fp);
+ return (TRUE);
+
+error: fprintf(stderr, "rpcbind: will start from scratch\n");
+ return (FALSE);
+}
+
+void
+write_warmstart()
+{
+ (void) write_struct(RPCBFILE, xdr_rpcblist_ptr, &list_rbl);
+#ifdef PORTMAP
+ (void) write_struct(PMAPFILE, xdr_pmaplist_ptr, &list_pml);
+#endif
+
+}
+
+void
+read_warmstart()
+{
+ rpcblist_ptr tmp_rpcbl = NULL;
+#ifdef PORTMAP
+ struct pmaplist *tmp_pmapl = NULL;
+#endif
+ int ok1, ok2 = TRUE;
+
+ ok1 = read_struct(RPCBFILE, xdr_rpcblist_ptr, &tmp_rpcbl);
+ if (ok1 == FALSE)
+ return;
+#ifdef PORTMAP
+ ok2 = read_struct(PMAPFILE, xdr_pmaplist_ptr, &tmp_pmapl);
+#endif
+ if (ok2 == FALSE) {
+ xdr_free((xdrproc_t) xdr_rpcblist_ptr, (char *)&tmp_rpcbl);
+ return;
+ }
+ xdr_free((xdrproc_t) xdr_rpcblist_ptr, (char *)&list_rbl);
+ list_rbl = tmp_rpcbl;
+#ifdef PORTMAP
+ xdr_free((xdrproc_t) xdr_pmaplist_ptr, (char *)&list_pml);
+ list_pml = tmp_pmapl;
+#endif
+}
OpenPOWER on IntegriCloud