summaryrefslogtreecommitdiffstats
path: root/usr.sbin
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
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')
-rw-r--r--usr.sbin/Makefile2
-rw-r--r--usr.sbin/bootparamd/callbootd/callbootd.c10
-rw-r--r--usr.sbin/keyserv/keyserv.c49
-rw-r--r--usr.sbin/mountd/mountd.c876
-rw-r--r--usr.sbin/nfsd/nfsd.824
-rw-r--r--usr.sbin/nfsd/nfsd.c823
-rw-r--r--usr.sbin/portmap/Makefile13
-rw-r--r--usr.sbin/portmap/from_local.c233
-rw-r--r--usr.sbin/portmap/pmap_check.c263
-rw-r--r--usr.sbin/portmap/pmap_check.h41
-rw-r--r--usr.sbin/portmap/pmap_dump/Makefile7
-rw-r--r--usr.sbin/portmap/pmap_dump/pmap_dump.c69
-rw-r--r--usr.sbin/portmap/pmap_set/Makefile7
-rw-r--r--usr.sbin/portmap/pmap_set/pmap_set.c78
-rw-r--r--usr.sbin/portmap/portmap.8122
-rw-r--r--usr.sbin/portmap/portmap.c612
-rw-r--r--usr.sbin/rpc.lockd/Makefile22
-rw-r--r--usr.sbin/rpc.lockd/lock_proc.c1294
-rw-r--r--usr.sbin/rpc.lockd/lockd.c231
-rw-r--r--usr.sbin/rpc.lockd/lockd.h17
-rw-r--r--usr.sbin/rpc.lockd/lockd_lock.c759
-rw-r--r--usr.sbin/rpc.lockd/lockd_lock.h21
-rw-r--r--usr.sbin/rpc.lockd/rpc.lockd.887
-rw-r--r--usr.sbin/rpc.lockd/test.c119
-rw-r--r--usr.sbin/rpc.statd/statd.h15
-rw-r--r--usr.sbin/rpc.umntall/rpc.umntall.c68
-rw-r--r--usr.sbin/rpc.yppasswdd/yppasswdd_main.c13
-rw-r--r--usr.sbin/rpc.ypupdated/ypupdated_extern.h1
-rw-r--r--usr.sbin/rpc.ypupdated/ypupdated_server.c1
-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
-rw-r--r--usr.sbin/ypbind/yp_ping.c4
-rw-r--r--usr.sbin/ypbind/ypbind.c2
-rw-r--r--usr.sbin/yppush/yppush_main.c6
-rw-r--r--usr.sbin/ypserv/yp_dnslookup.c4
46 files changed, 8282 insertions, 2248 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index c51b87a..7a41e40 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -66,7 +66,6 @@ SUBDIR= IPXrouted \
pim6sd \
pkg_install \
pnpinfo \
- portmap \
ppp \
pppctl \
pppd \
@@ -84,6 +83,7 @@ SUBDIR= IPXrouted \
rip6query \
rmt \
route6d \
+ rpcbind \
rpc.lockd \
rpc.statd \
rpc.umntall \
diff --git a/usr.sbin/bootparamd/callbootd/callbootd.c b/usr.sbin/bootparamd/callbootd/callbootd.c
index 7a09168..b7827ac 100644
--- a/usr.sbin/bootparamd/callbootd/callbootd.c
+++ b/usr.sbin/bootparamd/callbootd/callbootd.c
@@ -118,8 +118,9 @@ char **argv;
} else {
clnt_stat=clnt_broadcast(BOOTPARAMPROG, BOOTPARAMVERS,
BOOTPARAMPROC_WHOAMI,
- xdr_bp_whoami_arg, &whoami_arg,
- xdr_bp_whoami_res, &stat_whoami_res, eachres_whoami);
+ (xdrproc_t)xdr_bp_whoami_arg, (char *)&whoami_arg,
+ xdr_bp_whoami_res, (char *)&stat_whoami_res,
+ (resultproc_t)eachres_whoami);
exit(0);
}
@@ -138,8 +139,9 @@ char **argv;
} else {
clnt_stat=clnt_broadcast(BOOTPARAMPROG, BOOTPARAMVERS,
BOOTPARAMPROC_GETFILE,
- xdr_bp_getfile_arg, &getfile_arg,
- xdr_bp_getfile_res, &stat_getfile_res,eachres_getfile);
+ xdr_bp_getfile_arg, (char *)&getfile_arg,
+ xdr_bp_getfile_res, (char *)&stat_getfile_res,
+ (resultproc_t)eachres_getfile);
exit(0);
}
diff --git a/usr.sbin/keyserv/keyserv.c b/usr.sbin/keyserv/keyserv.c
index 72a334a..9a156d5 100644
--- a/usr.sbin/keyserv/keyserv.c
+++ b/usr.sbin/keyserv/keyserv.c
@@ -56,7 +56,6 @@ static const char rcsid[] =
#include <sys/stat.h>
#include <sys/types.h>
#include <rpc/rpc.h>
-#include <rpc/pmap_clnt.h>
#include <sys/param.h>
#include <sys/file.h>
#include <rpc/des_crypt.h>
@@ -162,46 +161,24 @@ main(argc, argv)
setmodulus(HEXMODULUS);
getrootkey(&masterkey, nflag);
-
- /* Create services. */
-
- (void) pmap_unset(KEY_PROG, KEY_VERS);
- (void) pmap_unset(KEY_PROG, KEY_VERS2);
- unlink(KEYSERVSOCK);
-
- transp = svcudp_create(RPC_ANYSOCK);
- if (transp == NULL)
- errx(1, "cannot create udp service");
- if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, IPPROTO_UDP))
- errx(1, "unable to register (KEY_PROG, KEY_VERS, udp)");
- if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, IPPROTO_UDP))
- errx(1, "unable to register (KEY_PROG, KEY_VERS2, udp)");
-
- transp = svctcp_create(RPC_ANYSOCK, 0, 0);
- if (transp == NULL)
- errx(1, "cannot create tcp service");
- if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, IPPROTO_TCP))
- errx(1, "unable to register (KEY_PROG, KEY_VERS, tcp)");
- if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, IPPROTO_TCP))
- errx(1, "unable to register (KEY_PROG, KEY_VERS2, tcp)");
-
- transp = svcunix_create(sock, 0, 0, KEYSERVSOCK);
- chmod(KEYSERVSOCK, 0666);
- if (transp == NULL)
- errx(1, "cannot create AF_UNIX service");
- if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, 0))
- errx(1, "unable to register (KEY_PROG, KEY_VERS, unix)");
- if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, 0))
- errx(1, "unable to register (KEY_PROG, KEY_VERS2, unix)");
- if (!svc_register(transp, CRYPT_PROG, CRYPT_VERS, crypt_prog_1, 0))
- errx(1, "unable to register (CRYPT_PROG, CRYPT_VERS, unix)");
+ if (svc_create(keyprogram, KEY_PROG, KEY_VERS,
+ "netpath") == 0) {
+ (void) fprintf(stderr,
+ "%s: unable to create service\n", argv[0]);
+ exit(1);
+ }
+
+ if (svc_create(keyprogram, KEY_PROG, KEY_VERS2,
+ "netpath") == 0) {
+ (void) fprintf(stderr,
+ "%s: unable to create service\n", argv[0]);
+ exit(1);
+ }
if (!debugging) {
daemon(0,0);
}
- signal(SIGPIPE, SIG_IGN);
-
svc_run();
abort();
/* NOTREACHED */
diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
index 2f46a9f..b527765 100644
--- a/usr.sbin/mountd/mountd.c
+++ b/usr.sbin/mountd/mountd.c
@@ -50,12 +50,15 @@ static const char rcsid[] =
#include <sys/param.h>
#include <sys/mount.h>
+#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <sys/sysctl.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include <rpcsvc/mount.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
@@ -83,6 +86,10 @@ static const char rcsid[] =
#include <stdarg.h>
#endif
+#ifndef MOUNTDLOCK
+#define MOUNTDLOCK "/var/run/mountd.lock"
+#endif
+
/*
* Structures for keeping the mount list and export list
*/
@@ -117,13 +124,13 @@ struct exportlist {
#define EX_LINKED 0x1
struct netmsk {
- u_int32_t nt_net;
+ struct sockaddr_storage nt_net;
u_int32_t nt_mask;
char *nt_name;
};
union grouptypes {
- struct hostent *gt_hostent;
+ struct addrinfo *gt_addrinfo;
struct netmsk gt_net;
};
@@ -157,8 +164,8 @@ void add_dlist __P((struct dirlist **, struct dirlist *,
void add_mlist __P((char *, char *));
int check_dirpath __P((char *));
int check_options __P((struct dirlist *));
-int chk_host __P((struct dirlist *, u_int32_t, int *, int *));
-void del_mlist __P((char *, char *));
+int chk_host __P((struct dirlist *, struct sockaddr *, int *, int *));
+int del_mlist __P((char *, char *, struct sockaddr *));
struct dirlist *dirp_search __P((struct dirlist *, char *));
int do_mount __P((struct exportlist *, struct grouplist *, int,
struct xucred *, char *, int, struct statfs *));
@@ -186,18 +193,25 @@ void nextfield __P((char **, char **));
void out_of_mem __P((void));
void parsecred __P((char *, struct xucred *));
int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
-int scan_tree __P((struct dirlist *, u_int32_t));
+int scan_tree __P((struct dirlist *, struct sockaddr *));
static void usage __P((void));
int xdr_dir __P((XDR *, char *));
int xdr_explist __P((XDR *, caddr_t));
int xdr_fhs __P((XDR *, caddr_t));
int xdr_mlist __P((XDR *, caddr_t));
+void terminate __P((int));
/* C library */
int getnetgrent();
void endnetgrent();
void setnetgrent();
+static int bitcmp __P((void *, void *, int));
+static int netpartcmp __P((struct sockaddr *, struct sockaddr *, int));
+static int sacmp __P((struct sockaddr *, struct sockaddr *));
+static int allones __P((struct sockaddr_storage *, int));
+static int countones __P((struct sockaddr *));
+
struct exportlist *exphead;
struct mountlist *mlhead;
struct grouplist *grphead;
@@ -213,7 +227,16 @@ int force_v2 = 0;
int resvport_only = 1;
int dir_only = 1;
int log = 0;
+
int opt_flags;
+static int have_v6 = 1;
+#ifdef NI_WITHSCOPEID
+static const int ninumeric = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+static const int ninumeric = NI_NUMERICHOST;
+#endif
+
+int mountdlockfd;
/* Bits for above */
#define OP_MAPROOT 0x01
#define OP_MAPALL 0x02
@@ -221,6 +244,7 @@ int opt_flags;
#define OP_MASK 0x08
#define OP_NET 0x10
#define OP_ALLDIRS 0x40
+#define OP_MASKLEN 0x200
#ifdef DEBUG
int debug = 1;
@@ -242,10 +266,26 @@ main(argc, argv)
int argc;
char **argv;
{
- SVCXPRT *udptransp, *tcptransp;
+ SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp;
+ struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf;
+ int udpsock, tcpsock, udp6sock, tcp6sock;
+ int xcreated = 0, s;
+ int one = 1;
int c, error, mib[3];
struct vfsconf vfc;
+ /* Check that another mountd isn't already running. */
+
+ if ((mountdlockfd = (open(MOUNTDLOCK, O_RDONLY|O_CREAT, 0444))) == -1)
+ err(1, "%s", MOUNTDLOCK);
+
+ if(flock(mountdlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
+ errx(1, "another rpc.mountd is already running. Aborting");
+ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0)
+ have_v6 = 0;
+ else
+ close(s);
error = getvfsbyname("nfs", &vfc);
if (error && vfsisloadable("nfs")) {
if(vfsload("nfs"))
@@ -301,12 +341,38 @@ main(argc, argv)
signal(SIGQUIT, SIG_IGN);
}
signal(SIGHUP, (void (*) __P((int))) get_exportlist);
+ signal(SIGTERM, terminate);
{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
if (pidfile != NULL) {
fprintf(pidfile, "%d\n", getpid());
fclose(pidfile);
}
}
+ rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
+ rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
+ udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ tcpsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ udp6sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ tcp6sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ /*
+ * We're doing host-based access checks here, so don't allow
+ * v4-in-v6 to confuse things. The kernel will disable it
+ * by default on NFS sockets too.
+ */
+ if (udp6sock != -1 && setsockopt(udp6sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY, &one, sizeof one) < 0){
+ syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket");
+ exit(1);
+ }
+ if (tcp6sock != -1 && setsockopt(tcp6sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY, &one, sizeof one) < 0){
+ syslog(LOG_ERR, "can't disable v4-in-v6 on UDP socket");
+ exit(1);
+ }
+ udpconf = getnetconfigent("udp");
+ tcpconf = getnetconfigent("tcp");
+ udp6conf = getnetconfigent("udp6");
+ tcp6conf = getnetconfigent("tcp6");
if (!resvport_only) {
mib[0] = CTL_VFS;
mib[1] = vfc.vfc_typenum;
@@ -322,17 +388,90 @@ main(argc, argv)
syslog(LOG_ERR, "can't create socket");
exit(1);
}
- pmap_unset(RPCPROG_MNT, 1);
- pmap_unset(RPCPROG_MNT, 3);
- if (!force_v2)
- if (!svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) ||
- !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) {
- syslog(LOG_ERR, "can't register mount");
- exit(1);
- }
- if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) ||
- !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP)) {
- syslog(LOG_ERR, "can't register mount");
+ if (udpsock != -1 && udpconf != NULL) {
+ bindresvport(udpsock, NULL);
+ udptransp = svc_dg_create(udpsock, 0, 0);
+ if (udptransp != NULL) {
+ if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, udpconf))
+ syslog(LOG_WARNING, "can't register UDP RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, udpconf))
+ syslog(LOG_WARNING, "can't register UDP RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create UDP services");
+
+ }
+ if (tcpsock != -1 && tcpconf != NULL) {
+ bindresvport(tcpsock, NULL);
+ listen(tcpsock, SOMAXCONN);
+ tcptransp = svc_vc_create(tcpsock, 0, 0);
+ if (tcptransp != NULL) {
+ if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, tcpconf))
+ syslog(LOG_WARNING, "can't register TCP RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(tcptransp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, tcpconf))
+ syslog(LOG_WARNING, "can't register TCP RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create TCP service");
+
+ }
+ if (udp6sock != -1 && udp6conf != NULL) {
+ bindresvport(udp6sock, NULL);
+ udp6transp = svc_dg_create(udp6sock, 0, 0);
+ if (udp6transp != NULL) {
+ if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, udp6conf))
+ syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, udp6conf))
+ syslog(LOG_WARNING, "can't register UDP6 RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create UDP6 service");
+
+ }
+ if (tcp6sock != -1 && tcp6conf != NULL) {
+ bindresvport(tcp6sock, NULL);
+ listen(tcp6sock, SOMAXCONN);
+ tcp6transp = svc_vc_create(tcp6sock, 0, 0);
+ if (tcp6transp != NULL) {
+ if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER1,
+ mntsrv, tcp6conf))
+ syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER1 service");
+ else
+ xcreated++;
+ if (!force_v2) {
+ if (!svc_reg(tcp6transp, RPCPROG_MNT, RPCMNT_VER3,
+ mntsrv, tcp6conf))
+ syslog(LOG_WARNING, "can't register TCP6 RPCMNT_VER3 service");
+ else
+ xcreated++;
+ }
+ } else
+ syslog(LOG_WARNING, "can't create TCP6 service");
+
+ }
+ if (xcreated == 0) {
+ syslog(LOG_ERR, "could not create any services");
exit(1);
}
svc_run();
@@ -361,20 +500,38 @@ mntsrv(rqstp, transp)
struct fhreturn fhr;
struct stat stb;
struct statfs fsb;
- struct hostent *hp;
- struct in_addr saddrin;
- u_int32_t saddr;
+ struct addrinfo *ai;
+ char host[NI_MAXHOST], numerichost[NI_MAXHOST];
+ int lookup_failed = 1;
+ struct sockaddr *saddr;
u_short sport;
char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
int bad = 0, defset, hostset;
sigset_t sighup_mask;
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
sigemptyset(&sighup_mask);
sigaddset(&sighup_mask, SIGHUP);
- saddr = transp->xp_raddr.sin_addr.s_addr;
- saddrin = transp->xp_raddr.sin_addr;
- sport = ntohs(transp->xp_raddr.sin_port);
- hp = (struct hostent *)NULL;
+ saddr = svc_getrpccaller(transp)->buf;
+ switch (saddr->sa_family) {
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)saddr;
+ sport = ntohs(sin6->sin6_port);
+ break;
+ case AF_INET:
+ sin = (struct sockaddr_in *)saddr;
+ sport = ntohs(sin->sin_port);
+ break;
+ default:
+ syslog(LOG_ERR, "request from unknown address family");
+ return;
+ }
+ lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host,
+ NULL, 0, 0);
+ getnameinfo(saddr, saddr->sa_len, numerichost,
+ sizeof numerichost, NULL, 0, NI_NUMERICHOST);
+ ai = NULL;
switch (rqstp->rq_proc) {
case NULLPROC:
if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
@@ -384,13 +541,13 @@ mntsrv(rqstp, transp)
if (sport >= IPPORT_RESERVED && resvport_only) {
syslog(LOG_NOTICE,
"mount request from %s from unprivileged port",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_weakauth(transp);
return;
}
if (!svc_getargs(transp, xdr_dir, rpcpath)) {
syslog(LOG_NOTICE, "undecodable mount request from %s",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_decode(transp);
return;
}
@@ -403,12 +560,12 @@ mntsrv(rqstp, transp)
if (realpath(rpcpath, dirpath) == NULL ||
stat(dirpath, &stb) < 0 ||
(!S_ISDIR(stb.st_mode) &&
- (dir_only || !S_ISREG(stb.st_mode))) ||
+ (dir_only || !S_ISREG(stb.st_mode))) ||
statfs(dirpath, &fsb) < 0) {
chdir("/"); /* Just in case realpath doesn't */
syslog(LOG_NOTICE,
"mount request from %s for non existent path %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
if (debug)
warnx("stat failed on %s", dirpath);
bad = ENOENT; /* We will send error reply later */
@@ -420,9 +577,9 @@ mntsrv(rqstp, transp)
hostset = defset = 0;
if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
((dp = dirp_search(ep->ex_dirl, dirpath)) &&
- chk_host(dp, saddr, &defset, &hostset)) ||
- (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
- scan_tree(ep->ex_dirl, saddr) == 0))) {
+ chk_host(dp, saddr, &defset, &hostset)) ||
+ (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
+ scan_tree(ep->ex_dirl, saddr) == 0))) {
if (bad) {
if (!svc_sendreply(transp, xdr_long,
(caddr_t)&bad))
@@ -448,25 +605,21 @@ mntsrv(rqstp, transp)
}
if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
syslog(LOG_ERR, "can't send reply");
- if (hp == NULL)
- hp = gethostbyaddr((caddr_t)&saddr,
- sizeof(saddr), AF_INET);
- if (hp)
- add_mlist(hp->h_name, dirpath);
+ if (!lookup_failed)
+ add_mlist(host, dirpath);
else
- add_mlist(inet_ntoa(saddrin),
- dirpath);
+ add_mlist(numerichost, dirpath);
if (debug)
warnx("mount successful");
if (log)
syslog(LOG_NOTICE,
"mount request succeeded from %s for %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
} else {
bad = EACCES;
syslog(LOG_NOTICE,
"mount request denied from %s for %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
}
if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad))
@@ -479,56 +632,54 @@ mntsrv(rqstp, transp)
else if (log)
syslog(LOG_NOTICE,
"dump request succeeded from %s",
- inet_ntoa(saddrin));
+ numerichost);
return;
case RPCMNT_UMOUNT:
if (sport >= IPPORT_RESERVED && resvport_only) {
syslog(LOG_NOTICE,
"umount request from %s from unprivileged port",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_weakauth(transp);
return;
}
if (!svc_getargs(transp, xdr_dir, rpcpath)) {
syslog(LOG_NOTICE, "undecodable umount request from %s",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_decode(transp);
return;
}
if (realpath(rpcpath, dirpath) == NULL) {
syslog(LOG_NOTICE, "umount request from %s "
"for non existent path %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
}
if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
syslog(LOG_ERR, "can't send reply");
- hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
- if (hp)
- del_mlist(hp->h_name, dirpath);
- del_mlist(inet_ntoa(saddrin), dirpath);
+ if (!lookup_failed)
+ del_mlist(host, dirpath, saddr);
+ del_mlist(numerichost, dirpath, saddr);
if (log)
syslog(LOG_NOTICE,
"umount request succeeded from %s for %s",
- inet_ntoa(saddrin), dirpath);
+ numerichost, dirpath);
return;
case RPCMNT_UMNTALL:
if (sport >= IPPORT_RESERVED && resvport_only) {
syslog(LOG_NOTICE,
"umountall request from %s from unprivileged port",
- inet_ntoa(saddrin));
+ numerichost);
svcerr_weakauth(transp);
return;
}
if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
syslog(LOG_ERR, "can't send reply");
- hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
- if (hp)
- del_mlist(hp->h_name, (char *)NULL);
- del_mlist(inet_ntoa(saddrin), (char *)NULL);
+ if (!lookup_failed)
+ del_mlist(host, NULL, saddr);
+ del_mlist(numerichost, NULL, saddr);
if (log)
syslog(LOG_NOTICE,
"umountall request succeeded from %s",
- inet_ntoa(saddrin));
+ numerichost);
return;
case RPCMNT_EXPORT:
if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
@@ -536,7 +687,7 @@ mntsrv(rqstp, transp)
if (log)
syslog(LOG_NOTICE,
"export request succeeded from %s",
- inet_ntoa(saddrin));
+ numerichost);
return;
default:
svcerr_noproc(transp);
@@ -690,7 +841,7 @@ put_exlist(dp, xdrsp, adp, putdefp)
if (grp->gr_type == GT_HOST) {
if (!xdr_bool(xdrsp, &true))
return (1);
- strp = grp->gr_ptr.gt_hostent->h_name;
+ strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
if (!xdr_string(xdrsp, &strp,
RPCMNT_NAMELEN))
return (1);
@@ -732,7 +883,7 @@ get_exportlist()
struct exportlist **epp;
struct dirlist *dirhead;
struct statfs fsb, *fsp;
- struct hostent *hpe;
+ struct addrinfo *ai;
struct xucred anon;
char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
@@ -786,7 +937,7 @@ get_exportlist()
fsp->f_flags | MNT_UPDATE,
(caddr_t)&targs) < 0)
syslog(LOG_ERR, "can't delete exports for %s",
- fsp->f_mntonname);
+ fsp->f_mntonname);
}
fsp++;
}
@@ -874,9 +1025,9 @@ get_exportlist()
else
out_of_mem();
if (debug)
- warnx("making new ep fs=0x%x,0x%x",
- fsb.f_fsid.val[0],
- fsb.f_fsid.val[1]);
+ warnx("making new ep fs=0x%x,0x%x",
+ fsb.f_fsid.val[0],
+ fsb.f_fsid.val[1]);
} else if (debug)
warnx("found ep fs=0x%x,0x%x",
fsb.f_fsid.val[0],
@@ -944,14 +1095,17 @@ get_exportlist()
if (debug)
warnx("adding a default entry");
/* add a default group and make the grp list NULL */
- hpe = (struct hostent *)malloc(sizeof(struct hostent));
- if (hpe == (struct hostent *)NULL)
- out_of_mem();
- hpe->h_name = strdup("Default");
- hpe->h_addrtype = AF_INET;
- hpe->h_length = sizeof (u_int32_t);
- hpe->h_addr_list = (char **)NULL;
- grp->gr_ptr.gt_hostent = hpe;
+ ai = malloc(sizeof(struct addrinfo));
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET; /* XXXX */
+ ai->ai_socktype = SOCK_DGRAM;
+ /* setting the length to 0 will match anything */
+ ai->ai_addrlen = 0;
+ ai->ai_flags = AI_CANONNAME;
+ ai->ai_canonname = strdup("Default");
+ ai->ai_addr = NULL;
+ ai->ai_next = NULL;
+ grp->gr_ptr.gt_addrinfo = ai;
/*
* Don't allow a network export coincide with a list of
@@ -961,13 +1115,13 @@ get_exportlist()
getexp_err(ep, tgrp);
goto nextline;
- /*
- * If an export list was specified on this line, make sure
+ /*
+ * If an export list was specified on this line, make sure
* that we have at least one valid entry, otherwise skip it.
*/
} else {
grp = tgrp;
- while (grp && grp->gr_type == GT_IGNORE)
+ while (grp && grp->gr_type == GT_IGNORE)
grp = grp->gr_next;
if (! grp) {
getexp_err(ep, tgrp);
@@ -1219,19 +1373,27 @@ add_dlist(dpp, newdp, grp, flags)
/*
* Search for a dirpath on the export point.
*/
+void *
+test()
+{
+}
+
+/*
+ * Search for a dirpath on the export point.
+ */
struct dirlist *
-dirp_search(dp, dirpath)
+dirp_search(dp, dirp)
struct dirlist *dp;
- char *dirpath;
+ char *dirp;
{
int cmp;
if (dp) {
- cmp = strcmp(dp->dp_dirp, dirpath);
+ cmp = strcmp(dp->dp_dirp, dirp);
if (cmp > 0)
- return (dirp_search(dp->dp_left, dirpath));
+ return (dirp_search(dp->dp_left, dirp));
else if (cmp < 0)
- return (dirp_search(dp->dp_right, dirpath));
+ return (dirp_search(dp->dp_right, dirp));
else
return (dp);
}
@@ -1239,18 +1401,59 @@ dirp_search(dp, dirpath)
}
/*
+ * Some helper functions for netmasks. They all assume masks in network
+ * order (big endian).
+ */
+static int
+bitcmp(void *dst, void *src, int bitlen)
+{
+ int i;
+ u_int8_t *p1 = dst, *p2 = src;
+ u_int8_t bitmask;
+ int bytelen, bitsleft;
+
+ bytelen = bitlen / 8;
+ bitsleft = bitlen % 8;
+
+ if (debug) {
+ printf("comparing:\n");
+ for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++)
+ printf("%02x", p1[i]);
+ printf("\n");
+ for (i = 0; i < (bitsleft ? bytelen + 1 : bytelen); i++)
+ printf("%02x", p2[i]);
+ printf("\n");
+ }
+
+ for (i = 0; i < bytelen; i++) {
+ if (*p1 != *p2)
+ return 1;
+ p1++;
+ p2++;
+ }
+
+ for (i = 0; i < bitsleft; i++) {
+ bitmask = 1 << (7 - i);
+ if ((*p1 & bitmask) != (*p2 & bitmask))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
* Scan for a host match in a directory tree.
*/
int
chk_host(dp, saddr, defsetp, hostsetp)
struct dirlist *dp;
- u_int32_t saddr;
+ struct sockaddr *saddr;
int *defsetp;
int *hostsetp;
{
struct hostlist *hp;
struct grouplist *grp;
- u_int32_t **addrp;
+ struct addrinfo *ai;
if (dp) {
if (dp->dp_flag & DP_DEFSET)
@@ -1260,22 +1463,22 @@ chk_host(dp, saddr, defsetp, hostsetp)
grp = hp->ht_grp;
switch (grp->gr_type) {
case GT_HOST:
- addrp = (u_int32_t **)
- grp->gr_ptr.gt_hostent->h_addr_list;
- while (*addrp) {
- if (**addrp == saddr) {
- *hostsetp = (hp->ht_flag | DP_HOSTSET);
- return (1);
+ ai = grp->gr_ptr.gt_addrinfo;
+ for (; ai; ai = ai->ai_next) {
+ if (!sacmp(ai->ai_addr, saddr)) {
+ *hostsetp =
+ (hp->ht_flag | DP_HOSTSET);
+ return (1);
+ }
}
- addrp++;
- }
break;
case GT_NET:
- if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
- grp->gr_ptr.gt_net.nt_net) {
- *hostsetp = (hp->ht_flag | DP_HOSTSET);
- return (1);
- }
+ if (!netpartcmp(saddr,
+ (struct sockaddr *) &grp->gr_ptr.gt_net.nt_net,
+ grp->gr_ptr.gt_net.nt_mask)) {
+ *hostsetp = (hp->ht_flag | DP_HOSTSET);
+ return (1);
+ }
break;
};
hp = hp->ht_next;
@@ -1290,7 +1493,7 @@ chk_host(dp, saddr, defsetp, hostsetp)
int
scan_tree(dp, saddr)
struct dirlist *dp;
- u_int32_t saddr;
+ struct sockaddr *saddr;
{
int defset, hostset;
@@ -1392,6 +1595,11 @@ do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
opt_flags |= OP_MASK;
} else if (cpoptarg && (!strcmp(cpopt, "network") ||
!strcmp(cpopt, "n"))) {
+ if (strchr(cpoptarg, '/') != NULL) {
+ if (debug)
+ fprintf(stderr, "setting OP_MASKLEN\n");
+ opt_flags |= OP_MASKLEN;
+ }
if (grp->gr_type != GT_NULL) {
syslog(LOG_ERR, "network/host conflict");
return (1);
@@ -1442,84 +1650,40 @@ get_host(cp, grp, tgrp)
struct grouplist *tgrp;
{
struct grouplist *checkgrp;
- struct hostent *hp, *nhp;
- char **addrp, **naddrp;
- struct hostent t_host;
+ struct addrinfo *ai, hints;
+ int ecode;
+ char host[NI_MAXHOST];
int i;
- u_int32_t saddr;
char *aptr[2];
- if (grp->gr_type != GT_NULL)
+ if (grp->gr_type != GT_NULL) {
+ syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
return (1);
- if ((hp = gethostbyname(cp)) == NULL) {
- if (isdigit(*cp)) {
- saddr = inet_addr(cp);
- if (saddr == -1) {
- syslog(LOG_ERR, "inet_addr failed for %s", cp);
- return (1);
- }
- if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
- AF_INET)) == NULL) {
- hp = &t_host;
- hp->h_name = cp;
- hp->h_addrtype = AF_INET;
- hp->h_length = sizeof (u_int32_t);
- hp->h_addr_list = aptr;
- aptr[0] = (char *)&saddr;
- aptr[1] = (char *)NULL;
- }
- } else {
- syslog(LOG_ERR, "gethostbyname failed for %s", cp);
- return (1);
- }
}
- /*
- * Sanity check: make sure we don't already have an entry
- * for this host in the grouplist.
- */
- checkgrp = tgrp;
- while (checkgrp != NULL) {
- if (checkgrp->gr_type == GT_HOST &&
- checkgrp->gr_ptr.gt_hostent != NULL &&
- (!strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)
- || *(u_int32_t *)checkgrp->gr_ptr.gt_hostent->h_addr ==
- *(u_int32_t *)hp->h_addr)) {
- grp->gr_type = GT_IGNORE;
- return(0);
- }
- checkgrp = checkgrp->gr_next;
- }
-
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(cp, NULL, &hints, &ai);
+ if (ecode != 0) {
+ syslog(LOG_ERR,"can't get address info for "
+ "host %s", cp);
+ return 1;
+ }
grp->gr_type = GT_HOST;
- nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
- malloc(sizeof(struct hostent));
- if (nhp == (struct hostent *)NULL)
- out_of_mem();
- memmove(nhp, hp, sizeof(struct hostent));
- i = strlen(hp->h_name)+1;
- nhp->h_name = (char *)malloc(i);
- if (nhp->h_name == (char *)NULL)
- out_of_mem();
- memmove(nhp->h_name, hp->h_name, i);
- addrp = hp->h_addr_list;
- i = 1;
- while (*addrp++)
- i++;
- naddrp = nhp->h_addr_list = (char **)malloc(i*sizeof(char *));
- if (naddrp == (char **)NULL)
- out_of_mem();
- addrp = hp->h_addr_list;
- while (*addrp) {
- *naddrp = (char *)malloc(hp->h_length);
- if (*naddrp == (char *)NULL)
- out_of_mem();
- memmove(*naddrp, *addrp, hp->h_length);
- addrp++;
- naddrp++;
- }
- *naddrp = (char *)NULL;
- if (debug)
- warnx("got host %s", hp->h_name);
+ grp->gr_ptr.gt_addrinfo = ai;
+ while (ai != NULL) {
+ if (ai->ai_canonname == NULL) {
+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
+ sizeof host, NULL, 0, ninumeric) != 0)
+ strlcpy(host, "?", sizeof(host));
+ ai->ai_canonname = strdup(host);
+ ai->ai_flags |= AI_CANONNAME;
+ } else
+ ai->ai_flags &= ~AI_CANONNAME;
+ if (debug)
+ (void)fprintf(stderr, "got host %s\n", ai->ai_canonname);
+ ai = ai->ai_next;
+ }
return (0);
}
@@ -1597,68 +1761,64 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
int dirplen;
struct statfs *fsb;
{
- char *cp = (char *)NULL;
- u_int32_t **addrp;
+ struct sockaddr *addrp;
+ struct sockaddr_storage ss;
+ struct addrinfo *ai;
+ int addrlen;
+ char *cp = NULL;
int done;
char savedc = '\0';
- struct sockaddr_in sin, imask;
union {
struct ufs_args ua;
struct iso_args ia;
struct mfs_args ma;
#ifdef __NetBSD__
struct msdosfs_args da;
+ struct adosfs_args aa;
#endif
struct ntfs_args na;
} args;
- u_int32_t net;
args.ua.fspec = 0;
args.ua.export.ex_flags = exflags;
args.ua.export.ex_anon = *anoncrp;
args.ua.export.ex_indexfile = ep->ex_indexfile;
- memset(&sin, 0, sizeof(sin));
- memset(&imask, 0, sizeof(imask));
- sin.sin_family = AF_INET;
- sin.sin_len = sizeof(sin);
- imask.sin_family = AF_INET;
- imask.sin_len = sizeof(sin);
- if (grp->gr_type == GT_HOST)
- addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list;
- else
- addrp = (u_int32_t **)NULL;
+ if (grp->gr_type == GT_HOST) {
+ ai = grp->gr_ptr.gt_addrinfo;
+ addrp = ai->ai_addr;
+ addrlen = ai->ai_addrlen;
+ } else
+ addrp = NULL;
done = FALSE;
while (!done) {
switch (grp->gr_type) {
case GT_HOST:
- if (addrp) {
- sin.sin_addr.s_addr = **addrp;
- args.ua.export.ex_addrlen = sizeof(sin);
- } else
- args.ua.export.ex_addrlen = 0;
- args.ua.export.ex_addr = (struct sockaddr *)&sin;
+ if (addrp != NULL && addrp->sa_family == AF_INET6 &&
+ have_v6 == 0)
+ goto skip;
+ args.ua.export.ex_addr = addrp;
+ args.ua.export.ex_addrlen = addrlen;
args.ua.export.ex_masklen = 0;
break;
case GT_NET:
- if (grp->gr_ptr.gt_net.nt_mask)
- imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
- else {
- net = ntohl(grp->gr_ptr.gt_net.nt_net);
- if (IN_CLASSA(net))
- imask.sin_addr.s_addr = inet_addr("255.0.0.0");
- else if (IN_CLASSB(net))
- imask.sin_addr.s_addr =
- inet_addr("255.255.0.0");
- else
- imask.sin_addr.s_addr =
- inet_addr("255.255.255.0");
- grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
+ args.ua.export.ex_addr = (struct sockaddr *)
+ &grp->gr_ptr.gt_net.nt_net;
+ if (args.ua.export.ex_addr->sa_family == AF_INET6 &&
+ have_v6 == 0)
+ goto skip;
+ args.ua.export.ex_addrlen =
+ args.ua.export.ex_addr->sa_len;
+ memset(&ss, 0, sizeof ss);
+ ss.ss_family = args.ua.export.ex_addr->sa_family;
+ ss.ss_len = args.ua.export.ex_addr->sa_len;
+ if (allones(&ss, grp->gr_ptr.gt_net.nt_mask) != 0) {
+ syslog(LOG_ERR, "Bad network flag");
+ if (cp)
+ *cp = savedc;
+ return (1);
}
- sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
- args.ua.export.ex_addr = (struct sockaddr *)&sin;
- args.ua.export.ex_addrlen = sizeof (sin);
- args.ua.export.ex_mask = (struct sockaddr *)&imask;
- args.ua.export.ex_masklen = sizeof (imask);
+ args.ua.export.ex_mask = (struct sockaddr *)&ss;
+ args.ua.export.ex_masklen = ss.ss_len;
break;
case GT_IGNORE:
return(0);
@@ -1678,7 +1838,7 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
* exportable file systems and not just "ufs".
*/
while (mount(fsb->f_fstypename, dirp,
- fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
+ fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
if (cp)
*cp-- = savedc;
else
@@ -1707,10 +1867,15 @@ do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
savedc = *cp;
*cp = '\0';
}
+skip:
if (addrp) {
- ++addrp;
- if (*addrp == (u_int32_t *)NULL)
+ ai = ai->ai_next;
+ if (ai == NULL)
done = TRUE;
+ else {
+ addrp = ai->ai_addr;
+ addrlen = ai->ai_addrlen;
+ }
} else
done = TRUE;
}
@@ -1729,47 +1894,105 @@ get_net(cp, net, maskflg)
int maskflg;
{
struct netent *np;
- long netaddr;
- struct in_addr inetaddr, inetaddr2;
- char *name;
+ char *name, *p, *prefp;
+ struct sockaddr_in sin, *sinp;
+ struct sockaddr *sa;
+ struct addrinfo hints, *ai = NULL;
+ char netname[NI_MAXHOST];
+ long preflen;
+ int ecode;
+
+ if ((opt_flags & OP_MASKLEN) && !maskflg) {
+ p = strchr(cp, '/');
+ *p = '\0';
+ prefp = p + 1;
+ }
- if (isdigit(*cp) && ((netaddr = inet_network(cp)) != -1)) {
- inetaddr = inet_makeaddr(netaddr, 0);
- /*
- * Due to arbitrary subnet masks, you don't know how many
- * bits to shift the address to make it into a network,
- * however you do know how to make a network address into
- * a host with host == 0 and then compare them.
- * (What a pest)
- */
- if (!maskflg) {
- setnetent(0);
- while ((np = getnetent())) {
- inetaddr2 = inet_makeaddr(np->n_net, 0);
- if (inetaddr2.s_addr == inetaddr.s_addr)
- break;
- }
- endnetent();
- }
- } else if ((np = getnetbyname(cp)) != NULL) {
- inetaddr = inet_makeaddr(np->n_net, 0);
+ if ((np = getnetbyname(cp)) != NULL) {
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof sin;
+ sin.sin_addr = inet_makeaddr(np->n_net, 0);
+ sa = (struct sockaddr *)&sin;
+ } else if (isdigit(*cp)) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(cp, NULL, &hints, &ai) != 0) {
+ /*
+ * If getaddrinfo() failed, try the inet4 network
+ * notation with less than 3 dots.
+ */
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof sin;
+ sin.sin_addr = inet_makeaddr(inet_network(cp),0);
+ if (debug)
+ fprintf(stderr, "get_net: v4 addr %x\n",
+ sin.sin_addr.s_addr);
+ sa = (struct sockaddr *)&sin;
+ } else
+ sa = ai->ai_addr;
+ } else if (isxdigit(*cp) || *cp == ':') {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
+ sa = ai->ai_addr;
+ else
+ goto fail;
} else
- return (1);
+ goto fail;
+
+ ecode = getnameinfo(sa, sa->sa_len, netname, sizeof netname,
+ NULL, 0, ninumeric);
+ if (ecode != 0)
+ goto fail;
if (maskflg)
- net->nt_mask = inetaddr.s_addr;
+ net->nt_mask = countones(sa);
else {
+ if (opt_flags & OP_MASKLEN) {
+ preflen = strtol(prefp, NULL, 10);
+ if (preflen == LONG_MIN && errno == ERANGE)
+ goto fail;
+ net->nt_mask = (int)preflen;
+ *p = '/';
+ }
+
if (np)
name = np->n_name;
+ else {
+ if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
+ NULL, 0, ninumeric) != 0)
+ strlcpy(netname, "?", sizeof(netname));
+ name = netname;
+ }
+ net->nt_name = strdup(name);
+ memcpy(&net->nt_net, sa, sa->sa_len);
+ }
+
+ if (!maskflg && sa->sa_family == AF_INET &&
+ !(opt_flags & (OP_MASK|OP_MASKLEN))) {
+ sinp = (struct sockaddr_in *)sa;
+ if (IN_CLASSA(sinp->sin_addr.s_addr))
+ net->nt_mask = 8;
+ else if (IN_CLASSB(sinp->sin_addr.s_addr))
+ net->nt_mask = 16;
+ else if (IN_CLASSC(sinp->sin_addr.s_addr))
+ net->nt_mask = 24;
+ else if (IN_CLASSD(sinp->sin_addr.s_addr))
+ net->nt_mask = 28;
else
- name = inet_ntoa(inetaddr);
- net->nt_name = (char *)malloc(strlen(name) + 1);
- if (net->nt_name == (char *)NULL)
- out_of_mem();
- strcpy(net->nt_name, name);
- net->nt_net = inetaddr.s_addr;
+ net->nt_mask = 32; /* XXX */
}
- return (0);
+
+ if (ai)
+ freeaddrinfo(ai);
+ return 0;
+
+fail:
+ if (ai)
+ freeaddrinfo(ai);
+ return 1;
}
/*
@@ -1958,15 +2181,28 @@ get_mountlist()
fclose(mlfile);
}
-void
-del_mlist(hostp, dirp)
+int
+del_mlist(hostp, dirp, saddr)
char *hostp, *dirp;
+ struct sockaddr *saddr;
{
struct mountlist *mlp, **mlpp;
struct mountlist *mlp2;
+ u_short sport;
FILE *mlfile;
int fnd = 0;
-
+ char host[NI_MAXHOST];
+
+ switch (saddr->sa_family) {
+ case AF_INET6:
+ sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
+ break;
+ case AF_INET:
+ sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
+ break;
+ default:
+ return -1;
+ }
mlpp = &mlhead;
mlp = mlhead;
while (mlp) {
@@ -2034,17 +2270,11 @@ void
free_grp(grp)
struct grouplist *grp;
{
- char **addrp;
+ struct addrinfo *ai;
if (grp->gr_type == GT_HOST) {
- if (grp->gr_ptr.gt_hostent->h_name) {
- addrp = grp->gr_ptr.gt_hostent->h_addr_list;
- while (addrp && *addrp)
- free(*addrp++);
- free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
- free(grp->gr_ptr.gt_hostent->h_name);
- }
- free((caddr_t)grp->gr_ptr.gt_hostent);
+ if (grp->gr_ptr.gt_addrinfo != NULL)
+ freeaddrinfo(grp->gr_ptr.gt_addrinfo);
} else if (grp->gr_type == GT_NET) {
if (grp->gr_ptr.gt_net.nt_name)
free(grp->gr_ptr.gt_net.nt_name);
@@ -2093,7 +2323,6 @@ check_options(dp)
/*
* Check an absolute directory path for any symbolic links. Return true
- * if no symbolic links are found.
*/
int
check_dirpath(dirp)
@@ -2134,3 +2363,146 @@ get_num(cp)
}
return (res);
}
+
+static int
+netpartcmp(struct sockaddr *s1, struct sockaddr *s2, int bitlen)
+{
+ void *src, *dst;
+
+ if (s1->sa_family != s2->sa_family)
+ return 1;
+
+ switch (s1->sa_family) {
+ case AF_INET:
+ src = &((struct sockaddr_in *)s1)->sin_addr;
+ dst = &((struct sockaddr_in *)s2)->sin_addr;
+ if (bitlen > sizeof(((struct sockaddr_in *)s1)->sin_addr) * 8)
+ return 1;
+ break;
+ case AF_INET6:
+ src = &((struct sockaddr_in6 *)s1)->sin6_addr;
+ dst = &((struct sockaddr_in6 *)s2)->sin6_addr;
+ if (((struct sockaddr_in6 *)s1)->sin6_scope_id !=
+ ((struct sockaddr_in6 *)s2)->sin6_scope_id)
+ return 1;
+ if (bitlen > sizeof(((struct sockaddr_in6 *)s1)->sin6_addr) * 8)
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return bitcmp(src, dst, bitlen);
+}
+
+static int
+allones(struct sockaddr_storage *ssp, int bitlen)
+{
+ u_int8_t *p;
+ int bytelen, bitsleft, i;
+ int zerolen;
+
+ switch (ssp->ss_family) {
+ case AF_INET:
+ p = (u_int8_t *)&((struct sockaddr_in *)ssp)->sin_addr;
+ zerolen = sizeof (((struct sockaddr_in *)ssp)->sin_addr);
+ break;
+ case AF_INET6:
+ p = (u_int8_t *)&((struct sockaddr_in6 *)ssp)->sin6_addr;
+ zerolen = sizeof (((struct sockaddr_in6 *)ssp)->sin6_addr);
+ break;
+ default:
+ return -1;
+ }
+
+ memset(p, 0, zerolen);
+
+ bytelen = bitlen / 8;
+ bitsleft = bitlen % 8;
+
+ if (bytelen > zerolen)
+ return -1;
+
+ for (i = 0; i < bytelen; i++)
+ *p++ = 0xff;
+
+ for (i = 0; i < bitsleft; i++)
+ *p |= 1 << (7 - i);
+
+ return 0;
+}
+
+static int
+countones(struct sockaddr *sa)
+{
+ void *mask;
+ int i, bits = 0, bytelen;
+ u_int8_t *p;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ mask = (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr;
+ bytelen = 4;
+ break;
+ case AF_INET6:
+ mask = (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr;
+ bytelen = 16;
+ break;
+ default:
+ return 0;
+ }
+
+ p = mask;
+
+ for (i = 0; i < bytelen; i++, p++) {
+ if (*p != 0xff) {
+ for (bits = 0; bits < 8; bits++) {
+ if (!(*p & (1 << (7 - bits))))
+ break;
+ }
+ break;
+ }
+ }
+
+ return (i * 8 + bits);
+}
+
+static int
+sacmp(struct sockaddr *sa1, struct sockaddr *sa2)
+{
+ void *p1, *p2;
+ int len;
+
+ if (sa1->sa_family != sa2->sa_family)
+ return 1;
+
+ switch (sa1->sa_family) {
+ case AF_INET:
+ p1 = &((struct sockaddr_in *)sa1)->sin_addr;
+ p2 = &((struct sockaddr_in *)sa2)->sin_addr;
+ len = 4;
+ break;
+ case AF_INET6:
+ p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
+ p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
+ len = 16;
+ if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
+ ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return memcmp(p1, p2, len);
+}
+
+void terminate(sig)
+int sig;
+{
+ close(mountdlockfd);
+ unlink(MOUNTDLOCK);
+ pmap_unset(RPCPROG_MNT, 1);
+ pmap_unset(RPCPROG_MNT, 3);
+ exit (0);
+}
diff --git a/usr.sbin/nfsd/nfsd.8 b/usr.sbin/nfsd/nfsd.8
index fb44149..0031ea1 100644
--- a/usr.sbin/nfsd/nfsd.8
+++ b/usr.sbin/nfsd/nfsd.8
@@ -42,7 +42,7 @@
server
.Sh SYNOPSIS
.Nm
-.Op Fl arut
+.Op Fl ardut
.Op Fl n Ar num_servers
.Op Fl h Ar bindip
.Sh DESCRIPTION
@@ -64,13 +64,19 @@ The following options are available:
Register the
.Tn NFS
service with
-.Xr portmap 8
+.Xr rpcbind 8
without creating any servers.
This option can be used along with the
.Fl u
or
.Fl t
-options to re-register NFS if the portmap server is restarted.
+options to re-register NFS if the rpcbind server is restarted.
+.It Fl d
+Unregister the
+.Tn NFS
+service with
+.Xr rpcbind 8
+without creating any servers.
.It Fl n
Specifies how many servers to create.
.It Fl h Ar bindip
@@ -147,6 +153,16 @@ that the NFS sockets can only be accessed by the inside interface.
would then be used to block nfs-related packets that come in on the outside
interface.
.Pp
+.Nm
+has to be terminated with SIGUSR1 and cannot be killed with SIGTERM oder SIGQUIT.
+.Nm
+needs to ignore these signals in order to stay alive as long
+as possible during a shutdown, otherwise loopback mounts will
+not be able to unmount. If you have to kill
+.Nm
+just do a
+.Dq Li "kill -USR1 <PID of master nfsd>"
+.Pp
The
.Nm
utility exits 0 on success, and >0 if an error occurs.
@@ -156,7 +172,7 @@ utility exits 0 on success, and >0 if an error occurs.
.Xr kldload 8 ,
.Xr mountd 8 ,
.Xr nfsiod 8 ,
-.Xr portmap 8 ,
+.Xr rpcbind 8 ,
.Xr ipfw 8
.Sh HISTORY
The
diff --git a/usr.sbin/nfsd/nfsd.c b/usr.sbin/nfsd/nfsd.c
index 2d923a4..959f0fb 100644
--- a/usr.sbin/nfsd/nfsd.c
+++ b/usr.sbin/nfsd/nfsd.c
@@ -58,9 +58,6 @@ static const char rcsid[] =
#include <netdb.h>
#include <arpa/inet.h>
-#ifdef ISO
-#include <netiso/iso.h>
-#endif
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
@@ -76,6 +73,7 @@ static const char rcsid[] =
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
+#include <netdb.h>
/* Global defs */
#ifdef DEBUG
@@ -103,15 +101,23 @@ struct timeval ktv;
NFSKERBKEYSCHED_T kerb_keysched;
#endif
-void nonfs __P((int));
-void reapchild __P((int));
-void setbindhost __P((struct sockaddr_in *ia, const char *bindhost));
+#define MAXNFSDCNT 20
+#define DEFNFSDCNT 4
+pid_t children[MAXNFSDCNT]; /* PIDs of children */
+int nfsdcnt; /* number of children */
+
+void cleanup(int);
+void killchildren(void);
+void nonfs (int);
+void reapchild (int);
+int setbindhost (struct addrinfo **ia, const char *bindhost, struct addrinfo hints);
#ifdef OLD_SETPROCTITLE
#ifdef __FreeBSD__
-void setproctitle __P((char *));
+void setproctitle (char *);
#endif
#endif
-void usage __P((void));
+void unregistration (void);
+void usage (void);
/*
* Nfs server daemon mostly just a user context for nfssvc()
@@ -119,7 +125,7 @@ void usage __P((void));
* 1 - do file descriptor and signal cleanup
* 2 - fork the nfsd(s)
* 3 - create server socket(s)
- * 4 - register socket with portmap
+ * 4 - register socket with rpcbind
*
* For connectionless protocols, just pass the socket into the kernel via.
* nfssvc().
@@ -127,7 +133,8 @@ void usage __P((void));
* socket from accept, pass the msgsock into the kernel via. nfssvc().
* The arguments are:
* -c - support iso cltp clients
- * -r - reregister with portmapper
+ * -r - reregister with rpcbind
+ * -d - unregister with rpcbind
* -t - support tcp nfs clients
* -u - support udp nfs clients
* followed by "n" which is the number of nfsds' to fork off
@@ -138,20 +145,20 @@ main(argc, argv, envp)
char *argv[], *envp[];
{
struct nfsd_args nfsdargs;
- struct sockaddr_in inetaddr, inetpeer;
-#ifdef ISO
- struct sockaddr_iso isoaddr, isopeer;
- char *cp;
-#endif
+ struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
+ struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
+ struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
+ struct sockaddr_in inetpeer;
+ struct sockaddr_in6 inet6peer;
fd_set ready, sockbits;
+ fd_set v4bits, v6bits;
int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
- int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
- int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag;
- int bindhostc = 0, bindanyflag;
+ int nfssvc_flag, on = 1, unregister, reregister, sock;
+ int tcp6sock, ip6flag, tcpflag, tcpsock;
+ int udpflag, ecode, s;
+ int bindhostc = 0, bindanyflag, rpcbreg, rpcbregcnt;
char **bindhost = NULL;
-#ifdef notyet
- int tp4sock, tpipsock;
-#endif
+ pid_t pid;
#ifdef NFSKERB
struct group *grp;
struct passwd *pwd;
@@ -184,18 +191,11 @@ main(argc, argv, envp)
LastArg = envp[-1] + strlen(envp[-1]);
#endif
-#define MAXNFSDCNT 20
-#define DEFNFSDCNT 4
nfsdcnt = DEFNFSDCNT;
- cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
- bindanyflag = tpipflag = udpflag = 0;
-#ifdef ISO
-#define GETOPT "ach:n:rtu"
-#define USAGE "[-acrtu] [-n num_servers] [-h bindip]"
-#else
-#define GETOPT "ah:n:rtu"
-#define USAGE "[-artu] [-n num_servers] [-h bindip]"
-#endif
+ cltpflag = unregister = reregister = tcpflag = 0;
+ bindanyflag = udpflag = ip6flag = 0;
+#define GETOPT "ah:n:rdtu"
+#define USAGE "[-ardtu] [-n num_servers] [-h bindip]"
while ((ch = getopt(argc, argv, GETOPT)) != -1)
switch (ch) {
case 'a':
@@ -221,25 +221,15 @@ main(argc, argv, envp)
case 'r':
reregister = 1;
break;
+ case 'd':
+ unregister = 1;
+ break;
case 't':
tcpflag = 1;
break;
case 'u':
udpflag = 1;
break;
-#ifdef ISO
- case 'c':
- cltpflag = 1;
- break;
-#ifdef notyet
- case 'i':
- tp4cnt = 1;
- break;
- case 'p':
- tpipcnt = 1;
- break;
-#endif /* notyet */
-#endif /* ISO */
default:
case '?':
usage();
@@ -263,6 +253,13 @@ main(argc, argv, envp)
nfsdcnt = DEFNFSDCNT;
}
}
+ ip6flag = 1;
+ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0 && (errno == EPROTONOSUPPORT ||
+ errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
+ ip6flag = 0;
+ else
+ close(s);
if (bindhostc == 0 || bindanyflag) {
bindhostc++;
@@ -278,33 +275,126 @@ main(argc, argv, envp)
daemon(0, 0);
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
- (void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGSYS, nonfs);
+ (void)signal(SIGUSR1, cleanup);
+ /*
+ * nfsd sits in the kernel most of the time. It needs
+ * to ignore SIGTERM/SIGQUIT in order to stay alive as long
+ * as possible during a shutdown, otherwise loopback
+ * mounts will not be able to unmount.
+ */
(void)signal(SIGTERM, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
}
(void)signal(SIGCHLD, reapchild);
-
+ if (unregister) {
+ unregistration();
+ exit (0);
+ }
if (reregister) {
- if (udpflag &&
- (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)))
- err(1, "can't register with portmap for UDP");
- if (tcpflag &&
- (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)))
- err(1, "can't register with portmap for TCP");
- exit(0);
+ if (udpflag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp = getnetconfigent("udp");
+ if (nconf_udp == NULL)
+ err(1, "getnetconfigent udp failed");
+ nb_udp.buf = ai_udp->ai_addr;
+ nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
+ err(1, "rpcb_set udp failed");
+ freeaddrinfo(ai_udp);
+ }
+ if (udpflag && ip6flag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp6 = getnetconfigent("udp6");
+ if (nconf_udp6 == NULL)
+ err(1, "getnetconfigent udp6 failed");
+ nb_udp6.buf = ai_udp6->ai_addr;
+ nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
+ err(1, "rpcb_set udp6 failed");
+ freeaddrinfo(ai_udp6);
+ }
+ if (tcpflag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp = getnetconfigent("tcp");
+ if (nconf_tcp == NULL)
+ err(1, "getnetconfigent tcp failed");
+ nb_tcp.buf = ai_tcp->ai_addr;
+ nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
+ err(1, "rpcb_set tcp failed");
+ freeaddrinfo(ai_tcp);
+ }
+ if (tcpflag && ip6flag) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp6 = getnetconfigent("tcp6");
+ if (nconf_tcp6 == NULL)
+ err(1, "getnetconfigent tcp6 failed");
+ nb_tcp6.buf = ai_tcp6->ai_addr;
+ nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
+ err(1, "rpcb_set tcp6 failed");
+ freeaddrinfo(ai_tcp6);
+ }
+ exit (0);
}
+
openlog("nfsd:", LOG_PID, LOG_DAEMON);
for (i = 0; i < nfsdcnt; i++) {
- switch (fork()) {
+ switch ((pid = fork())) {
case -1:
syslog(LOG_ERR, "fork: %m");
+ killchildren();
exit (1);
case 0:
break;
default:
+ children[i] = pid;
continue;
}
@@ -399,182 +489,295 @@ main(argc, argv, envp)
exit(0);
}
- /* If we are serving udp, set up the socket. */
- for (i = 0; udpflag && i < bindhostc; i++) {
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "can't create udp socket");
- exit(1);
- }
- setbindhost(&inetaddr, bindhost[i]);
- if (bind(sock,
- (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
- syslog(LOG_ERR, "can't bind udp addr %s: %m", bindhost[i]);
- exit(1);
- }
- if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register with udp portmap");
- exit(1);
+ if (atexit(killchildren) == -1) {
+ syslog(LOG_ERR, "atexit: %s", strerror(errno));
+ exit(1);
+ }
+ FD_ZERO(&v4bits);
+ FD_ZERO(&v6bits);
+
+ rpcbregcnt = 0;
+ /* Set up the socket for udp and rpcb register it. */
+ if (udpflag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((sock = socket(ai_udp->ai_family,
+ ai_udp->ai_socktype,
+ ai_udp->ai_protocol)) < 0) {
+ syslog(LOG_ERR,
+ "can't create udp socket");
+ exit(1);
+ }
+ if (bind(sock, ai_udp->ai_addr,
+ ai_udp->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind udp addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ freeaddrinfo(ai_udp);
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR, "can't Add UDP socket");
+ exit(1);
+ }
+ (void)close(sock);
+ }
}
- nfsdargs.sock = sock;
- nfsdargs.name = NULL;
- nfsdargs.namelen = 0;
- if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
- syslog(LOG_ERR, "can't Add UDP socket");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp = getnetconfigent("udp");
+ if (nconf_udp == NULL)
+ err(1, "getnetconfigent udp failed");
+ nb_udp.buf = ai_udp->ai_addr;
+ nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
+ err(1, "rpcb_set udp failed");
+ freeaddrinfo(ai_udp);
}
- (void)close(sock);
}
-#ifdef ISO
- /* If we are serving cltp, set up the socket. */
- if (cltpflag) {
- if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "can't create cltp socket");
- exit(1);
- }
- memset(&isoaddr, 0, sizeof(isoaddr));
- isoaddr.siso_family = AF_ISO;
- isoaddr.siso_tlen = 2;
- cp = TSEL(&isoaddr);
- *cp++ = (NFS_PORT >> 8);
- *cp = (NFS_PORT & 0xff);
- isoaddr.siso_len = sizeof(isoaddr);
- if (bind(sock,
- (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
- syslog(LOG_ERR, "can't bind cltp addr");
- exit(1);
- }
-#ifdef notyet
- /*
- * XXX
- * Someday this should probably use "rpcbind", the son of
- * portmap.
- */
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register with udp portmap");
- exit(1);
+ /* Set up the socket for udp6 and rpcb register it. */
+ if (udpflag && ip6flag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((sock = socket(ai_udp6->ai_family,
+ ai_udp6->ai_socktype,
+ ai_udp6->ai_protocol)) < 0) {
+ syslog(LOG_ERR,
+ "can't create udp6 socket");
+ exit(1);
+ }
+ if (setsockopt(sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY,
+ &on, sizeof on) < 0) {
+ syslog(LOG_ERR,
+ "can't set v6-only binding for "
+ "udp6 socket: %m");
+ exit(1);
+ }
+ if (bind(sock, ai_udp6->ai_addr,
+ ai_udp6->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind udp6 addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ freeaddrinfo(ai_udp6);
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR,
+ "can't add UDP6 socket");
+ exit(1);
+ }
+ (void)close(sock);
+ }
}
-#endif /* notyet */
- nfsdargs.sock = sock;
- nfsdargs.name = NULL;
- nfsdargs.namelen = 0;
- if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
- syslog(LOG_ERR, "can't add UDP socket");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo udp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_udp6 = getnetconfigent("udp6");
+ if (nconf_udp6 == NULL)
+ err(1, "getnetconfigent udp6 failed");
+ nb_udp6.buf = ai_udp6->ai_addr;
+ nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
+ err(1, "rpcb_set udp6 failed");
+ freeaddrinfo(ai_udp6);
}
- close(sock);
}
-#endif /* ISO */
-
- /* Now set up the master server socket waiting for tcp connections. */
- on = 1;
- FD_ZERO(&sockbits);
- connect_type_cnt = 0;
- for (i = 0; tcpflag && i < bindhostc; i++) {
- if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- syslog(LOG_ERR, "can't create tcp socket");
- exit(1);
- }
- if (setsockopt(tcpsock,
- SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
- setbindhost(&inetaddr, bindhost[i]);
- if (bind(tcpsock,
- (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
- syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]);
- exit(1);
- }
- if (listen(tcpsock, 5) < 0) {
- syslog(LOG_ERR, "listen failed");
- exit(1);
+
+ /* Set up the socket for tcp and rpcb register it. */
+ if (tcpflag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((tcpsock = socket(AF_INET, SOCK_STREAM,
+ 0)) < 0) {
+ syslog(LOG_ERR,
+ "can't create tpc socket");
+ exit(1);
+ }
+ if (setsockopt(tcpsock, SOL_SOCKET,
+ SO_REUSEADDR,
+ (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_REUSEADDR: %m");
+ if (bind(tcpsock, ai_tcp->ai_addr,
+ ai_tcp->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind tcp addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ if (listen(tcpsock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ freeaddrinfo(ai_tcp);
+ FD_SET(tcpsock, &sockbits);
+ FD_SET(tcpsock, &v4bits);
+ maxsock = tcpsock;
+ connect_type_cnt++;
+ }
}
- if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) ||
- !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register tcp with portmap");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints,
+ &ai_tcp);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp = getnetconfigent("tcp");
+ if (nconf_tcp == NULL)
+ err(1, "getnetconfigent tcp failed");
+ nb_tcp.buf = ai_tcp->ai_addr;
+ nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
+ &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
+ nconf_tcp, &nb_tcp)))
+ err(1, "rpcb_set tcp failed");
+ freeaddrinfo(ai_tcp);
}
- FD_SET(tcpsock, &sockbits);
- maxsock = tcpsock;
- connect_type_cnt++;
}
-#ifdef notyet
- /* Now set up the master server socket waiting for tp4 connections. */
- if (tp4flag) {
- if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
- syslog(LOG_ERR, "can't create tp4 socket");
- exit(1);
- }
- if (setsockopt(tp4sock,
- SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
- memset(&isoaddr, 0, sizeof(isoaddr));
- isoaddr.siso_family = AF_ISO;
- isoaddr.siso_tlen = 2;
- cp = TSEL(&isoaddr);
- *cp++ = (NFS_PORT >> 8);
- *cp = (NFS_PORT & 0xff);
- isoaddr.siso_len = sizeof(isoaddr);
- if (bind(tp4sock,
- (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
- syslog(LOG_ERR, "can't bind tp4 addr");
- exit(1);
- }
- if (listen(tp4sock, 5) < 0) {
- syslog(LOG_ERR, "listen failed");
- exit(1);
+ /* Set up the socket for tcp6 and rpcb register it. */
+ if (tcpflag && ip6flag) {
+ rpcbreg = 0;
+ for (i = 0; i < bindhostc; i++) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
+ rpcbreg = 1;
+ rpcbregcnt++;
+ if ((tcp6sock = socket(ai_tcp6->ai_family,
+ ai_tcp6->ai_socktype,
+ ai_tcp6->ai_protocol)) < 0) {
+ syslog(LOG_ERR,
+ "can't create tcp6 socket");
+ exit(1);
+ }
+ if (setsockopt(tcp6sock, SOL_SOCKET,
+ SO_REUSEADDR,
+ (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_REUSEADDR: %m");
+ if (setsockopt(tcp6sock, IPPROTO_IPV6,
+ IPV6_BINDV6ONLY, &on, sizeof on) < 0) {
+ syslog(LOG_ERR,
+ "can't set v6-only binding for tcp6 "
+ "socket: %m");
+ exit(1);
+ }
+ if (bind(tcp6sock, ai_tcp6->ai_addr,
+ ai_tcp6->ai_addrlen) < 0) {
+ syslog(LOG_ERR,
+ "can't bind tcp6 addr %s: %m",
+ bindhost[i]);
+ exit(1);
+ }
+ if (listen(tcp6sock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ freeaddrinfo(ai_tcp6);
+ FD_SET(tcp6sock, &sockbits);
+ FD_SET(tcp6sock, &v6bits);
+ if (maxsock < tcp6sock)
+ maxsock = tcp6sock;
+ connect_type_cnt++;
+ }
}
- /*
- * XXX
- * Someday this should probably use "rpcbind", the son of
- * portmap.
- */
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register tcp with portmap");
- exit(1);
+ if (rpcbreg == 1) {
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo tcp6: %s",
+ gai_strerror(ecode));
+ exit(1);
+ }
+ nconf_tcp6 = getnetconfigent("tcp6");
+ if (nconf_tcp6 == NULL)
+ err(1, "getnetconfigent tcp6 failed");
+ nb_tcp6.buf = ai_tcp6->ai_addr;
+ nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
+ if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
+ (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
+ err(1, "rpcb_set tcp6 failed");
+ freeaddrinfo(ai_tcp6);
}
- FD_SET(tp4sock, &sockbits);
- maxsock = tp4sock;
- connect_type_cnt++;
}
- /* Now set up the master server socket waiting for tpip connections. */
- for (i = 0; tpipflag && i < bindhostc; i++) {
- if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
- syslog(LOG_ERR, "can't create tpip socket");
- exit(1);
- }
- if (setsockopt(tpipsock,
- SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
- setbindhost(&inetaddr, bindhost[i]);
- if (bind(tpipsock,
- (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
- syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]);
- exit(1);
- }
- if (listen(tpipsock, 5) < 0) {
- syslog(LOG_ERR, "listen failed");
- exit(1);
- }
- /*
- * XXX
- * Someday this should probably use "rpcbind", the son of
- * portmap.
- */
- if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
- syslog(LOG_ERR, "can't register tcp with portmap");
- exit(1);
- }
- FD_SET(tpipsock, &sockbits);
- maxsock = tpipsock;
- connect_type_cnt++;
+ if (rpcbregcnt == 0) {
+ syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
+ exit(1);
}
-#endif /* notyet */
- if (connect_type_cnt == 0)
- exit(0);
+ if ((tcpflag) && (connect_type_cnt == 0)) {
+ syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
+ exit(1);
+ }
setproctitle("master");
@@ -591,82 +794,94 @@ main(argc, argv, envp)
exit(1);
}
}
- if (tcpflag && FD_ISSET(tcpsock, &ready)) {
- len = sizeof(inetpeer);
- if ((msgsock = accept(tcpsock,
- (struct sockaddr *)&inetpeer, &len)) < 0) {
- syslog(LOG_ERR, "accept failed: %m");
- exit(1);
- }
- memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
- if (setsockopt(msgsock, SOL_SOCKET,
- SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR,
- "setsockopt SO_KEEPALIVE: %m");
- nfsdargs.sock = msgsock;
- nfsdargs.name = (caddr_t)&inetpeer;
- nfsdargs.namelen = sizeof(inetpeer);
- nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
- (void)close(msgsock);
- }
-#ifdef notyet
- if (tp4flag && FD_ISSET(tp4sock, &ready)) {
- len = sizeof(isopeer);
- if ((msgsock = accept(tp4sock,
- (struct sockaddr *)&isopeer, &len)) < 0) {
- syslog(LOG_ERR, "accept failed: %m");
- exit(1);
- }
- if (setsockopt(msgsock, SOL_SOCKET,
- SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR,
- "setsockopt SO_KEEPALIVE: %m");
- nfsdargs.sock = msgsock;
- nfsdargs.name = (caddr_t)&isopeer;
- nfsdargs.namelen = len;
- nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
- (void)close(msgsock);
- }
- if (tpipflag && FD_ISSET(tpipsock, &ready)) {
- len = sizeof(inetpeer);
- if ((msgsock = accept(tpipsock,
- (struct sockaddr *)&inetpeer, &len)) < 0) {
- syslog(LOG_ERR, "accept failed: %m");
- exit(1);
+ for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
+ if (FD_ISSET(tcpsock, &ready)) {
+ if (FD_ISSET(tcpsock, &v4bits)) {
+ len = sizeof(inetpeer);
+ if ((msgsock = accept(tcpsock,
+ (struct sockaddr *)&inetpeer, &len)) < 0) {
+ syslog(LOG_ERR, "accept failed: %m");
+ exit(1);
+ }
+ memset(inetpeer.sin_zero, 0,
+ sizeof(inetpeer.sin_zero));
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inetpeer;
+ nfsdargs.namelen = sizeof(inetpeer);
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ } else if (FD_ISSET(tcpsock, &v6bits)) {
+ len = sizeof(inet6peer);
+ if ((msgsock = accept(tcpsock,
+ (struct sockaddr *)&inet6peer,
+ &len)) < 0) {
+ syslog(LOG_ERR,
+ "accept failed: %m");
+ exit(1);
+ }
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on,
+ sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt "
+ "SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inet6peer;
+ nfsdargs.namelen = sizeof(inet6peer);
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
}
- if (setsockopt(msgsock, SOL_SOCKET,
- SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
- syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
- nfsdargs.sock = msgsock;
- nfsdargs.name = (caddr_t)&inetpeer;
- nfsdargs.namelen = len;
- nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
- (void)close(msgsock);
}
-#endif /* notyet */
}
}
-void
-setbindhost(struct sockaddr_in *ia, const char *bindhost)
+int
+setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
{
- ia->sin_family = AF_INET;
- ia->sin_port = htons(NFS_PORT);
- ia->sin_len = sizeof(*ia);
- if (bindhost == NULL || strcmp(bindhost,"*") == 0) {
- ia->sin_addr.s_addr = INADDR_ANY;
- } else {
- if (inet_aton(bindhost, &ia->sin_addr) == 0) {
- struct hostent *he;
-
- he = gethostbyname2(bindhost, ia->sin_family);
- if (he == NULL) {
- syslog(LOG_ERR, "gethostbyname of %s failed", bindhost);
- exit(1);
+ int ecode;
+ u_int32_t host_addr[4]; /* IPv4 or IPv6 */
+ const char *hostptr;
+
+ if (bindhost == NULL || strcmp("*", bindhost) == 0)
+ hostptr = NULL;
+ else
+ hostptr = bindhost;
+
+ if (hostptr != NULL) {
+ switch (hints.ai_family) {
+ case AF_INET:
+ if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
+ hints.ai_flags = AI_NUMERICHOST;
+ } else {
+ if (inet_pton(AF_INET6, hostptr,
+ host_addr) == 1)
+ return (1);
+ }
+ break;
+ case AF_INET6:
+ if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
+ hints.ai_flags = AI_NUMERICHOST;
+ } else {
+ if (inet_pton(AF_INET, hostptr,
+ host_addr) == 1)
+ return (1);
}
- bcopy(he->h_addr, &ia->sin_addr, he->h_length);
+ break;
+ default:
}
}
+
+ ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
+ if (ecode != 0) {
+ syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
+ gai_strerror(ecode));
+ return (1);
+ }
+ return (0);
}
void
@@ -691,6 +906,48 @@ reapchild(signo)
while (wait3(NULL, WNOHANG, NULL) > 0);
}
+void
+unregistration()
+{
+ if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) ||
+ (!rpcb_unset(RPCPROG_NFS, 3, NULL)))
+ syslog(LOG_ERR, "rpcb_unset failed");
+}
+
+void
+killchildren()
+{
+ int i;
+ sigset_t sigs;
+
+ sigemptyset(&sigs);
+ /*
+ * Block SIGCHLD to avoid killing a reaped process (although it is
+ * unlikely, the pid might have been reused).
+ */
+ sigaddset(&sigs, SIGCHLD);
+ if (sigprocmask(SIG_BLOCK, &sigs, NULL) == -1) {
+ syslog(LOG_ERR, "sigprocmask: %s",
+ strerror(errno));
+ return;
+ }
+ for (i = 0; i < nfsdcnt; i++) {
+ if (children[i] > 0)
+ kill(children[i], SIGKILL);
+ }
+ if (sigprocmask(SIG_UNBLOCK, &sigs, NULL) == -1) {
+ syslog(LOG_ERR, "sigprocmask: %s", strerror(errno));
+ }
+ unregistration();
+}
+
+void
+cleanup(signo)
+{
+ killchildren();
+ exit (0);
+}
+
#ifdef OLD_SETPROCTITLE
#ifdef __FreeBSD__
void
diff --git a/usr.sbin/portmap/Makefile b/usr.sbin/portmap/Makefile
deleted file mode 100644
index b87cf59..0000000
--- a/usr.sbin/portmap/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
-# $FreeBSD$
-
-PROG= portmap
-MAN8= portmap.8
-SRCS= portmap.c from_local.c pmap_check.c
-SUBDIR= pmap_set pmap_dump
-
-CFLAGS+=-DCHECK_PORT -DHOSTS_ACCESS
-DPADD= ${LIBWRAP}
-LDADD= -lwrap
-
-.include <bsd.prog.mk>
diff --git a/usr.sbin/portmap/from_local.c b/usr.sbin/portmap/from_local.c
deleted file mode 100644
index 9886f12..0000000
--- a/usr.sbin/portmap/from_local.c
+++ /dev/null
@@ -1,233 +0,0 @@
- /*
- * Check if an address belongs to the local system. Adapted from:
- *
- * @(#)pmap_svc.c 1.32 91/03/11 Copyright 1984,1990 Sun Microsystems, Inc.
- * @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC.
- */
-
-/*
- * 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 or with the express written consent of
- * Sun Microsystems, Inc.
- *
- * 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
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#) from_local.c 1.2 93/11/16 21:50:02";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-#ifdef TEST
-#undef perror
-#endif
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-#include <sys/time.h>
-
-#include <netdb.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/route.h>
-#include <netinet/in.h>
-
-#include "pmap_check.h"
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#define ROUNDUP(x) ((x) ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long))
-
-/* How many interfaces could there be on a computer? */
-
-#define ESTIMATED_LOCAL 20
-static int num_local = -1;
-static struct in_addr *addrs;
-
-static void
-rtiparse(struct ifa_msghdr *ifam, struct rt_addrinfo *ai)
-{
- char *wp;
- int rtax;
-
- wp = (char *)(ifam + 1);
-
- ai->rti_addrs = ifam->ifam_addrs;
- for (rtax = 0; rtax < sizeof ai->rti_info / sizeof *ai->rti_info; rtax++)
- if (ifam->ifam_addrs & (1 << rtax)) {
- ai->rti_info[rtax] = (struct sockaddr *)wp;
- wp += ROUNDUP(ai->rti_info[rtax]->sa_len);
- } else
- ai->rti_info[rtax] = NULL;
-}
-
-/* find_local - find all IP addresses for this host */
-
-static int
-find_local()
-{
- int mib[6], n, s, alloced;
- size_t needed;
- char *buf, *end, *ptr;
- struct if_msghdr *ifm;
- struct ifa_msghdr *ifam;
- struct rt_addrinfo ai;
- struct ifreq ifr;
- struct sockaddr_dl *dl;
-
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE;
- mib[4] = NET_RT_IFLIST;
- mib[2] = mib[3] = mib[5] = 0;
-
- if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket");
- return (0);
- }
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
- close(s);
- perror("sysctl(NET_RT_IFLIST)");
- return 0;
- }
- if ((buf = (char *)malloc(needed)) == NULL) {
- close(s);
- perror("malloc");
- return 0;
- }
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
- close(s);
- free(buf);
- perror("sysctl(NET_RT_IFLIST)(after malloc)");
- return 0;
- }
-
- if (addrs) {
- free(addrs);
- addrs = NULL;
- }
- num_local = 0;
- alloced = 0;
- end = buf + needed;
-
- for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
- ifm = (struct if_msghdr *)ptr;
- dl = (struct sockaddr_dl *)(ifm + 1);
-
- if (ifm->ifm_index != dl->sdl_index || dl->sdl_nlen == 0)
- /* Skip over remaining ifa_msghdrs */
- continue;
-
- n = dl->sdl_nlen > sizeof ifr.ifr_name ?
- sizeof ifr.ifr_name : dl->sdl_nlen;
- strncpy(ifr.ifr_name, dl->sdl_data, n);
- if (n < sizeof ifr.ifr_name)
- ifr.ifr_name[n] = '\0';
-
- /* we only want the first address from each interface */
- if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
- fprintf(stderr, "%.*s: SIOCGIFFLAGS: %s\n", n, ifr.ifr_name,
- strerror(errno));
- else if (ifr.ifr_flags & IFF_UP) { /* active interface */
- ifam = (struct ifa_msghdr *)(ptr + ifm->ifm_msglen);
- while ((char *)ifam < end && ifam->ifam_type == RTM_NEWADDR) {
- rtiparse(ifam, &ai);
-
- if (ai.rti_info[RTAX_IFA] != NULL &&
- ai.rti_info[RTAX_IFA]->sa_family == AF_INET) {
- if (alloced < num_local + 1) {
- alloced += ESTIMATED_LOCAL;
- addrs = (struct in_addr *)realloc(addrs, alloced * sizeof addrs[0]);
- if (addrs == NULL) {
- perror("malloc/realloc");
- num_local = 0;
- break;
- }
- }
- addrs[num_local++] = ((struct sockaddr_in *)
- ai.rti_info[RTAX_IFA])->sin_addr;
-
- }
- ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
- }
- }
- }
- free(buf);
- close(s);
-
- return num_local;
-}
-
-/* from_local - determine whether request comes from the local system */
-
-int
-from_local(addr)
- struct sockaddr_in *addr;
-{
- int i;
-
- if (num_local == -1 && find_local() == 0)
- syslog(LOG_ERR, "cannot find any active local network interfaces");
-
- for (i = 0; i < num_local; i++) {
- if (memcmp((char *) &(addr->sin_addr), (char *) &(addrs[i]),
- sizeof(struct in_addr)) == 0)
- return (TRUE);
- }
- return (FALSE);
-}
-
-#ifdef TEST
-
-int
-main(argc, argv)
- int argc;
- char **argv;
-{
- char *inet_ntoa();
- int i;
-
- find_local();
- for (i = 0; i < num_local; i++)
- printf("%s\n", inet_ntoa(addrs[i]));
-
- return 0;
-}
-
-#endif
diff --git a/usr.sbin/portmap/pmap_check.c b/usr.sbin/portmap/pmap_check.c
deleted file mode 100644
index 7ad25c9..0000000
--- a/usr.sbin/portmap/pmap_check.c
+++ /dev/null
@@ -1,263 +0,0 @@
- /*
- * pmap_check - additional portmap security.
- *
- * Always reject non-local requests to update the portmapper tables.
- *
- * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the
- * requests would appear to come from the local system, and nfs export
- * restrictions could be bypassed.
- *
- * Refuse to forward requests to the nfsd process.
- *
- * Refuse to forward requests to NIS (YP) daemons; The only exception is the
- * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial
- * contact with the NIS server.
- *
- * Always allocate an unprivileged port when forwarding a request.
- *
- * If compiled with -DCHECK_PORT, require that requests to register or
- * unregister a privileged port come from a privileged port. This makes it
- * more difficult to replace a critical service by a trojan.
- *
- * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
- * authorized by the /etc/hosts.{allow,deny} files. The local system is
- * always treated as an authorized host. The access control tables are never
- * consulted for requests from the local system, and are always consulted
- * for requests from other hosts. Access control is based on IP addresses
- * only; attempts to map an address to a host name might cause the
- * portmapper to hang.
- *
- * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
- * Computing Science, Eindhoven University of Technology, The Netherlands.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#) pmap_check.c 1.6 93/11/21 20:58:59";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <syslog.h>
-#include <netdb.h>
-#include <sys/signal.h>
-
-#include "pmap_check.h"
-
-/* Explicit #defines in case the include files are not available. */
-
-#define NFSPROG ((u_long) 100003)
-#define MOUNTPROG ((u_long) 100005)
-#define YPXPROG ((u_long) 100069)
-#define YPPROG ((u_long) 100004)
-#define YPPROC_DOMAIN_NONACK ((u_long) 2)
-#define MOUNTPROC_MNT ((u_long) 1)
-
-static void logit __P((int, struct sockaddr_in *, u_long, u_long, const char *));
-static void toggle_verboselog __P((int));
-
-int verboselog = 0;
-int allow_severity = LOG_INFO;
-int deny_severity = LOG_WARNING;
-
-/* A handful of macros for "readability". */
-
-#define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "")
-
-#define legal_port(a,p) \
- (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
-
-#define log_bad_port(addr, proc, prog) \
- logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
-
-#define log_bad_host(addr, proc, prog) \
- logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
-
-#define log_bad_owner(addr, proc, prog) \
- logit(deny_severity, addr, proc, prog, ": request from non-local host")
-
-#define log_no_forward(addr, proc, prog) \
- logit(deny_severity, addr, proc, prog, ": request not forwarded")
-
-#define log_client(addr, proc, prog) \
- logit(allow_severity, addr, proc, prog, "")
-
-/* check_startup - additional startup code */
-
-void
-check_startup()
-{
-
- /*
- * Give up root privileges so that we can never allocate a privileged
- * port when forwarding an rpc request.
- */
- if (setuid(1) == -1) {
- syslog(LOG_ERR, "setuid(1) failed: %m");
- exit(1);
- }
- (void) signal(SIGINT, toggle_verboselog);
-}
-
-/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
-
-int
-check_default(addr, proc, prog)
- struct sockaddr_in *addr;
- u_long proc, prog;
-{
-#ifdef HOSTS_ACCESS
- if (!(from_local(addr) || good_client(addr))) {
- log_bad_host(addr, proc, prog);
- return (FALSE);
- }
-#endif
- if (verboselog)
- log_client(addr, proc, prog);
- return (TRUE);
-}
-
-/* check_privileged_port - additional checks for privileged-port updates */
-
-int
-check_privileged_port(addr, proc, prog, port)
- struct sockaddr_in *addr;
- u_long proc, prog, port;
-{
-#ifdef CHECK_PORT
- if (!legal_port(addr, port)) {
- log_bad_port(addr, proc, prog);
- return (FALSE);
- }
-#endif
- return (TRUE);
-}
-
-/* check_setunset - additional checks for update requests */
-
-int
-check_setunset(addr, proc, prog, port)
- struct sockaddr_in *addr;
- u_long proc, prog, port;
-{
- if (!from_local(addr)) {
-#ifdef HOSTS_ACCESS
- (void) good_client(addr); /* because of side effects */
-#endif
- log_bad_owner(addr, proc, prog);
- return (FALSE);
- }
- if (port && !check_privileged_port(addr, proc, prog, port))
- return (FALSE);
- if (verboselog)
- log_client(addr, proc, prog);
- return (TRUE);
-}
-
-/* check_callit - additional checks for forwarded requests */
-
-int
-check_callit(addr, proc, prog, aproc)
- struct sockaddr_in *addr;
- u_long proc, prog, aproc;
-{
-#ifdef HOSTS_ACCESS
- if (!(from_local(addr) || good_client(addr))) {
- log_bad_host(addr, proc, prog);
- return (FALSE);
- }
-#endif
- if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
- (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
- (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
- log_no_forward(addr, proc, prog);
- return (FALSE);
- }
- if (verboselog)
- log_client(addr, proc, prog);
- return (TRUE);
-}
-
-/* toggle_verboselog - toggle verbose logging flag */
-
-static void
-toggle_verboselog(sig)
- int sig;
-{
- (void) signal(sig, toggle_verboselog);
- verboselog = !verboselog;
-}
-
-/* logit - report events of interest via the syslog daemon */
-
-static void
-logit(severity, addr, procnum, prognum, text)
- int severity;
- struct sockaddr_in *addr;
- u_long procnum, prognum;
- const char *text;
-{
- const char *procname;
- char procbuf[4 * sizeof(u_long)];
- const char *progname;
- char progbuf[4 * sizeof(u_long)];
- struct rpcent *rpc;
- struct proc_map {
- u_long code;
- const char *proc;
- };
- struct proc_map *procp;
- static struct proc_map procmap[] = {
- {PMAPPROC_CALLIT, "callit"},
- {PMAPPROC_DUMP, "dump"},
- {PMAPPROC_GETPORT, "getport"},
- {PMAPPROC_NULL, "null"},
- {PMAPPROC_SET, "set"},
- {PMAPPROC_UNSET, "unset"},
- {0, 0},
- };
-
- /*
- * Fork off a process or the portmap daemon might hang while
- * getrpcbynumber() or syslog() does its thing.
- */
-
- if (fork() == 0) {
-
- /* Try to map program number to name. */
-
- if (prognum == 0) {
- progname = "";
- } else if ((rpc = getrpcbynumber((int) prognum))) {
- progname = rpc->r_name;
- } else {
- sprintf(progbuf, "%lu", prognum);
- progname = progbuf;
- }
-
- /* Try to map procedure number to name. */
-
- for (procp = procmap; procp->proc && procp->code != procnum; procp++)
- /* void */ ;
- if ((procname = procp->proc) == 0) {
- sprintf(procbuf, "%lu", (u_long) procnum);
- procname = procbuf;
- }
-
- /* Write syslog record. */
-
- syslog(severity, "connect from %s to %s(%s)%s",
- inet_ntoa(addr->sin_addr), procname, progname, text);
- exit(0);
- }
-}
diff --git a/usr.sbin/portmap/pmap_check.h b/usr.sbin/portmap/pmap_check.h
deleted file mode 100644
index dc454a5..0000000
--- a/usr.sbin/portmap/pmap_check.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-
- * Copyright (c) 2000 Brian Somers <brian@Awfulhak.org>
- * All rights reserved.
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- *
- * @(#) pmap_check.h 1.3 93/11/21 16:18:53
- *
- * $FreeBSD$
- */
-
-extern int from_local __P((struct sockaddr_in *));
-extern void check_startup __P((void));
-extern int check_default __P((struct sockaddr_in *, u_long, u_long));
-extern int check_setunset __P((struct sockaddr_in *, u_long, u_long, u_long));
-extern int check_privileged_port __P((struct sockaddr_in *, u_long, u_long,
- u_long));
-extern int check_callit __P((struct sockaddr_in *, u_long, u_long, u_long));
-
-extern int verboselog;
-extern int allow_severity;
-extern int deny_severity;
diff --git a/usr.sbin/portmap/pmap_dump/Makefile b/usr.sbin/portmap/pmap_dump/Makefile
deleted file mode 100644
index 0064f28..0000000
--- a/usr.sbin/portmap/pmap_dump/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
-
-PROG= pmap_dump
-NOMAN= noman
-
-.include "${.CURDIR}/../../Makefile.inc"
-.include <bsd.prog.mk>
diff --git a/usr.sbin/portmap/pmap_dump/pmap_dump.c b/usr.sbin/portmap/pmap_dump/pmap_dump.c
deleted file mode 100644
index 96fb5c2..0000000
--- a/usr.sbin/portmap/pmap_dump/pmap_dump.c
+++ /dev/null
@@ -1,69 +0,0 @@
- /*
- * pmap_dump - dump portmapper table in format readable by pmap_set
- *
- * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
- * Computing Science, Eindhoven University of Technology, The Netherlands.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#) pmap_dump.c 1.1 92/06/11 22:53:15";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-#ifdef SYSV40
-#include <netinet/in.h>
-#include <rpc/rpcent.h>
-#else
-#include <netdb.h>
-#endif
-#include <rpc/rpc.h>
-#include <rpc/pmap_clnt.h>
-#include <rpc/pmap_prot.h>
-
-static const char *protoname __P((u_long));
-
-int
-main(argc, argv)
- int argc;
- char **argv;
-{
- struct sockaddr_in addr;
- register struct pmaplist *list;
- register struct rpcent *rpc;
-
- get_myaddress(&addr);
-
- for (list = pmap_getmaps(&addr); list; list = list->pml_next) {
- rpc = getrpcbynumber((int) list->pml_map.pm_prog);
- printf("%10lu %4lu %5s %6lu %s\n",
- list->pml_map.pm_prog,
- list->pml_map.pm_vers,
- protoname(list->pml_map.pm_prot),
- list->pml_map.pm_port,
- rpc ? rpc->r_name : "");
- }
-#undef perror
- return (fclose(stdout) ? (perror(argv[0]), 1) : 0);
-}
-
-static const char *
-protoname(proto)
- u_long proto;
-{
- static char buf[BUFSIZ];
-
- switch (proto) {
- case IPPROTO_UDP:
- return ("udp");
- case IPPROTO_TCP:
- return ("tcp");
- default:
- sprintf(buf, "%lu", proto);
- return (buf);
- }
-}
diff --git a/usr.sbin/portmap/pmap_set/Makefile b/usr.sbin/portmap/pmap_set/Makefile
deleted file mode 100644
index 987e320..0000000
--- a/usr.sbin/portmap/pmap_set/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
-
-PROG= pmap_set
-NOMAN= noman
-
-.include "${.CURDIR}/../../Makefile.inc"
-.include <bsd.prog.mk>
diff --git a/usr.sbin/portmap/pmap_set/pmap_set.c b/usr.sbin/portmap/pmap_set/pmap_set.c
deleted file mode 100644
index 35a7fbe..0000000
--- a/usr.sbin/portmap/pmap_set/pmap_set.c
+++ /dev/null
@@ -1,78 +0,0 @@
- /*
- * pmap_set - set portmapper table from data produced by pmap_dump
- *
- * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
- * Computing Science, Eindhoven University of Technology, The Netherlands.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#) pmap_set.c 1.1 92/06/11 22:53:16";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
-
-#include <err.h>
-#include <stdio.h>
-#include <sys/types.h>
-#ifdef SYSV40
-#include <netinet/in.h>
-#endif
-#include <rpc/rpc.h>
-#include <rpc/pmap_clnt.h>
-
-static int parse_line __P((char *, u_long *, u_long *, int *, unsigned *));
-
-int
-main(argc, argv)
- int argc;
- char **argv;
-{
- struct sockaddr_in addr;
- char buf[BUFSIZ];
- u_long prog;
- u_long vers;
- int prot;
- unsigned port;
-
- get_myaddress(&addr);
-
- while (fgets(buf, sizeof(buf), stdin)) {
- if (parse_line(buf, &prog, &vers, &prot, &port) == 0) {
- warnx("malformed line: %s", buf);
- return (1);
- }
- if (pmap_set(prog, vers, prot, (unsigned short) port) == 0)
- warnx("not registered: %s", buf);
- }
- return (0);
-}
-
-/* parse_line - convert line to numbers */
-
-static int
-parse_line(buf, prog, vers, prot, port)
- char *buf;
- u_long *prog, *vers;
- int *prot;
- unsigned *port;
-{
- char proto_name[BUFSIZ];
-
- if (sscanf(buf, "%lu %lu %s %u", prog, vers, proto_name, port) != 4) {
- return (0);
- }
- if (strcmp(proto_name, "tcp") == 0) {
- *prot = IPPROTO_TCP;
- return (1);
- }
- if (strcmp(proto_name, "udp") == 0) {
- *prot = IPPROTO_UDP;
- return (1);
- }
- if (sscanf(proto_name, "%d", prot) == 1) {
- return (1);
- }
- return (0);
-}
diff --git a/usr.sbin/portmap/portmap.8 b/usr.sbin/portmap/portmap.8
deleted file mode 100644
index 455ccbd..0000000
--- a/usr.sbin/portmap/portmap.8
+++ /dev/null
@@ -1,122 +0,0 @@
-.\" Copyright (c) 1987 Sun Microsystems
-.\" Copyright (c) 1990, 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" 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 University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
-.\"
-.\" @(#)portmap.8 8.1 (Berkeley) 6/6/93
-.\" $FreeBSD$
-.\"
-.Dd June 6, 1993
-.Dt PORTMAP 8
-.Os BSD 4.3
-.Sh NAME
-.Nm portmap
-.Nd
-.Tn RPC
-program,version
-to
-.Tn DARPA
-port mapper
-.Sh SYNOPSIS
-.Nm
-.Op Fl d
-.Op Fl v
-.Sh DESCRIPTION
-.Nm Portmap
-is a server that converts
-.Tn RPC
-program numbers into
-.Tn DARPA
-protocol port numbers.
-It must be running in order to make
-.Tn RPC
-calls.
-.Pp
-When an
-.Tn RPC
-server is started, it will tell
-.Nm
-what port number it is listening to, and what
-.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 will first contact
-.Nm
-on the server machine to determine
-the port number where
-.Tn RPC
-packets should be sent.
-.Pp
-.Nm Portmap
-must be started before any
-.Tn RPC
-servers are invoked.
-.Pp
-.Nm Portmap
-uses
-.Xr hosts_access 5
-access control by default.
-Access control patterns may only reference IP addresses.
-.Pp
-Normally
-.Nm
-forks and dissociates itself from the terminal
-like any other daemon.
-.Nm Portmap
-then logs errors using
-.Xr syslog 3 .
-.Pp
-The following options are available:
-.Bl -tag -width indent
-.It Fl d
-Prevent
-.Nm
-from running as a daemon,
-and causes errors and debugging information
-to be printed to the standard error output.
-.It Fl v
-Enable verbose logging of access control checks.
-.El
-.Sh SEE ALSO
-.Xr hosts_access 5 ,
-.Xr inetd.conf 5 ,
-.Xr inetd 8 ,
-.Xr rpcinfo 8
-.Sh BUGS
-If
-.Nm
-crashes, all servers must be restarted.
-.Sh HISTORY
-The
-.Nm
-command appeared in
-.Bx 4.3
diff --git a/usr.sbin/portmap/portmap.c b/usr.sbin/portmap/portmap.c
deleted file mode 100644
index 658b53c..0000000
--- a/usr.sbin/portmap/portmap.c
+++ /dev/null
@@ -1,612 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * 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 University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- */
-
-#ifndef lint
-static const char copyright[] =
-"@(#) Copyright (c) 1990, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)portmap.c 8.1 (Berkeley) 6/6/93";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-/*
-@(#)portmap.c 2.3 88/08/11 4.0 RPCSRC
-static char sccsid[] = "@(#)portmap.c 1.32 87/08/06 Copyr 1984 Sun Micro";
-*/
-
-/*
- * portmap.c, Implements the program,version to port number mapping for
- * rpc.
- */
-
-/*
- * 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
- */
-
-#include <err.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-#include <sys/signal.h>
-#include <sys/resource.h>
-
-#include "pmap_check.h"
-
-static void reg_service __P((struct svc_req *, SVCXPRT *));
-static void reap __P((int));
-static void callit __P((struct svc_req *, SVCXPRT *));
-static void usage __P((void));
-
-struct pmaplist *pmaplist;
-int debugging = 0;
-
-int
-main(argc, argv)
- int argc;
- char **argv;
-{
- SVCXPRT *xprt;
- int sock, c;
- struct sockaddr_in addr;
- int len = sizeof(struct sockaddr_in);
- register struct pmaplist *pml;
-
- while ((c = getopt(argc, argv, "dv")) != -1) {
- switch (c) {
-
- case 'd':
- debugging = 1;
- break;
-
- case 'v':
- verboselog = 1;
- break;
-
- default:
- usage();
- }
- }
-
- if (!debugging && daemon(0, 0))
- err(1, "fork");
-
- openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID,
- LOG_DAEMON);
-
- if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
- syslog(LOG_ERR, "cannot create udp socket: %m");
- exit(1);
- }
-
- addr.sin_addr.s_addr = 0;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(PMAPPORT);
- if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
- syslog(LOG_ERR, "cannot bind udp: %m");
- exit(1);
- }
-
- if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
- syslog(LOG_ERR, "couldn't do udp_create");
- exit(1);
- }
- /* make an entry for ourself */
- pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
- pml->pml_next = 0;
- pml->pml_map.pm_prog = PMAPPROG;
- pml->pml_map.pm_vers = PMAPVERS;
- pml->pml_map.pm_prot = IPPROTO_UDP;
- pml->pml_map.pm_port = PMAPPORT;
- pmaplist = pml;
-
- if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
- syslog(LOG_ERR, "cannot create tcp socket: %m");
- exit(1);
- }
- if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
- syslog(LOG_ERR, "cannot bind tcp: %m");
- exit(1);
- }
- if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
- == (SVCXPRT *)NULL) {
- syslog(LOG_ERR, "couldn't do tcp_create");
- exit(1);
- }
- /* make an entry for ourself */
- pml = (struct pmaplist *)malloc((u_int)sizeof(struct pmaplist));
- pml->pml_map.pm_prog = PMAPPROG;
- pml->pml_map.pm_vers = PMAPVERS;
- pml->pml_map.pm_prot = IPPROTO_TCP;
- pml->pml_map.pm_port = PMAPPORT;
- pml->pml_next = pmaplist;
- pmaplist = pml;
-
- (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
-
- /* additional initializations */
- check_startup();
- (void)signal(SIGCHLD, reap);
- svc_run();
- syslog(LOG_ERR, "svc_run returned unexpectedly");
- abort();
-}
-
-static void
-usage()
-{
- fprintf(stderr, "usage: portmap [-dv]\n");
- exit(1);
-}
-
-#ifndef lint
-/* need to override perror calls in rpc library */
-void
-perror(what)
- const char *what;
-{
- syslog(LOG_ERR, "%s: %m", what);
-}
-#endif
-
-static struct pmaplist *
-find_service(prog, vers, prot)
- u_long prog, vers, prot;
-{
- register struct pmaplist *hit = NULL;
- register struct pmaplist *pml;
-
- for (pml = pmaplist; 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);
-}
-
-/*
- * 1 OK, 0 not
- */
-static void
-reg_service(rqstp, xprt)
- struct svc_req *rqstp;
- SVCXPRT *xprt;
-{
- struct pmap reg;
- struct pmaplist *pml, *prevpml, *fnd;
- int ans, port;
- caddr_t t;
-
- /*
- * Later wrappers change the logging severity on the fly. Reset to
- * defaults before handling the next request.
- */
- allow_severity = LOG_INFO;
- deny_severity = LOG_WARNING;
-
- if (debugging)
- (void) fprintf(stderr, "server: about to do a switch\n");
- switch (rqstp->rq_proc) {
-
- case PMAPPROC_NULL:
- /*
- * Null proc call
- */
- /* remote host authorization check */
- check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
- if (!svc_sendreply(xprt, xdr_void, (caddr_t)0) && debugging) {
- abort();
- }
- break;
-
- case PMAPPROC_SET:
- /*
- * Set a program,version to port mapping
- */
- if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg))
- svcerr_decode(xprt);
- else {
- /* reject non-local requests, protect priv. ports */
- if (!check_setunset(svc_getcaller(xprt),
- rqstp->rq_proc, reg.pm_prog, reg.pm_port)) {
- ans = 0;
- goto done;
- }
- /*
- * 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.pm_prog, reg.pm_vers, reg.pm_prot);
- if (fnd && fnd->pml_map.pm_vers == reg.pm_vers) {
- if (fnd->pml_map.pm_port == reg.pm_port) {
- ans = 1;
- goto done;
- }
- else {
- ans = 0;
- goto done;
- }
- } else {
- /*
- * add to END of list
- */
- pml = (struct pmaplist *)
- malloc((u_int)sizeof(struct pmaplist));
- pml->pml_map = reg;
- pml->pml_next = 0;
- if (pmaplist == 0) {
- pmaplist = pml;
- } else {
- for (fnd= pmaplist; fnd->pml_next != 0;
- fnd = fnd->pml_next);
- fnd->pml_next = pml;
- }
- ans = 1;
- }
- done:
- if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
- debugging) {
- (void) fprintf(stderr, "svc_sendreply\n");
- abort();
- }
- }
- break;
-
- case PMAPPROC_UNSET:
- /*
- * Remove a program,version to port mapping.
- */
- if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg))
- svcerr_decode(xprt);
- else {
- ans = 0;
- /* reject non-local requests */
- if (!check_setunset(svc_getcaller(xprt),
- rqstp->rq_proc, reg.pm_prog, (u_long) 0))
- goto done;
- for (prevpml = NULL, pml = pmaplist; pml != NULL; ) {
- if ((pml->pml_map.pm_prog != reg.pm_prog) ||
- (pml->pml_map.pm_vers != reg.pm_vers)) {
- /* both pml & prevpml move forwards */
- prevpml = pml;
- pml = pml->pml_next;
- continue;
- }
- /* found it; pml moves forward, prevpml stays */
- /* privileged port check */
- if (!check_privileged_port(svc_getcaller(xprt),
- rqstp->rq_proc,
- reg.pm_prog,
- pml->pml_map.pm_port)) {
- ans = 0;
- break;
- }
- ans = 1;
- t = (caddr_t)pml;
- pml = pml->pml_next;
- if (prevpml == NULL)
- pmaplist = pml;
- else
- prevpml->pml_next = pml;
- free(t);
- }
- if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&ans)) &&
- debugging) {
- (void) fprintf(stderr, "svc_sendreply\n");
- abort();
- }
- }
- break;
-
- case PMAPPROC_GETPORT:
- /*
- * Lookup the mapping for a program,version and return its port
- */
- if (!svc_getargs(xprt, xdr_pmap, (caddr_t)&reg))
- svcerr_decode(xprt);
- else {
- /* remote host authorization check */
- if (!check_default(svc_getcaller(xprt),
- rqstp->rq_proc,
- reg.pm_prog)) {
- ans = 0;
- goto done;
- }
- fnd = find_service(reg.pm_prog, reg.pm_vers, reg.pm_prot);
- if (fnd)
- port = fnd->pml_map.pm_port;
- else
- port = 0;
- if ((!svc_sendreply(xprt, xdr_long, (caddr_t)&port)) &&
- debugging) {
- (void) fprintf(stderr, "svc_sendreply\n");
- abort();
- }
- }
- break;
-
- case PMAPPROC_DUMP:
- /*
- * Return the current set of mapped program,version
- */
- if (!svc_getargs(xprt, xdr_void, NULL))
- svcerr_decode(xprt);
- else {
- /* remote host authorization check */
- struct pmaplist *p;
- if (!check_default(svc_getcaller(xprt),
- rqstp->rq_proc, (u_long) 0)) {
- p = 0; /* send empty list */
- } else {
- p = pmaplist;
- }
- if ((!svc_sendreply(xprt, xdr_pmaplist,
- (caddr_t)&p)) && debugging) {
- (void) fprintf(stderr, "svc_sendreply\n");
- abort();
- }
- }
- 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.
- */
- callit(rqstp, xprt);
- break;
-
- default:
- /* remote host authorization check */
- check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
- svcerr_noproc(xprt);
- break;
- }
-}
-
-
-/*
- * Stuff for the rmtcall service
- */
-#define ARGSIZE 9000
-
-struct encap_parms {
- u_int arglen;
- char *args;
-};
-
-static bool_t
-xdr_encap_parms(xdrs, epp)
- XDR *xdrs;
- struct encap_parms *epp;
-{
-
- return (xdr_bytes(xdrs, &(epp->args), &(epp->arglen), ARGSIZE));
-}
-
-struct rmtcallargs {
- u_long rmt_prog;
- u_long rmt_vers;
- u_long rmt_port;
- u_long rmt_proc;
- struct encap_parms rmt_args;
-};
-
-static bool_t
-xdr_rmtcall_args(xdrs, cap)
- XDR *xdrs;
- struct rmtcallargs *cap;
-{
-
- /* does not get a port number */
- if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
- xdr_u_long(xdrs, &(cap->rmt_vers)) &&
- xdr_u_long(xdrs, &(cap->rmt_proc))) {
- return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
- }
- return (FALSE);
-}
-
-static bool_t
-xdr_rmtcall_result(xdrs, cap)
- XDR *xdrs;
- struct rmtcallargs *cap;
-{
- if (xdr_u_long(xdrs, &(cap->rmt_port)))
- return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
- return (FALSE);
-}
-
-/*
- * only worries about the struct encap_parms part of struct rmtcallargs.
- * The arglen must already be set!!
- */
-static bool_t
-xdr_opaque_parms(xdrs, cap)
- XDR *xdrs;
- struct rmtcallargs *cap;
-{
- return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
-}
-
-/*
- * This routine finds and sets the length of incoming opaque paraters
- * and then calls xdr_opaque_parms.
- */
-static bool_t
-xdr_len_opaque_parms(xdrs, cap)
- XDR *xdrs;
- struct rmtcallargs *cap;
-{
- register u_int beginpos, lowpos, highpos, currpos, pos;
-
- beginpos = lowpos = pos = xdr_getpos(xdrs);
- highpos = lowpos + ARGSIZE;
- while ((int)(highpos - lowpos) >= 0) {
- currpos = (lowpos + highpos) / 2;
- if (xdr_setpos(xdrs, currpos)) {
- pos = currpos;
- lowpos = currpos + 1;
- } else {
- highpos = currpos - 1;
- }
- }
- xdr_setpos(xdrs, beginpos);
- cap->rmt_args.arglen = pos - beginpos;
- return (xdr_opaque_parms(xdrs, cap));
-}
-
-/*
- * 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, less the requestor be
- * overrun with complaints at the expense of not hearing a valid reply ...
- *
- * This now forks so that the program & process that it calls can call
- * back to the portmapper.
- */
-static void
-callit(rqstp, xprt)
- struct svc_req *rqstp;
- SVCXPRT *xprt;
-{
- struct rmtcallargs a;
- struct pmaplist *pml;
- u_short port;
- struct sockaddr_in me;
- int pid, so = -1;
- CLIENT *client;
- struct authunix_parms *au = (struct authunix_parms *)rqstp->rq_clntcred;
- struct timeval timeout;
- char buf[ARGSIZE];
-
- timeout.tv_sec = 5;
- timeout.tv_usec = 0;
- a.rmt_args.args = buf;
- if (!svc_getargs(xprt, xdr_rmtcall_args, (caddr_t)&a))
- return;
- /* host and service access control */
- if (!check_callit(svc_getcaller(xprt),
- rqstp->rq_proc, a.rmt_prog, a.rmt_proc))
- return;
- if ((pml = find_service(a.rmt_prog, a.rmt_vers,
- (u_long)IPPROTO_UDP)) == NULL)
- return;
- /*
- * fork a child to do the work. Parent immediately returns.
- * Child exits upon completion.
- */
- if ((pid = fork()) != 0) {
- if (pid < 0)
- syslog(LOG_ERR, "CALLIT (prog %lu): fork: %m",
- a.rmt_prog);
- return;
- }
- port = pml->pml_map.pm_port;
- get_myaddress(&me);
- me.sin_port = htons(port);
- client = clntudp_create(&me, a.rmt_prog, a.rmt_vers, timeout, &so);
- if (client != (CLIENT *)NULL) {
- if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
- client->cl_auth = authunix_create(au->aup_machname,
- au->aup_uid, au->aup_gid, au->aup_len, au->aup_gids);
- }
- a.rmt_port = (u_long)port;
- if (clnt_call(client, a.rmt_proc, xdr_opaque_parms, &a,
- xdr_len_opaque_parms, &a, timeout) == RPC_SUCCESS) {
- svc_sendreply(xprt, xdr_rmtcall_result, (caddr_t)&a);
- }
- AUTH_DESTROY(client->cl_auth);
- clnt_destroy(client);
- }
- (void)close(so);
- exit(0);
-}
-
-static void
-reap(sig)
- int sig;
-{
- int save_errno;
-
- save_errno = errno;
- while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
- errno = save_errno;
-}
diff --git a/usr.sbin/rpc.lockd/Makefile b/usr.sbin/rpc.lockd/Makefile
index 19a6565..ba6b3c7 100644
--- a/usr.sbin/rpc.lockd/Makefile
+++ b/usr.sbin/rpc.lockd/Makefile
@@ -1,15 +1,17 @@
-# $FreeBSD$
+# $FreeBSD$
+# $NetBSD: Makefile,v 1.12 2000/08/07 16:23:31 thorpej Exp $
-PROG = rpc.lockd
-SRCS = nlm_prot_svc.c nlm_prot.h lockd.c procs.c
-MAN8 = rpc.lockd.8
+PROG= rpc.lockd
+SRCS= nlm_prot_svc.c lockd.c lock_proc.c lockd_lock.c
+MAN8= rpc.lockd.8
+MLINKS= rpc.lockd.8 lockd.8
-DPADD= ${LIBRPCSVC}
-LDADD= -lrpcsvc
+CFLAGS+= -I. -I${DESTDIR}/usr/include/rpcsvc
-CFLAGS+= -I.
+DPADD= ${LIBRPCSVC} ${LIBUTIL}
+LDADD= -lrpcsvc -lutil
-CLEANFILES= nlm_prot_svc.c nlm_prot.h
+CLEANFILES= nlm_prot_svc.c nlm_prot.h test
RPCSRC= ${DESTDIR}/usr/include/rpcsvc/nlm_prot.x
RPCGEN= rpcgen -L -C
@@ -20,7 +22,7 @@ nlm_prot_svc.c: ${RPCSRC}
nlm_prot.h: ${RPCSRC}
${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
-test: test.c
- cc -o test test.c -lrpcsvc
+test: ${.CURDIR}/test.c
+ cc -o test ${.CURDIR}/test.c -lrpcsvc
.include <bsd.prog.mk>
diff --git a/usr.sbin/rpc.lockd/lock_proc.c b/usr.sbin/rpc.lockd/lock_proc.c
new file mode 100644
index 0000000..8b08fd0
--- /dev/null
+++ b/usr.sbin/rpc.lockd/lock_proc.c
@@ -0,0 +1,1294 @@
+/* $NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $ */
+/* $FreeBSD$ */
+/*
+ * Copyright (c) 1995
+ * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
+ *
+ * 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 for the FreeBSD project
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON 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 AUTHOR 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <netconfig.h>
+
+#include <rpc/rpc.h>
+#include <rpcsvc/sm_inter.h>
+
+#include "lockd.h"
+#include <rpcsvc/nlm_prot.h>
+#include "lockd_lock.h"
+
+
+#define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */
+#define CLIENT_CACHE_LIFETIME 120 /* In seconds */
+
+static void log_from_addr __P((char *, struct svc_req *));
+static int addrcmp __P((struct sockaddr *, struct sockaddr *));
+
+/* log_from_addr ----------------------------------------------------------- */
+/*
+ * Purpose: Log name of function called and source address
+ * Returns: Nothing
+ * Notes: Extracts the source address from the transport handle
+ * passed in as part of the called procedure specification
+ */
+static void
+log_from_addr(fun_name, req)
+ char *fun_name;
+ struct svc_req *req;
+{
+ struct sockaddr *addr;
+ char hostname_buf[NI_MAXHOST];
+
+ addr = svc_getrpccaller(req->rq_xprt)->buf;
+ if (getnameinfo(addr , addr->sa_len, hostname_buf, sizeof hostname_buf,
+ NULL, 0, 0) != 0)
+ return;
+
+ syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
+}
+
+/* get_client -------------------------------------------------------------- */
+/*
+ * Purpose: Get a CLIENT* for making RPC calls to lockd on given host
+ * Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error
+ * Notes: Creating a CLIENT* is quite expensive, involving a
+ * conversation with the remote portmapper to get the
+ * port number. Since a given client is quite likely
+ * to make several locking requests in succession, it is
+ * desirable to cache the created CLIENT*.
+ *
+ * Since we are using UDP rather than TCP, there is no cost
+ * to the remote system in keeping these cached indefinitely.
+ * Unfortunately there is a snag: if the remote system
+ * reboots, the cached portmapper results will be invalid,
+ * and we will never detect this since all of the xxx_msg()
+ * calls return no result - we just fire off a udp packet
+ * and hope for the best.
+ *
+ * We solve this by discarding cached values after two
+ * minutes, regardless of whether they have been used
+ * in the meanwhile (since a bad one might have been used
+ * plenty of times, as the host keeps retrying the request
+ * and we keep sending the reply back to the wrong port).
+ *
+ * Given that the entries will always expire in the order
+ * that they were created, there is no point in a LRU
+ * algorithm for when the cache gets full - entries are
+ * always re-used in sequence.
+ */
+static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
+static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */
+static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE];
+static int clnt_cache_next_to_use = 0;
+
+static int
+addrcmp(sa1, sa2)
+ struct sockaddr *sa1;
+ struct sockaddr *sa2;
+{
+ int len;
+ void *p1, *p2;
+
+ if (sa1->sa_family != sa2->sa_family)
+ return -1;
+
+ switch (sa1->sa_family) {
+ case AF_INET:
+ p1 = &((struct sockaddr_in *)sa1)->sin_addr;
+ p2 = &((struct sockaddr_in *)sa2)->sin_addr;
+ len = 4;
+ break;
+ case AF_INET6:
+ p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
+ p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
+ len = 16;
+ break;
+ default:
+ return -1;
+ }
+
+ return memcmp(p1, p2, len);
+}
+
+CLIENT *
+get_client(host_addr, vers)
+ struct sockaddr *host_addr;
+ rpcvers_t vers;
+{
+ CLIENT *client;
+ struct timeval retry_time, time_now;
+ int i;
+ char *netid;
+ struct netconfig *nconf;
+ char host[NI_MAXHOST];
+
+ gettimeofday(&time_now, NULL);
+
+ /*
+ * Search for the given client in the cache, zapping any expired
+ * entries that we happen to notice in passing.
+ */
+ for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
+ client = clnt_cache_ptr[i];
+ if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
+ < time_now.tv_sec)) {
+ /* Cache entry has expired. */
+ if (debug_level > 3)
+ syslog(LOG_DEBUG, "Expired CLIENT* in cache");
+ clnt_cache_time[i] = 0L;
+ clnt_destroy(client);
+ clnt_cache_ptr[i] = NULL;
+ client = NULL;
+ }
+ if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i],
+ host_addr)) {
+ /* Found it! */
+ if (debug_level > 3)
+ syslog(LOG_DEBUG, "Found CLIENT* in cache");
+ return (client);
+ }
+ }
+
+ /* Not found in cache. Free the next entry if it is in use. */
+ if (clnt_cache_ptr[clnt_cache_next_to_use]) {
+ clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
+ clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
+ }
+
+ /*
+ * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
+ * to avoid DNS lookups.
+ */
+ if (getnameinfo(host_addr, host_addr->sa_len, host, sizeof host,
+ NULL, 0, NI_NUMERICHOST) != 0) {
+ syslog(LOG_ERR, "unable to get name string for caller");
+ return NULL;
+ }
+
+#if 1
+ if (host_addr->sa_family == AF_INET6)
+ netid = "udp6";
+ else
+ netid = "udp";
+#else
+ if (host_addr->sa_family == AF_INET6)
+ netid = "tcp6";
+ else
+ netid = "tcp";
+#endif
+ nconf = getnetconfigent(netid);
+ if (nconf == NULL) {
+ syslog(LOG_ERR, "could not get netconfig info for '%s': "
+ "no /etc/netconfig file?", netid);
+ return NULL;
+ }
+
+ client = clnt_tp_create(host, NLM_PROG, vers, nconf);
+ freenetconfigent(nconf);
+
+ if (!client) {
+ syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create"));
+ syslog(LOG_ERR, "Unable to return result to %s", host);
+ return NULL;
+ }
+
+ /* Success - update the cache entry */
+ clnt_cache_ptr[clnt_cache_next_to_use] = client;
+ memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
+ host_addr->sa_len);
+ clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
+ if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE)
+ clnt_cache_next_to_use = 0;
+
+ /*
+ * Disable the default timeout, so we can specify our own in calls
+ * to clnt_call(). (Note that the timeout is a different concept
+ * from the retry period set in clnt_udp_create() above.)
+ */
+ retry_time.tv_sec = -1;
+ retry_time.tv_usec = -1;
+ clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
+
+ if (debug_level > 3)
+ syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
+ return client;
+}
+
+
+/* transmit_result --------------------------------------------------------- */
+/*
+ * Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs
+ * Returns: Nothing - we have no idea if the datagram got there
+ * Notes: clnt_call() will always fail (with timeout) as we are
+ * calling it with timeout 0 as a hack to just issue a datagram
+ * without expecting a result
+ */
+void
+transmit_result(opcode, result, addr)
+ int opcode;
+ nlm_res *result;
+ struct sockaddr *addr;
+{
+ static char dummy;
+ CLIENT *cli;
+ struct timeval timeo;
+ int success;
+
+ if ((cli = get_client(addr, NLM_VERS)) != NULL) {
+ timeo.tv_sec = 0; /* No timeout - not expecting response */
+ timeo.tv_usec = 0;
+
+ success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void,
+ &dummy, timeo);
+
+ if (debug_level > 2)
+ syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
+ success, clnt_sperrno(success));
+ }
+}
+/* transmit4_result --------------------------------------------------------- */
+/*
+ * Purpose: Transmit result for nlm4_xxx_msg pseudo-RPCs
+ * Returns: Nothing - we have no idea if the datagram got there
+ * Notes: clnt_call() will always fail (with timeout) as we are
+ * calling it with timeout 0 as a hack to just issue a datagram
+ * without expecting a result
+ */
+void
+transmit4_result(opcode, result, addr)
+ int opcode;
+ nlm4_res *result;
+ struct sockaddr *addr;
+{
+ static char dummy;
+ CLIENT *cli;
+ struct timeval timeo;
+ int success;
+
+ if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
+ timeo.tv_sec = 0; /* No timeout - not expecting response */
+ timeo.tv_usec = 0;
+
+ success = clnt_call(cli, opcode, xdr_nlm4_res, result, xdr_void,
+ &dummy, timeo);
+
+ if (debug_level > 2)
+ syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
+ success, clnt_sperrno(success));
+ }
+}
+
+/*
+ * converts a struct nlm_lock to struct nlm4_lock
+ */
+static void nlmtonlm4 __P((struct nlm_lock *, struct nlm4_lock *));
+static void
+nlmtonlm4(arg, arg4)
+ struct nlm_lock *arg;
+ struct nlm4_lock *arg4;
+{
+ memcpy(arg4, arg, sizeof(nlm_lock));
+ arg4->l_offset = arg->l_offset;
+ arg4->l_len = arg->l_len;
+}
+/* ------------------------------------------------------------------------- */
+/*
+ * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
+ * involved to ensure reclaim of locks after a crash of the "stateless"
+ * server.
+ *
+ * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
+ * The first are standard RPCs with argument and result.
+ * The nlm_xxx_msg() calls implement exactly the same functions, but
+ * use two pseudo-RPCs (one in each direction). These calls are NOT
+ * standard use of the RPC protocol in that they do not return a result
+ * at all (NB. this is quite different from returning a void result).
+ * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
+ * datagrams, requiring higher-level code to perform retries.
+ *
+ * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
+ * are documented in the comments to get_client() above), this is the
+ * interface used by all current commercial NFS implementations
+ * [Solaris, SCO, AIX etc.]. This is presumed to be because these allow
+ * implementations to continue using the standard RPC libraries, while
+ * avoiding the block-until-result nature of the library interface.
+ *
+ * No client implementations have been identified so far that make use
+ * of the true RPC version (early SunOS releases would be a likely candidate
+ * for testing).
+ */
+
+/* nlm_test ---------------------------------------------------------------- */
+/*
+ * Purpose: Test whether a specified lock would be granted if requested
+ * Returns: nlm_granted (or error code)
+ * Notes:
+ */
+nlm_testres *
+nlm_test_1_svc(arg, rqstp)
+ nlm_testargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_testres res;
+ struct nlm4_lock arg4;
+ struct nlm4_holder *holder;
+ nlmtonlm4(&arg->alock, &arg4);
+
+ if (debug_level)
+ log_from_addr("nlm_test", rqstp);
+
+ holder = testlock(&arg4, 0);
+ /*
+ * Copy the cookie from the argument into the result. Note that this
+ * is slightly hazardous, as the structure contains a pointer to a
+ * malloc()ed buffer that will get freed by the caller. However, the
+ * main function transmits the result before freeing the argument
+ * so it is in fact safe.
+ */
+ res.cookie = arg->cookie;
+ if (holder == NULL) {
+ res.stat.stat = nlm_granted;
+ } else {
+ res.stat.stat = nlm_denied;
+ memcpy(&res.stat.nlm_testrply_u.holder, holder,
+ sizeof(struct nlm_holder));
+ res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
+ res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
+ }
+ return (&res);
+}
+
+void *
+nlm_test_msg_1_svc(arg, rqstp)
+ nlm_testargs *arg;
+ struct svc_req *rqstp;
+{
+ nlm_testres res;
+ static char dummy;
+ struct sockaddr *addr;
+ CLIENT *cli;
+ int success;
+ struct timeval timeo;
+ struct nlm4_lock arg4;
+ struct nlm4_holder *holder;
+
+ nlmtonlm4(&arg->alock, &arg4);
+
+ if (debug_level)
+ log_from_addr("nlm_test_msg", rqstp);
+
+ holder = testlock(&arg4, 0);
+
+ res.cookie = arg->cookie;
+ if (holder == NULL) {
+ res.stat.stat = nlm_granted;
+ } else {
+ res.stat.stat = nlm_denied;
+ memcpy(&res.stat.nlm_testrply_u.holder, holder,
+ sizeof(struct nlm_holder));
+ res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
+ res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
+ }
+
+ /*
+ * nlm_test has different result type to the other operations, so
+ * can't use transmit_result() in this case
+ */
+ addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
+ if ((cli = get_client(addr, NLM_VERS)) != NULL) {
+ timeo.tv_sec = 0; /* No timeout - not expecting response */
+ timeo.tv_usec = 0;
+
+ success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres,
+ &res, xdr_void, &dummy, timeo);
+
+ if (debug_level > 2)
+ syslog(LOG_DEBUG, "clnt_call returns %d", success);
+ }
+ return (NULL);
+}
+
+/* nlm_lock ---------------------------------------------------------------- */
+/*
+ * Purposes: Establish a lock
+ * Returns: granted, denied or blocked
+ * Notes: *** grace period support missing
+ */
+nlm_res *
+nlm_lock_1_svc(arg, rqstp)
+ nlm_lockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+ struct nlm4_lockargs arg4;
+ nlmtonlm4(&arg->alock, &arg4.alock);
+ arg4.cookie = arg->cookie;
+ arg4.block = arg->block;
+ arg4.exclusive = arg->exclusive;
+ arg4.reclaim = arg->reclaim;
+ arg4.state = arg->state;
+
+ if (debug_level)
+ log_from_addr("nlm_lock", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm_test_1() */
+ res.cookie = arg->cookie;
+
+ res.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
+ return (&res);
+}
+
+void *
+nlm_lock_msg_1_svc(arg, rqstp)
+ nlm_lockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+ struct nlm4_lockargs arg4;
+
+ nlmtonlm4(&arg->alock, &arg4.alock);
+ arg4.cookie = arg->cookie;
+ arg4.block = arg->block;
+ arg4.exclusive = arg->exclusive;
+ arg4.reclaim = arg->reclaim;
+ arg4.state = arg->state;
+
+ if (debug_level)
+ log_from_addr("nlm_lock_msg", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
+ transmit_result(NLM_LOCK_RES, &res,
+ (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+
+ return (NULL);
+}
+
+/* nlm_cancel -------------------------------------------------------------- */
+/*
+ * Purpose: Cancel a blocked lock request
+ * Returns: granted or denied
+ * Notes:
+ */
+nlm_res *
+nlm_cancel_1_svc(arg, rqstp)
+ nlm_cancargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+ struct nlm4_lock arg4;
+
+ nlmtonlm4(&arg->alock, &arg4);
+
+ if (debug_level)
+ log_from_addr("nlm_cancel", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm_test_1() */
+ res.cookie = arg->cookie;
+
+ /*
+ * Since at present we never return 'nlm_blocked', there can never be
+ * a lock to cancel, so this call always fails.
+ */
+ res.stat.stat = unlock(&arg4, LOCK_CANCEL);
+ return (&res);
+}
+
+void *
+nlm_cancel_msg_1_svc(arg, rqstp)
+ nlm_cancargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+ struct nlm4_lock arg4;
+
+ nlmtonlm4(&arg->alock, &arg4);
+
+ if (debug_level)
+ log_from_addr("nlm_cancel_msg", rqstp);
+
+ res.cookie = arg->cookie;
+ /*
+ * Since at present we never return 'nlm_blocked', there can never be
+ * a lock to cancel, so this call always fails.
+ */
+ res.stat.stat = unlock(&arg4, LOCK_CANCEL);
+ transmit_result(NLM_CANCEL_RES, &res,
+ (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+ return (NULL);
+}
+
+/* nlm_unlock -------------------------------------------------------------- */
+/*
+ * Purpose: Release an existing lock
+ * Returns: Always granted, unless during grace period
+ * Notes: "no such lock" error condition is ignored, as the
+ * protocol uses unreliable UDP datagrams, and may well
+ * re-try an unlock that has already succeeded.
+ */
+nlm_res *
+nlm_unlock_1_svc(arg, rqstp)
+ nlm_unlockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+ struct nlm4_lock arg4;
+
+ nlmtonlm4(&arg->alock, &arg4);
+
+ if (debug_level)
+ log_from_addr("nlm_unlock", rqstp);
+
+ res.stat.stat = unlock(&arg4, 0);
+ res.cookie = arg->cookie;
+
+ return (&res);
+}
+
+void *
+nlm_unlock_msg_1_svc(arg, rqstp)
+ nlm_unlockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+ struct nlm4_lock arg4;
+
+ nlmtonlm4(&arg->alock, &arg4);
+
+ if (debug_level)
+ log_from_addr("nlm_unlock_msg", rqstp);
+
+ res.stat.stat = unlock(&arg4, 0);
+ res.cookie = arg->cookie;
+
+ transmit_result(NLM_UNLOCK_RES, &res,
+ (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+ return (NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ * Client-side pseudo-RPCs for results. Note that for the client there
+ * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
+ * version returns the results in the RPC result, and so the client
+ * does not normally receive incoming RPCs.
+ *
+ * The exception to this is nlm_granted(), which is genuinely an RPC
+ * call from the server to the client - a 'call-back' in normal procedure
+ * call terms.
+ */
+
+/* nlm_granted ------------------------------------------------------------- */
+/*
+ * Purpose: Receive notification that formerly blocked lock now granted
+ * Returns: always success ('granted')
+ * Notes:
+ */
+nlm_res *
+nlm_granted_1_svc(arg, rqstp)
+ nlm_testargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+
+ if (debug_level)
+ log_from_addr("nlm_granted", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm_test_1() */
+ res.cookie = arg->cookie;
+
+ res.stat.stat = nlm_granted;
+ return (&res);
+}
+
+void *
+nlm_granted_msg_1_svc(arg, rqstp)
+ nlm_testargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+
+ if (debug_level)
+ log_from_addr("nlm_granted_msg", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat.stat = nlm_granted;
+ transmit_result(NLM_GRANTED_RES, &res,
+ (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+ return (NULL);
+}
+
+/* nlm_test_res ------------------------------------------------------------ */
+/*
+ * Purpose: Accept result from earlier nlm_test_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm_test_res_1_svc(arg, rqstp)
+ nlm_testres *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm_test_res", rqstp);
+ return (NULL);
+}
+
+/* nlm_lock_res ------------------------------------------------------------ */
+/*
+ * Purpose: Accept result from earlier nlm_lock_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm_lock_res_1_svc(arg, rqstp)
+ nlm_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm_lock_res", rqstp);
+
+ return (NULL);
+}
+
+/* nlm_cancel_res ---------------------------------------------------------- */
+/*
+ * Purpose: Accept result from earlier nlm_cancel_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm_cancel_res_1_svc(arg, rqstp)
+ nlm_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm_cancel_res", rqstp);
+ return (NULL);
+}
+
+/* nlm_unlock_res ---------------------------------------------------------- */
+/*
+ * Purpose: Accept result from earlier nlm_unlock_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm_unlock_res_1_svc(arg, rqstp)
+ nlm_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm_unlock_res", rqstp);
+ return (NULL);
+}
+
+/* nlm_granted_res --------------------------------------------------------- */
+/*
+ * Purpose: Accept result from earlier nlm_granted_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm_granted_res_1_svc(arg, rqstp)
+ nlm_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm_granted_res", rqstp);
+ return (NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ * Calls for PCNFS locking (aka non-monitored locking, no involvement
+ * of rpc.statd).
+ *
+ * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
+ */
+
+/* nlm_share --------------------------------------------------------------- */
+/*
+ * Purpose: Establish a DOS-style lock
+ * Returns: success or failure
+ * Notes: Blocking locks are not supported - client is expected
+ * to retry if required.
+ */
+nlm_shareres *
+nlm_share_3_svc(arg, rqstp)
+ nlm_shareargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_shareres res;
+
+ if (debug_level)
+ log_from_addr("nlm_share", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat = nlm_granted;
+ res.sequence = 1234356; /* X/Open says this field is ignored? */
+ return (&res);
+}
+
+/* nlm_unshare ------------------------------------------------------------ */
+/*
+ * Purpose: Release a DOS-style lock
+ * Returns: nlm_granted, unless in grace period
+ * Notes:
+ */
+nlm_shareres *
+nlm_unshare_3_svc(arg, rqstp)
+ nlm_shareargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_shareres res;
+
+ if (debug_level)
+ log_from_addr("nlm_unshare", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat = nlm_granted;
+ res.sequence = 1234356; /* X/Open says this field is ignored? */
+ return (&res);
+}
+
+/* nlm_nm_lock ------------------------------------------------------------ */
+/*
+ * Purpose: non-monitored version of nlm_lock()
+ * Returns: as for nlm_lock()
+ * Notes: These locks are in the same style as the standard nlm_lock,
+ * but the rpc.statd should not be called to establish a
+ * monitor for the client machine, since that machine is
+ * declared not to be running a rpc.statd, and so would not
+ * respond to the statd protocol.
+ */
+nlm_res *
+nlm_nm_lock_3_svc(arg, rqstp)
+ nlm_lockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm_res res;
+
+ if (debug_level)
+ log_from_addr("nlm_nm_lock", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm_test_1() */
+ res.cookie = arg->cookie;
+ res.stat.stat = nlm_granted;
+ return (&res);
+}
+
+/* nlm_free_all ------------------------------------------------------------ */
+/*
+ * Purpose: Release all locks held by a named client
+ * Returns: Nothing
+ * Notes: Potential denial of service security problem here - the
+ * locks to be released are specified by a host name, independent
+ * of the address from which the request has arrived.
+ * Should probably be rejected if the named host has been
+ * using monitored locks.
+ */
+void *
+nlm_free_all_3_svc(arg, rqstp)
+ nlm_notify *arg;
+ struct svc_req *rqstp;
+{
+ static char dummy;
+
+ if (debug_level)
+ log_from_addr("nlm_free_all", rqstp);
+ return (&dummy);
+}
+
+/* calls for nlm version 4 (NFSv3) */
+/* nlm_test ---------------------------------------------------------------- */
+/*
+ * Purpose: Test whether a specified lock would be granted if requested
+ * Returns: nlm_granted (or error code)
+ * Notes:
+ */
+nlm4_testres *
+nlm4_test_4_svc(arg, rqstp)
+ nlm4_testargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_testres res;
+ struct nlm4_holder *holder;
+
+ if (debug_level)
+ log_from_addr("nlm4_test", rqstp);
+
+ holder = testlock(&arg->alock, LOCK_V4);
+
+ /*
+ * Copy the cookie from the argument into the result. Note that this
+ * is slightly hazardous, as the structure contains a pointer to a
+ * malloc()ed buffer that will get freed by the caller. However, the
+ * main function transmits the result before freeing the argument
+ * so it is in fact safe.
+ */
+ res.cookie = arg->cookie;
+ if (holder == NULL) {
+ res.stat.stat = nlm4_granted;
+ } else {
+ res.stat.stat = nlm4_denied;
+ memcpy(&res.stat.nlm4_testrply_u.holder, holder,
+ sizeof(struct nlm4_holder));
+ }
+ return (&res);
+}
+
+void *
+nlm4_test_msg_4_svc(arg, rqstp)
+ nlm4_testargs *arg;
+ struct svc_req *rqstp;
+{
+ nlm4_testres res;
+ static char dummy;
+ struct sockaddr *addr;
+ CLIENT *cli;
+ int success;
+ struct timeval timeo;
+ struct nlm4_holder *holder;
+
+ if (debug_level)
+ log_from_addr("nlm4_test_msg", rqstp);
+
+ holder = testlock(&arg->alock, LOCK_V4);
+
+ res.cookie = arg->cookie;
+ if (holder == NULL) {
+ res.stat.stat = nlm4_granted;
+ } else {
+ res.stat.stat = nlm4_denied;
+ memcpy(&res.stat.nlm4_testrply_u.holder, holder,
+ sizeof(struct nlm4_holder));
+ }
+
+ /*
+ * nlm_test has different result type to the other operations, so
+ * can't use transmit4_result() in this case
+ */
+ addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
+ if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
+ timeo.tv_sec = 0; /* No timeout - not expecting response */
+ timeo.tv_usec = 0;
+
+ success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres,
+ &res, xdr_void, &dummy, timeo);
+
+ if (debug_level > 2)
+ syslog(LOG_DEBUG, "clnt_call returns %d", success);
+ }
+ return (NULL);
+}
+
+/* nlm_lock ---------------------------------------------------------------- */
+/*
+ * Purposes: Establish a lock
+ * Returns: granted, denied or blocked
+ * Notes: *** grace period support missing
+ */
+nlm4_res *
+nlm4_lock_4_svc(arg, rqstp)
+ nlm4_lockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_lock", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm_test_4() */
+ res.cookie = arg->cookie;
+
+ res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_V4);
+ return (&res);
+}
+
+void *
+nlm4_lock_msg_4_svc(arg, rqstp)
+ nlm4_lockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_lock_msg", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4);
+ transmit4_result(NLM4_LOCK_RES, &res,
+ (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+
+ return (NULL);
+}
+
+/* nlm_cancel -------------------------------------------------------------- */
+/*
+ * Purpose: Cancel a blocked lock request
+ * Returns: granted or denied
+ * Notes:
+ */
+nlm4_res *
+nlm4_cancel_4_svc(arg, rqstp)
+ nlm4_cancargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_cancel", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm_test_1() */
+ res.cookie = arg->cookie;
+
+ /*
+ * Since at present we never return 'nlm_blocked', there can never be
+ * a lock to cancel, so this call always fails.
+ */
+ res.stat.stat = unlock(&arg->alock, LOCK_CANCEL);
+ return (&res);
+}
+
+void *
+nlm4_cancel_msg_4_svc(arg, rqstp)
+ nlm4_cancargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_cancel_msg", rqstp);
+
+ res.cookie = arg->cookie;
+ /*
+ * Since at present we never return 'nlm_blocked', there can never be
+ * a lock to cancel, so this call always fails.
+ */
+ res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4);
+ transmit4_result(NLM4_CANCEL_RES, &res,
+ (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+ return (NULL);
+}
+
+/* nlm_unlock -------------------------------------------------------------- */
+/*
+ * Purpose: Release an existing lock
+ * Returns: Always granted, unless during grace period
+ * Notes: "no such lock" error condition is ignored, as the
+ * protocol uses unreliable UDP datagrams, and may well
+ * re-try an unlock that has already succeeded.
+ */
+nlm4_res *
+nlm4_unlock_4_svc(arg, rqstp)
+ nlm4_unlockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_unlock", rqstp);
+
+ res.stat.stat = unlock(&arg->alock, LOCK_V4);
+ res.cookie = arg->cookie;
+
+ return (&res);
+}
+
+void *
+nlm4_unlock_msg_4_svc(arg, rqstp)
+ nlm4_unlockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_unlock_msg", rqstp);
+
+ res.stat.stat = unlock(&arg->alock, LOCK_V4);
+ res.cookie = arg->cookie;
+
+ transmit4_result(NLM4_UNLOCK_RES, &res,
+ (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+ return (NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ * Client-side pseudo-RPCs for results. Note that for the client there
+ * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
+ * version returns the results in the RPC result, and so the client
+ * does not normally receive incoming RPCs.
+ *
+ * The exception to this is nlm_granted(), which is genuinely an RPC
+ * call from the server to the client - a 'call-back' in normal procedure
+ * call terms.
+ */
+
+/* nlm_granted ------------------------------------------------------------- */
+/*
+ * Purpose: Receive notification that formerly blocked lock now granted
+ * Returns: always success ('granted')
+ * Notes:
+ */
+nlm4_res *
+nlm4_granted_4_svc(arg, rqstp)
+ nlm4_testargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_granted", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm_test_1() */
+ res.cookie = arg->cookie;
+
+ res.stat.stat = nlm4_granted;
+ return (&res);
+}
+
+void *
+nlm4_granted_msg_4_svc(arg, rqstp)
+ nlm4_testargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_granted_msg", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat.stat = nlm4_granted;
+ transmit4_result(NLM4_GRANTED_RES, &res,
+ (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
+ return (NULL);
+}
+
+/* nlm_test_res ------------------------------------------------------------ */
+/*
+ * Purpose: Accept result from earlier nlm_test_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm4_test_res_4_svc(arg, rqstp)
+ nlm4_testres *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm4_test_res", rqstp);
+ return (NULL);
+}
+
+/* nlm_lock_res ------------------------------------------------------------ */
+/*
+ * Purpose: Accept result from earlier nlm_lock_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm4_lock_res_4_svc(arg, rqstp)
+ nlm4_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm4_lock_res", rqstp);
+
+ return (NULL);
+}
+
+/* nlm_cancel_res ---------------------------------------------------------- */
+/*
+ * Purpose: Accept result from earlier nlm_cancel_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm4_cancel_res_4_svc(arg, rqstp)
+ nlm4_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm4_cancel_res", rqstp);
+ return (NULL);
+}
+
+/* nlm_unlock_res ---------------------------------------------------------- */
+/*
+ * Purpose: Accept result from earlier nlm_unlock_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm4_unlock_res_4_svc(arg, rqstp)
+ nlm4_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm4_unlock_res", rqstp);
+ return (NULL);
+}
+
+/* nlm_granted_res --------------------------------------------------------- */
+/*
+ * Purpose: Accept result from earlier nlm_granted_msg() call
+ * Returns: Nothing
+ */
+void *
+nlm4_granted_res_4_svc(arg, rqstp)
+ nlm4_res *arg;
+ struct svc_req *rqstp;
+{
+ if (debug_level)
+ log_from_addr("nlm4_granted_res", rqstp);
+ return (NULL);
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ * Calls for PCNFS locking (aka non-monitored locking, no involvement
+ * of rpc.statd).
+ *
+ * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
+ */
+
+/* nlm_share --------------------------------------------------------------- */
+/*
+ * Purpose: Establish a DOS-style lock
+ * Returns: success or failure
+ * Notes: Blocking locks are not supported - client is expected
+ * to retry if required.
+ */
+nlm4_shareres *
+nlm4_share_4_svc(arg, rqstp)
+ nlm4_shareargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_shareres res;
+
+ if (debug_level)
+ log_from_addr("nlm4_share", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat = nlm4_granted;
+ res.sequence = 1234356; /* X/Open says this field is ignored? */
+ return (&res);
+}
+
+/* nlm4_unshare ------------------------------------------------------------ */
+/*
+ * Purpose: Release a DOS-style lock
+ * Returns: nlm_granted, unless in grace period
+ * Notes:
+ */
+nlm4_shareres *
+nlm4_unshare_4_svc(arg, rqstp)
+ nlm4_shareargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_shareres res;
+
+ if (debug_level)
+ log_from_addr("nlm_unshare", rqstp);
+
+ res.cookie = arg->cookie;
+ res.stat = nlm4_granted;
+ res.sequence = 1234356; /* X/Open says this field is ignored? */
+ return (&res);
+}
+
+/* nlm4_nm_lock ------------------------------------------------------------ */
+/*
+ * Purpose: non-monitored version of nlm4_lock()
+ * Returns: as for nlm4_lock()
+ * Notes: These locks are in the same style as the standard nlm4_lock,
+ * but the rpc.statd should not be called to establish a
+ * monitor for the client machine, since that machine is
+ * declared not to be running a rpc.statd, and so would not
+ * respond to the statd protocol.
+ */
+nlm4_res *
+nlm4_nm_lock_4_svc(arg, rqstp)
+ nlm4_lockargs *arg;
+ struct svc_req *rqstp;
+{
+ static nlm4_res res;
+
+ if (debug_level)
+ log_from_addr("nlm4_nm_lock", rqstp);
+
+ /* copy cookie from arg to result. See comment in nlm4_test_1() */
+ res.cookie = arg->cookie;
+ res.stat.stat = nlm4_granted;
+ return (&res);
+}
+
+/* nlm4_free_all ------------------------------------------------------------ */
+/*
+ * Purpose: Release all locks held by a named client
+ * Returns: Nothing
+ * Notes: Potential denial of service security problem here - the
+ * locks to be released are specified by a host name, independent
+ * of the address from which the request has arrived.
+ * Should probably be rejected if the named host has been
+ * using monitored locks.
+ */
+void *
+nlm4_free_all_4_svc(arg, rqstp)
+ nlm_notify *arg;
+ struct svc_req *rqstp;
+{
+ static char dummy;
+
+ if (debug_level)
+ log_from_addr("nlm4_free_all", rqstp);
+ return (&dummy);
+}
+
+/* nlm_sm_notify --------------------------------------------------------- */
+/*
+ * Purpose: called by rpc.statd when a monitored host state changes.
+ * Returns: Nothing
+ */
+void *
+nlm_sm_notify_0_svc(arg, rqstp)
+ struct nlm_sm_status *arg;
+ struct svc_req *rqstp;
+{
+ static char dummy;
+ notify(arg->mon_name, arg->state);
+ return (&dummy);
+}
diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c
index ac32856..e0ac5cf 100644
--- a/usr.sbin/rpc.lockd/lockd.c
+++ b/usr.sbin/rpc.lockd/lockd.c
@@ -1,3 +1,6 @@
+/* $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ */
+/* $FreeBSD$ */
+
/*
* Copyright (c) 1995
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
@@ -31,77 +34,193 @@
*
*/
+#include <sys/cdefs.h>
#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+__RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $");
+#endif
+
+/*
+ * main() function for NFS lock daemon. Most of the code in this
+ * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x.
+ *
+ * The actual program logic is in the file lock_proc.c
+ */
-/* main() function for NFS lock daemon. Most of the code in this */
-/* file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x */
-/* The actual program logic is in the file procs.c */
+#include <sys/types.h>
+#include <sys/socket.h>
#include <err.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
+#include <syslog.h>
+#include <signal.h>
#include <string.h>
+#include <unistd.h>
+#include <libutil.h>
+#include <netconfig.h>
+
#include <rpc/rpc.h>
-#include <rpc/pmap_clnt.h>
+#include <rpcsvc/sm_inter.h>
+
#include "lockd.h"
+#include <rpcsvc/nlm_prot.h>
+
+int debug_level = 0; /* 0 = no debugging syslog() calls */
+int _rpcsvcdirty = 0;
+
+int grace_expired;
-void nlm_prog_1 __P((struct svc_req *, SVCXPRT *));
-void nlm_prog_3 __P((struct svc_req *, SVCXPRT *));
-static void usage __P((void));
+int main __P((int, char **));
+void nlm_prog_0 __P((struct svc_req *, SVCXPRT *));
+void nlm_prog_1 __P((struct svc_req *, SVCXPRT *));
+void nlm_prog_3 __P((struct svc_req *, SVCXPRT *));
+void nlm_prog_4 __P((struct svc_req *, SVCXPRT *));
+void usage __P((void));
-int debug_level = 0; /* Zero means no debugging syslog() calls */
+void sigalarm_handler __P((int));
+
+char *transports[] = { "udp", "tcp", "udp6", "tcp6" };
int
-main(int argc, char **argv)
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ SVCXPRT *transp;
+ int ch, i, maxindex, s;
+ struct sigaction sigchild, sigalarm;
+ int grace_period = 30;
+ struct netconfig *nconf;
+
+ while ((ch = getopt(argc, argv, "d:g:")) != (-1)) {
+ switch (ch) {
+ case 'd':
+ debug_level = atoi(optarg);
+ if (!debug_level) {
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+ case 'g':
+ grace_period = atoi(optarg);
+ if (!grace_period) {
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+ default:
+ case '?':
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ if (geteuid()) { /* This command allowed only to root */
+ fprintf(stderr, "Sorry. You are not superuser\n");
+ exit(1);
+ }
+
+ (void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
+ (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
+ (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
+ (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
+
+ /*
+ * Check if IPv6 support is present.
+ */
+ s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0)
+ maxindex = 2;
+ else {
+ close(s);
+ maxindex = 4;
+ }
+
+ for (i = 0; i < maxindex; i++) {
+ nconf = getnetconfigent(transports[i]);
+ if (nconf == NULL)
+ errx(1, "cannot get udp netconf.");
+
+ transp = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
+ if (transp == NULL) {
+ errx(1, "cannot create %s service.", transports[i]);
+ /* NOTREACHED */
+ }
+ if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0, nconf)) {
+ errx(1, "unable to register (NLM_PROG, NLM_SM, %s)",
+ transports[i]);
+ /* NOTREACHED */
+ }
+ if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1, nconf)) {
+ errx(1, "unable to register (NLM_PROG, NLM_VERS, %s)",
+ transports[i]);
+ /* NOTREACHED */
+ }
+ if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, nconf)) {
+ errx(1, "unable to register (NLM_PROG, NLM_VERSX, %s)",
+ transports[i]);
+ /* NOTREACHED */
+ }
+ if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, nconf)) {
+ errx(1, "unable to register (NLM_PROG, NLM_VERS4, %s)",
+ transports[i]);
+ /* NOTREACHED */
+ }
+ freenetconfigent(nconf);
+ }
+
+ /*
+ * Note that it is NOT sensible to run this program from inetd - the
+ * protocol assumes that it will run immediately at boot time.
+ */
+ if (daemon(0, 0)) {
+ err(1, "cannot fork");
+ /* NOTREACHED */
+ }
+
+ openlog("rpc.lockd", 0, LOG_DAEMON);
+ if (debug_level)
+ syslog(LOG_INFO, "Starting, debug level %d", debug_level);
+ else
+ syslog(LOG_INFO, "Starting");
+
+ sigchild.sa_handler = sigchild_handler;
+ sigemptyset(&sigchild.sa_mask);
+ sigchild.sa_flags = SA_RESTART;
+ if (sigaction(SIGCHLD, &sigchild, NULL) != 0) {
+ syslog(LOG_WARNING, "sigaction(SIGCHLD) failed: %s",
+ strerror(errno));
+ exit(1);
+ }
+ sigalarm.sa_handler = sigalarm_handler;
+ sigemptyset(&sigalarm.sa_mask);
+ sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
+ sigalarm.sa_flags |= SA_RESTART;
+ if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
+ syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
+ strerror(errno));
+ exit(1);
+ }
+ grace_expired = 0;
+ if (alarm(10) < 0) {
+ syslog(LOG_WARNING, "alarm failed: %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ svc_run(); /* Should never return */
+ exit(1);
+}
+
+void
+sigalarm_handler(s)
+ int s;
{
- SVCXPRT *transp;
-
- if (argc > 1)
- {
- if (strncmp(argv[1], "-d", 2))
- usage();
- if (argc > 2) debug_level = atoi(argv[2]);
- else debug_level = atoi(argv[1] + 2);
- /* Ensure at least some debug if -d with no specified level */
- if (!debug_level) debug_level = 1;
- }
-
- (void)pmap_unset(NLM_PROG, NLM_VERS);
- (void)pmap_unset(NLM_PROG, NLM_VERSX);
-
- transp = svcudp_create(RPC_ANYSOCK);
- if (transp == NULL)
- errx(1, "cannot create udp service");
- if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP))
- errx(1, "unable to register (NLM_PROG, NLM_VERS, udp)");
- if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP))
- errx(1, "unable to register (NLM_PROG, NLM_VERSX, udp)");
-
- transp = svctcp_create(RPC_ANYSOCK, 0, 0);
- if (transp == NULL)
- errx(1, "cannot create tcp service");
- if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP))
- errx(1, "unable to register (NLM_PROG, NLM_VERS, tcp)");
- if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP))
- errx(1, "unable to register (NLM_PROG, NLM_VERSX, tcp)");
-
- /* Note that it is NOT sensible to run this program from inetd - the */
- /* protocol assumes that it will run immediately at boot time. */
- if (daemon(0,0))
- err(1, "fork");
- openlog("rpc.lockd", 0, LOG_DAEMON);
- if (debug_level) syslog(LOG_INFO, "Starting, debug level %d", debug_level);
- else syslog(LOG_INFO, "Starting");
-
- svc_run(); /* Should never return */
- exit(1);
+ grace_expired = 1;
}
-static void
+void
usage()
{
- fprintf(stderr, "usage: rpc.lockd [-d [debuglevel]]\n");
- exit(1);
+ errx(1, "usage: rpc.lockd [-d <debuglevel>] [-g <grace period>]");
}
diff --git a/usr.sbin/rpc.lockd/lockd.h b/usr.sbin/rpc.lockd/lockd.h
index 39586bf..42f14f1 100644
--- a/usr.sbin/rpc.lockd/lockd.h
+++ b/usr.sbin/rpc.lockd/lockd.h
@@ -1,3 +1,6 @@
+/* $NetBSD: lockd.h,v 1.2 2000/06/07 14:34:40 bouyer Exp $ */
+/* $FreeBSD$ */
+
/*
* Copyright (c) 1995
* A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
@@ -31,14 +34,6 @@
*
*/
-
-
-#include <stdio.h>
-#include <rpc/rpc.h>
-#include <syslog.h>
-#include <rpcsvc/sm_inter.h> /* protocol to talk to rpc.statd */
-#include "nlm_prot.h" /* The protocol we are implementing */
-
-
-/* global variables ------------------------------------------------------- */
-extern int debug_level;
+extern int debug_level;
+extern int grace_expired;
+void sigchild_handler __P((int));
diff --git a/usr.sbin/rpc.lockd/lockd_lock.c b/usr.sbin/rpc.lockd/lockd_lock.c
new file mode 100644
index 0000000..998a200
--- /dev/null
+++ b/usr.sbin/rpc.lockd/lockd_lock.c
@@ -0,0 +1,759 @@
+/* $NetBSD: lockd_lock.c,v 1.5 2000/11/21 03:47:41 enami Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2000 Manuel Bouyer.
+ *
+ * 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <rpc/rpc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+#include <rpcsvc/sm_inter.h>
+#include <rpcsvc/nlm_prot.h>
+#include "lockd_lock.h"
+#include "lockd.h"
+
+/* A set of utilities for managing file locking */
+LIST_HEAD(lcklst_head, file_lock);
+struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head);
+
+/* struct describing a lock */
+struct file_lock {
+ LIST_ENTRY(file_lock) lcklst;
+ fhandle_t filehandle; /* NFS filehandle */
+ struct sockaddr *addr;
+ struct nlm4_holder client; /* lock holder */
+ netobj client_cookie; /* cookie sent by the client */
+ char client_name[128];
+ int nsm_status; /* status from the remote lock manager */
+ int status; /* lock status, see below */
+ int flags; /* lock flags, see lockd_lock.h */
+ pid_t locker; /* pid of the child process trying to get the lock */
+ int fd; /* file descriptor for this lock */
+};
+
+/* lock status */
+#define LKST_LOCKED 1 /* lock is locked */
+#define LKST_WAITING 2 /* file is already locked by another host */
+#define LKST_PROCESSING 3 /* child is trying to aquire the lock */
+#define LKST_DYING 4 /* must dies when we get news from the child */
+
+void lfree __P((struct file_lock *));
+enum nlm_stats do_lock __P((struct file_lock *, int));
+enum nlm_stats do_unlock __P((struct file_lock *));
+void send_granted __P((struct file_lock *, int));
+void siglock __P((void));
+void sigunlock __P((void));
+
+/* list of hosts we monitor */
+LIST_HEAD(hostlst_head, host);
+struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head);
+
+/* struct describing a lock */
+struct host {
+ LIST_ENTRY(host) hostlst;
+ char name[SM_MAXSTRLEN];
+ int refcnt;
+};
+
+void do_mon __P((char *));
+
+/*
+ * testlock(): inform the caller if the requested lock would be granted or not
+ * returns NULL if lock would granted, or pointer to the current nlm4_holder
+ * otherwise.
+ */
+
+struct nlm4_holder *
+testlock(lock, flags)
+ struct nlm4_lock *lock;
+ int flags;
+{
+ struct file_lock *fl;
+ fhandle_t filehandle;
+
+ /* convert lock to a local filehandle */
+ memcpy(&filehandle, lock->fh.n_bytes, sizeof(filehandle));
+
+ siglock();
+ /* search through the list for lock holder */
+ for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
+ fl = LIST_NEXT(fl, lcklst)) {
+ if (fl->status != LKST_LOCKED)
+ continue;
+ if (memcmp(&fl->filehandle, &filehandle, sizeof(filehandle)))
+ continue;
+ /* got it ! */
+ syslog(LOG_DEBUG, "test for %s: found lock held by %s",
+ lock->caller_name, fl->client_name);
+ sigunlock();
+ return (&fl->client);
+ }
+ /* not found */
+ sigunlock();
+ syslog(LOG_DEBUG, "test for %s: no lock found", lock->caller_name);
+ return NULL;
+}
+
+/*
+ * getlock: try to aquire the lock.
+ * If file is already locked and we can sleep, put the lock in the list with
+ * status LKST_WAITING; it'll be processed later.
+ * Otherwise try to lock. If we're allowed to block, fork a child which
+ * will do the blocking lock.
+ */
+enum nlm_stats
+getlock(lckarg, rqstp, flags)
+ nlm4_lockargs * lckarg;
+ struct svc_req *rqstp;
+ int flags;
+{
+ struct file_lock *fl, *newfl;
+ enum nlm_stats retval;
+
+ if (grace_expired == 0 && lckarg->reclaim == 0)
+ return (flags & LOCK_V4) ?
+ nlm4_denied_grace_period : nlm_denied_grace_period;
+
+ /* allocate new file_lock for this request */
+ newfl = malloc(sizeof(struct file_lock));
+ if (newfl == NULL) {
+ syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
+ /* failed */
+ return (flags & LOCK_V4) ?
+ nlm4_denied_nolock : nlm_denied_nolocks;
+ }
+ if (lckarg->alock.fh.n_len != sizeof(fhandle_t)) {
+ syslog(LOG_DEBUG, "recieved fhandle size %d, local size %d",
+ lckarg->alock.fh.n_len, (int)sizeof(fhandle_t));
+ }
+ memcpy(&newfl->filehandle, lckarg->alock.fh.n_bytes, sizeof(fhandle_t));
+ newfl->addr = (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf;
+ newfl->client.exclusive = lckarg->exclusive;
+ newfl->client.svid = lckarg->alock.svid;
+ newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len);
+ if (newfl->client.oh.n_bytes == NULL) {
+ syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
+ free(newfl);
+ return (flags & LOCK_V4) ?
+ nlm4_denied_nolock : nlm_denied_nolocks;
+ }
+ newfl->client.oh.n_len = lckarg->alock.oh.n_len;
+ memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes,
+ lckarg->alock.oh.n_len);
+ newfl->client.l_offset = lckarg->alock.l_offset;
+ newfl->client.l_len = lckarg->alock.l_len;
+ newfl->client_cookie.n_len = lckarg->cookie.n_len;
+ newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len);
+ if (newfl->client_cookie.n_bytes == NULL) {
+ syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
+ free(newfl->client.oh.n_bytes);
+ free(newfl);
+ return (flags & LOCK_V4) ?
+ nlm4_denied_nolock : nlm_denied_nolocks;
+ }
+ memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes,
+ lckarg->cookie.n_len);
+ strncpy(newfl->client_name, lckarg->alock.caller_name, 128);
+ newfl->nsm_status = lckarg->state;
+ newfl->status = 0;
+ newfl->flags = flags;
+ siglock();
+ /* look for a lock rq from this host for this fh */
+ for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
+ fl = LIST_NEXT(fl, lcklst)) {
+ if (memcmp(&newfl->filehandle, &fl->filehandle,
+ sizeof(fhandle_t)) == 0) {
+ if (strcmp(newfl->client_name, fl->client_name) == 0 &&
+ newfl->client.svid == fl->client.svid) {
+ /* already locked by this host ??? */
+ sigunlock();
+ syslog(LOG_NOTICE, "duplicate lock from %s",
+ newfl->client_name);
+ lfree(newfl);
+ switch(fl->status) {
+ case LKST_LOCKED:
+ return (flags & LOCK_V4) ?
+ nlm4_granted : nlm_granted;
+ case LKST_WAITING:
+ case LKST_PROCESSING:
+ return (flags & LOCK_V4) ?
+ nlm4_blocked : nlm_blocked;
+ case LKST_DYING:
+ return (flags & LOCK_V4) ?
+ nlm4_denied : nlm_denied;
+ default:
+ syslog(LOG_NOTICE, "bad status %d",
+ fl->status);
+ return (flags & LOCK_V4) ?
+ nlm4_failed : nlm_denied;
+ }
+ }
+ /*
+ * We already have a lock for this file. Put this one
+ * in waiting state if allowed to block
+ */
+ if (lckarg->block) {
+ syslog(LOG_DEBUG, "lock from %s: already "
+ "locked, waiting",
+ lckarg->alock.caller_name);
+ newfl->status = LKST_WAITING;
+ LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
+ do_mon(lckarg->alock.caller_name);
+ sigunlock();
+ return (flags & LOCK_V4) ?
+ nlm4_blocked : nlm_blocked;
+ } else {
+ sigunlock();
+ syslog(LOG_DEBUG, "lock from %s: already "
+ "locked, failed",
+ lckarg->alock.caller_name);
+ lfree(newfl);
+ return (flags & LOCK_V4) ?
+ nlm4_denied : nlm_denied;
+ }
+ }
+ }
+ /* no entry for this file yet; add to list */
+ LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst);
+ /* do the lock */
+ retval = do_lock(newfl, lckarg->block);
+ switch (retval) {
+ case nlm4_granted:
+ /* case nlm_granted: is the same as nlm4_granted */
+ case nlm4_blocked:
+ /* case nlm_blocked: is the same as nlm4_blocked */
+ do_mon(lckarg->alock.caller_name);
+ break;
+ default:
+ lfree(newfl);
+ break;
+ }
+ sigunlock();
+ return retval;
+}
+
+/* unlock a filehandle */
+enum nlm_stats
+unlock(lck, flags)
+ nlm4_lock *lck;
+ int flags;
+{
+ struct file_lock *fl;
+ fhandle_t filehandle;
+ int err = (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
+
+ memcpy(&filehandle, lck->fh.n_bytes, sizeof(fhandle_t));
+ siglock();
+ for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
+ fl = LIST_NEXT(fl, lcklst)) {
+ if (strcmp(fl->client_name, lck->caller_name) ||
+ memcmp(&filehandle, &fl->filehandle, sizeof(fhandle_t)) ||
+ fl->client.oh.n_len != lck->oh.n_len ||
+ memcmp(fl->client.oh.n_bytes, lck->oh.n_bytes,
+ fl->client.oh.n_len) != 0 ||
+ fl->client.svid != lck->svid)
+ continue;
+ /* Got it, unlock and remove from the queue */
+ syslog(LOG_DEBUG, "unlock from %s: found struct, status %d",
+ lck->caller_name, fl->status);
+ switch (fl->status) {
+ case LKST_LOCKED:
+ err = do_unlock(fl);
+ break;
+ case LKST_WAITING:
+ /* remove from the list */
+ LIST_REMOVE(fl, lcklst);
+ lfree(fl);
+ break;
+ case LKST_PROCESSING:
+ /*
+ * being handled by a child; will clean up
+ * when the child exits
+ */
+ fl->status = LKST_DYING;
+ break;
+ case LKST_DYING:
+ /* nothing to do */
+ break;
+ default:
+ syslog(LOG_NOTICE, "unknow status %d for %s",
+ fl->status, fl->client_name);
+ }
+ sigunlock();
+ return err;
+ }
+ sigunlock();
+ /* didn't find a matching entry; log anyway */
+ syslog(LOG_NOTICE, "no matching entry for %s",
+ lck->caller_name);
+ return (flags & LOCK_V4) ? nlm4_granted : nlm_granted;
+}
+
+void
+lfree(fl)
+ struct file_lock *fl;
+{
+ free(fl->client.oh.n_bytes);
+ free(fl->client_cookie.n_bytes);
+ free(fl);
+}
+
+void
+sigchild_handler(sig)
+ int sig;
+{
+ int status;
+ pid_t pid;
+ struct file_lock *fl;
+
+ while (1) {
+ pid = wait4(-1, &status, WNOHANG, NULL);
+ if (pid == -1) {
+ if (errno != ECHILD)
+ syslog(LOG_NOTICE, "wait failed: %s",
+ strerror(errno));
+ else
+ syslog(LOG_DEBUG, "wait failed: %s",
+ strerror(errno));
+ return;
+ }
+ if (pid == 0) {
+ /* no more child to handle yet */
+ return;
+ }
+ /*
+ * if we're here we have a child that exited
+ * Find the associated file_lock.
+ */
+ for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
+ fl = LIST_NEXT(fl, lcklst)) {
+ if (pid == fl->locker)
+ break;
+ }
+ if (pid != fl->locker) {
+ syslog(LOG_NOTICE, "unknow child %d", pid);
+ } else {
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ syslog(LOG_NOTICE, "child %d failed", pid);
+ /*
+ * can't do much here; we can't reply
+ * anything but OK for blocked locks
+ * Eventually the client will time out
+ * and retry.
+ */
+ do_unlock(fl);
+ return;
+ }
+
+ /* check lock status */
+ syslog(LOG_DEBUG, "processing child %d, status %d",
+ pid, fl->status);
+ switch(fl->status) {
+ case LKST_PROCESSING:
+ fl->status = LKST_LOCKED;
+ send_granted(fl, (fl->flags & LOCK_V4) ?
+ nlm4_granted : nlm_granted);
+ break;
+ case LKST_DYING:
+ do_unlock(fl);
+ break;
+ default:
+ syslog(LOG_NOTICE, "bad lock status (%d) for"
+ " child %d", fl->status, pid);
+ }
+ }
+ }
+}
+
+/*
+ *
+ * try to aquire the lock described by fl. Eventually fock a child to do a
+ * blocking lock if allowed and required.
+ */
+
+enum nlm_stats
+do_lock(fl, block)
+ struct file_lock *fl;
+ int block;
+{
+ int lflags, error;
+ struct stat st;
+
+ fl->fd = fhopen(&fl->filehandle, O_RDWR);
+ if (fl->fd < 0) {
+ switch (errno) {
+ case ESTALE:
+ error = nlm4_stale_fh;
+ break;
+ case EROFS:
+ error = nlm4_rofs;
+ break;
+ default:
+ error = nlm4_failed;
+ }
+ if ((fl->flags & LOCK_V4) == 0)
+ error = nlm_denied;
+ syslog(LOG_NOTICE, "fhopen failed (from %s): %s",
+ fl->client_name, strerror(errno));
+ LIST_REMOVE(fl, lcklst);
+ return error;;
+ }
+ if (fstat(fl->fd, &st) < 0) {
+ syslog(LOG_NOTICE, "fstat failed (from %s): %s",
+ fl->client_name, strerror(errno));
+ }
+ syslog(LOG_DEBUG, "lock from %s for file%s%s: dev %d ino %d (uid %d), "
+ "flags %d",
+ fl->client_name, fl->client.exclusive ? " (exclusive)":"",
+ block ? " (block)":"",
+ st.st_dev, st.st_ino, st.st_uid, fl->flags);
+ lflags = LOCK_NB;
+ if (fl->client.exclusive == 0)
+ lflags |= LOCK_SH;
+ else
+ lflags |= LOCK_EX;
+ error = flock(fl->fd, lflags);
+ if (error != 0 && errno == EAGAIN && block) {
+ switch (fl->locker = fork()) {
+ case -1: /* fork failed */
+ syslog(LOG_NOTICE, "fork failed: %s", strerror(errno));
+ LIST_REMOVE(fl, lcklst);
+ close(fl->fd);
+ return (fl->flags & LOCK_V4) ?
+ nlm4_denied_nolock : nlm_denied_nolocks;
+ case 0:
+ /*
+ * Attempt a blocking lock. Will have to call
+ * NLM_GRANTED later.
+ */
+ setproctitle("%s", fl->client_name);
+ lflags &= ~LOCK_NB;
+ if(flock(fl->fd, lflags) != 0) {
+ syslog(LOG_NOTICE, "flock failed: %s",
+ strerror(errno));
+ exit(-1);
+ }
+ /* lock granted */
+ exit(0);
+ default:
+ syslog(LOG_DEBUG, "lock request from %s: forked %d",
+ fl->client_name, fl->locker);
+ fl->status = LKST_PROCESSING;
+ return (fl->flags & LOCK_V4) ?
+ nlm4_blocked : nlm_blocked;
+ }
+ }
+ /* non block case */
+ if (error != 0) {
+ switch (errno) {
+ case EAGAIN:
+ error = nlm4_denied;
+ break;
+ case ESTALE:
+ error = nlm4_stale_fh;
+ break;
+ case EROFS:
+ error = nlm4_rofs;
+ break;
+ default:
+ error = nlm4_failed;
+ }
+ if ((fl->flags & LOCK_V4) == 0)
+ error = nlm_denied;
+ if (errno != EAGAIN)
+ syslog(LOG_NOTICE, "flock for %s failed: %s",
+ fl->client_name, strerror(errno));
+ else syslog(LOG_DEBUG, "flock for %s failed: %s",
+ fl->client_name, strerror(errno));
+ LIST_REMOVE(fl, lcklst);
+ close(fl->fd);
+ return error;
+ }
+ fl->status = LKST_LOCKED;
+ return (fl->flags & LOCK_V4) ? nlm4_granted : nlm_granted;
+}
+
+void
+send_granted(fl, opcode)
+ struct file_lock *fl;
+ int opcode;
+{
+ CLIENT *cli;
+ static char dummy;
+ struct timeval timeo;
+ int success;
+ static struct nlm_res retval;
+ static struct nlm4_res retval4;
+
+ cli = get_client(fl->addr,
+ (fl->flags & LOCK_V4) ? NLM_VERS4 : NLM_VERS);
+ if (cli == NULL) {
+ syslog(LOG_NOTICE, "failed to get CLIENT for %s",
+ fl->client_name);
+ /*
+ * We fail to notify remote that the lock has been granted.
+ * The client will timeout and retry, the lock will be
+ * granted at this time.
+ */
+ return;
+ }
+ timeo.tv_sec = 0;
+ timeo.tv_usec = (fl->flags & LOCK_ASYNC) ? 0 : 500000; /* 0.5s */
+
+ if (fl->flags & LOCK_V4) {
+ static nlm4_testargs res;
+ res.cookie = fl->client_cookie;
+ res.exclusive = fl->client.exclusive;
+ res.alock.caller_name = fl->client_name;
+ res.alock.fh.n_len = sizeof(fhandle_t);
+ res.alock.fh.n_bytes = (char*)&fl->filehandle;
+ res.alock.oh = fl->client.oh;
+ res.alock.svid = fl->client.svid;
+ res.alock.l_offset = fl->client.l_offset;
+ res.alock.l_len = fl->client.l_len;
+ syslog(LOG_DEBUG, "sending v4 reply%s",
+ (fl->flags & LOCK_ASYNC) ? " (async)":"");
+ if (fl->flags & LOCK_ASYNC) {
+ success = clnt_call(cli, NLM4_GRANTED_MSG,
+ xdr_nlm4_testargs, &res, xdr_void, &dummy, timeo);
+ } else {
+ success = clnt_call(cli, NLM4_GRANTED,
+ xdr_nlm4_testargs, &res, xdr_nlm4_res,
+ &retval4, timeo);
+ }
+ } else {
+ static nlm_testargs res;
+
+ res.cookie = fl->client_cookie;
+ res.exclusive = fl->client.exclusive;
+ res.alock.caller_name = fl->client_name;
+ res.alock.fh.n_len = sizeof(fhandle_t);
+ res.alock.fh.n_bytes = (char*)&fl->filehandle;
+ res.alock.oh = fl->client.oh;
+ res.alock.svid = fl->client.svid;
+ res.alock.l_offset = fl->client.l_offset;
+ res.alock.l_len = fl->client.l_len;
+ syslog(LOG_DEBUG, "sending v1 reply%s",
+ (fl->flags & LOCK_ASYNC) ? " (async)":"");
+ if (fl->flags & LOCK_ASYNC) {
+ success = clnt_call(cli, NLM_GRANTED_MSG,
+ xdr_nlm_testargs, &res, xdr_void, &dummy, timeo);
+ } else {
+ success = clnt_call(cli, NLM_GRANTED,
+ xdr_nlm_testargs, &res, xdr_nlm_res,
+ &retval, timeo);
+ }
+ }
+ if (debug_level > 2)
+ syslog(LOG_DEBUG, "clnt_call returns %d(%s) for granted",
+ success, clnt_sperrno(success));
+
+}
+
+enum nlm_stats
+do_unlock(rfl)
+ struct file_lock *rfl;
+{
+ struct file_lock *fl;
+ int error;
+ int lockst;
+
+ /* unlock the file: closing is enouth ! */
+ if (close(rfl->fd) < 0) {
+ if (errno == ESTALE)
+ error = nlm4_stale_fh;
+ else
+ error = nlm4_failed;
+ if ((fl->flags & LOCK_V4) == 0)
+ error = nlm_denied;
+ syslog(LOG_NOTICE,
+ "close failed (from %s): %s",
+ rfl->client_name, strerror(errno));
+ } else {
+ error = (fl->flags & LOCK_V4) ?
+ nlm4_granted : nlm_granted;
+ }
+ LIST_REMOVE(rfl, lcklst);
+
+ /* process the next LKST_WAITING lock request for this fh */
+ for (fl = LIST_FIRST(&lcklst_head); fl != NULL;
+ fl = LIST_NEXT(fl, lcklst)) {
+ if (fl->status != LKST_WAITING ||
+ memcmp(&rfl->filehandle, &fl->filehandle,
+ sizeof(fhandle_t)) != 0)
+ continue;
+
+ lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */
+ switch (lockst) {
+ case nlm4_granted:
+ /* case nlm_granted: same as nlm4_granted */
+ send_granted(fl, (fl->flags & LOCK_V4) ?
+ nlm4_granted : nlm_granted);
+ break;
+ case nlm4_blocked:
+ /* case nlm_blocked: same as nlm4_blocked */
+ break;
+ default:
+ lfree(fl);
+ break;
+ }
+ break;
+ }
+ return error;
+}
+
+void
+siglock()
+{
+ sigset_t block;
+
+ sigemptyset(&block);
+ sigaddset(&block, SIGCHLD);
+
+ if (sigprocmask(SIG_BLOCK, &block, NULL) < 0) {
+ syslog(LOG_WARNING, "siglock failed: %s", strerror(errno));
+ }
+}
+
+void
+sigunlock()
+{
+ sigset_t block;
+
+ sigemptyset(&block);
+ sigaddset(&block, SIGCHLD);
+
+ if (sigprocmask(SIG_UNBLOCK, &block, NULL) < 0) {
+ syslog(LOG_WARNING, "sigunlock failed: %s", strerror(errno));
+ }
+}
+
+/* monitor a host through rpc.statd, and keep a ref count */
+void
+do_mon(hostname)
+ char *hostname;
+{
+ struct host *hp;
+ struct mon my_mon;
+ struct sm_stat_res res;
+ int retval;
+
+ for (hp = LIST_FIRST(&hostlst_head); hp != NULL;
+ hp = LIST_NEXT(hp, hostlst)) {
+ if (strcmp(hostname, hp->name) == 0) {
+ /* already monitored, just bump refcnt */
+ hp->refcnt++;
+ return;
+ }
+ }
+ /* not found, have to create an entry for it */
+ hp = malloc(sizeof(struct host));
+ strncpy(hp->name, hostname, SM_MAXSTRLEN);
+ hp->refcnt = 1;
+ syslog(LOG_DEBUG, "monitoring host %s",
+ hostname);
+ memset(&my_mon, 0, sizeof(my_mon));
+ my_mon.mon_id.mon_name = hp->name;
+ my_mon.mon_id.my_id.my_name = "localhost";
+ my_mon.mon_id.my_id.my_prog = NLM_PROG;
+ my_mon.mon_id.my_id.my_vers = NLM_SM;
+ my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
+ if ((retval =
+ callrpc("localhost", SM_PROG, SM_VERS, SM_MON, xdr_mon,
+ (char*)&my_mon, xdr_sm_stat_res, (char*)&res)) != 0) {
+ syslog(LOG_WARNING, "rpc to statd failed: %s",
+ clnt_sperrno((enum clnt_stat)retval));
+ free(hp);
+ return;
+ }
+ if (res.res_stat == stat_fail) {
+ syslog(LOG_WARNING, "statd failed");
+ free(hp);
+ return;
+ }
+ LIST_INSERT_HEAD(&hostlst_head, hp, hostlst);
+}
+
+void
+notify(hostname, state)
+ char *hostname;
+ int state;
+{
+ struct file_lock *fl, *next_fl;
+ int err;
+ syslog(LOG_DEBUG, "notify from %s, new state %d", hostname, state);
+ /* search all lock for this host; if status changed, release the lock */
+ siglock();
+ for (fl = LIST_FIRST(&lcklst_head); fl != NULL; fl = next_fl) {
+ next_fl = LIST_NEXT(fl, lcklst);
+ if (strcmp(hostname, fl->client_name) == 0 &&
+ fl->nsm_status != state) {
+ syslog(LOG_DEBUG, "state %d, nsm_state %d, unlocking",
+ fl->status, fl->nsm_status);
+ switch(fl->status) {
+ case LKST_LOCKED:
+ err = do_unlock(fl);
+ if (err != nlm_granted)
+ syslog(LOG_DEBUG,
+ "notify: unlock failed for %s (%d)",
+ hostname, err);
+ break;
+ case LKST_WAITING:
+ LIST_REMOVE(fl, lcklst);
+ lfree(fl);
+ break;
+ case LKST_PROCESSING:
+ fl->status = LKST_DYING;
+ break;
+ case LKST_DYING:
+ break;
+ default:
+ syslog(LOG_NOTICE, "unknow status %d for %s",
+ fl->status, fl->client_name);
+ }
+ }
+ }
+ sigunlock();
+}
diff --git a/usr.sbin/rpc.lockd/lockd_lock.h b/usr.sbin/rpc.lockd/lockd_lock.h
new file mode 100644
index 0000000..5b0232f
--- /dev/null
+++ b/usr.sbin/rpc.lockd/lockd_lock.h
@@ -0,0 +1,21 @@
+/* $NetBSD: lockd_lock.h,v 1.2 2000/06/09 14:00:54 fvdl Exp $ */
+/* $FreeBSD$ */
+
+/* Headers and function declarations for file-locking utilities */
+
+struct nlm4_holder * testlock __P((struct nlm4_lock *, int));
+
+enum nlm_stats getlock __P((nlm4_lockargs *, struct svc_req *, int));
+enum nlm_stats unlock __P((nlm4_lock *, int));
+void notify __P((char *, int));
+
+/* flags for testlock, getlock & unlock */
+#define LOCK_ASYNC 0x01 /* async version (getlock only) */
+#define LOCK_V4 0x02 /* v4 version */
+#define LOCK_MON 0x04 /* monitored lock (getlock only) */
+#define LOCK_CANCEL 0x08 /* cancel, not unlock request (unlock only) */
+
+/* callbacks from lock_proc.c */
+void transmit_result __P((int, nlm_res *, struct sockaddr *));
+void transmit4_result __P((int, nlm4_res *, struct sockaddr *));
+CLIENT *get_client __P((struct sockaddr *, rpcvers_t));
diff --git a/usr.sbin/rpc.lockd/rpc.lockd.8 b/usr.sbin/rpc.lockd/rpc.lockd.8
index 2438aacf..e87f5bb 100644
--- a/usr.sbin/rpc.lockd/rpc.lockd.8
+++ b/usr.sbin/rpc.lockd/rpc.lockd.8
@@ -1,4 +1,5 @@
-.\" -*- nroff -*-
+.\" $NetBSD: rpc.lockd.8,v 1.5 2000/06/09 18:51:47 cgd Exp $
+.\" $FreeBSD$
.\"
.\" Copyright (c) 1995 A.R.Gordon, andrew.gordon@net-tel.co.uk
.\" All rights reserved.
@@ -31,7 +32,6 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD$
.\"
.Dd September 24, 1995
.Dt RPC.LOCKD 8
@@ -41,34 +41,64 @@
.Nd NFS file locking daemon
.Sh SYNOPSIS
.Nm
-.Op Fl d Op Ar debug_level
+.Op Fl d Ar debug_level
+.Op Fl g Ar grace period
.Sh DESCRIPTION
-.Nm Rpc.lockd
-is a daemon which provides file- and record-locking services in an NFS
-environment.
+The
+.Nm
+daemon provides monitored and unmonitored file and record locking services
+in an NFS environment.
+To monitor the status of hosts requesting locks,
+the locking daemon typically operates in conjunction
+with
+.Xr rpc.statd 8 .
.Pp
-The following option is available:
+Options and operands available for
+.Nm :
.Bl -tag -width indent
.It Fl d
-Cause debugging information to be written to syslog, recording
-all RPC transactions to the daemon. These messages are logged with level
-LOG_DEBUG and facility LOG_DAEMON. If debug_level is not specified,
-level 1 is assumed, giving one log line per protocol operation. Higher
+The
+.Fl d
+option causes debugging information to be written to syslog, recording
+all RPC transactions to the daemon.
+These messages are logged with level
+.Dv LOG_DEBUG
+and facility
+.Dv LOG_DAEMON .
+Specifying a
+.Ar debug_level
+of 1 results
+in the generation of one log line per protocol operation.
+Higher
debug levels can be specified, causing display of operation arguments
and internal operations of the daemon.
+.It Fl g
+The
+.Fl g
+option allow to specify the
+.Ar grace period ,
+in seconds.
+During the grace period
+.Nm
+only accepts requests from hosts which are reinitialising locks which
+existed before the server restart.
+Default is 30 seconds.
.El
.Pp
Error conditions are logged to syslog, irrespective of the debug level,
-using log level LOG_ERR and facility LOG_DAEMON.
+using log level
+.Dv LOG_ERR
+and facility
+.Dv LOG_DAEMON .
.Pp
The
.Nm
daemon must NOT be invoked by
.Xr inetd 8
because the protocol assumes that the daemon will run from system start time.
-Instead, it should be run from
-.Xr rc 8
-after the network has been started.
+Instead, it should be configured in
+.Xr rc.conf 5
+to run at system startup.
.Sh FILES
.Bl -tag -width /usr/include/rpcsvc/nlm_prot.x -compact
.It Pa /usr/include/rpcsvc/nlm_prot.x
@@ -76,21 +106,32 @@ RPC protocol specification for the network lock manager protocol.
.El
.Sh SEE ALSO
.Xr syslog 3 ,
-.Xr rc 8 ,
+.Xr rc.conf 5 ,
.Xr rpc.statd 8
.Sh BUGS
The current implementation provides only the server side of the protocol
-(ie. clients running other OS types can establish locks on a
+(i.e., clients running other OS types can establish locks on a
.Fx
+/
+.Nx
fileserver,
but there is currently no means for a
.Fx
+/
+.Nx
client to establish locks).
.Pp
-Versions 1, 2 and 3 of the protocol are supported. However, only versions
-2 (Unix systems) and 3 (PC-NFS clients) seem to be in common use - the version
-1 support has not been tested due to the lack of version 1 clients against
-which to test.
+The current implementation serialises locks requests that could be shared.
.Sh STANDARDS
-The implementation is based on the specification in X/Open CAE Specification
-C218, "Protocols for X/Open PC Interworking: XNFS, Issue 4", ISBN 1 872630 66 9
+The implementation is based on the specification in
+.Rs
+.%B "X/Open CAE Specification C218"
+.%T "Protocols for X/Open PC Interworking: XNFS, Issue 4"
+.%O ISBN 1 872630 66 9
+.Re
+.Sh HISTORY
+A version of
+.Nm
+appeared in
+.Tn SunOS
+4.
diff --git a/usr.sbin/rpc.lockd/test.c b/usr.sbin/rpc.lockd/test.c
index 0dd8eae..a751e5c 100644
--- a/usr.sbin/rpc.lockd/test.c
+++ b/usr.sbin/rpc.lockd/test.c
@@ -1,14 +1,17 @@
+/* $NetBSD: test.c,v 1.2 1997/10/18 04:01:21 lukem Exp $ */
+
+#include <sys/cdefs.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/nlm_prot.h>
#ifndef lint
#if 0
static char sccsid[] = "from: @(#)nlm_prot.x 1.8 87/09/21 Copyr 1987 Sun Micro";
static char sccsid[] = "from: * @(#)nlm_prot.x 2.1 88/08/01 4.0 RPCSRC";
+#else
+__RCSID("$NetBSD: test.c,v 1.2 1997/10/18 04:01:21 lukem Exp $");
+static const char rcsid[] = "$FreeBSD$";
#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <rpc/rpc.h>
-#include <rpcsvc/nlm_prot.h>
+#endif /* not lint */
/* Default timeout can be changed using clnt_control() */
static struct timeval TIMEOUT = { 0, 0 };
@@ -304,63 +307,59 @@ nlm_free_all_3(argp, clnt)
int main(int argc, char **argv)
{
- CLIENT *cli;
- nlm_res res_block;
- nlm_res *out;
- nlm_lockargs arg;
- struct timeval tim;
-
- printf("Creating client for host %s\n", argv[1]);
- cli = clnt_create(argv[1], NLM_PROG, NLM_VERS, "udp");
- if (!cli)
- {
- printf("Failed to create client\n");
- exit(1);
- }
-
-
- clnt_control(cli, CLGET_TIMEOUT, &tim);
- printf("Default timeout was %d.%d\n", tim.tv_sec, tim.tv_usec);
- tim.tv_usec = -1;
- tim.tv_sec = -1;
- clnt_control(cli, CLSET_TIMEOUT, &tim);
- clnt_control(cli, CLGET_TIMEOUT, &tim);
- printf("timeout now %d.%d\n", tim.tv_sec, tim.tv_usec);
-
-
- arg.cookie.n_len = 4;
- arg.cookie.n_bytes = "hello";
- arg.block = 0;
- arg.exclusive = 0;
- arg.reclaim = 0;
- arg.state = 0x1234;
- arg.alock.caller_name = "localhost";
- arg.alock.fh.n_len = 32;
- arg.alock.fh.n_bytes = "\x04\x04\x02\x00\x01\x00\x00\x00\x0c\x00\x00\x00\xff\xff\xff\xd0\x16\x00\x00\x5b\x7c\xff\xff\xff\xec\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x54\xef\xbf\xd7\x94";
- arg.alock.oh.n_len = 8;
- arg.alock.oh.n_bytes = "\x00\x00\x02\xff\xff\xff\xd3";
- arg.alock.svid = 0x5678;
- arg.alock.l_offset = 0;
- arg.alock.l_len = 100;
-
- res_block.stat.stat = nlm_granted;
- res_block.cookie.n_bytes = "hello";
- res_block.cookie.n_len = 5;
+ CLIENT *cli;
+ nlm_res res_block;
+ nlm_res *out;
+ nlm_lockargs arg;
+ struct timeval tim;
+
+ printf("Creating client for host %s\n", argv[1]);
+ cli = clnt_create(argv[1], NLM_PROG, NLM_VERS, "udp");
+ if (!cli) {
+ errx(1, "Failed to create client\n");
+ /* NOTREACHED */
+ }
+ clnt_control(cli, CLGET_TIMEOUT, &tim);
+ printf("Default timeout was %d.%d\n", tim.tv_sec, tim.tv_usec);
+ tim.tv_usec = -1;
+ tim.tv_sec = -1;
+ clnt_control(cli, CLSET_TIMEOUT, &tim);
+ clnt_control(cli, CLGET_TIMEOUT, &tim);
+ printf("timeout now %d.%d\n", tim.tv_sec, tim.tv_usec);
+
+
+ arg.cookie.n_len = 4;
+ arg.cookie.n_bytes = "hello";
+ arg.block = 0;
+ arg.exclusive = 0;
+ arg.reclaim = 0;
+ arg.state = 0x1234;
+ arg.alock.caller_name = "localhost";
+ arg.alock.fh.n_len = 32;
+ arg.alock.fh.n_bytes = "\x04\x04\x02\x00\x01\x00\x00\x00\x0c\x00\x00\x00\xff\xff\xff\xd0\x16\x00\x00\x5b\x7c\xff\xff\xff\xec\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x54\xef\xbf\xd7\x94";
+ arg.alock.oh.n_len = 8;
+ arg.alock.oh.n_bytes = "\x00\x00\x02\xff\xff\xff\xd3";
+ arg.alock.svid = 0x5678;
+ arg.alock.l_offset = 0;
+ arg.alock.l_len = 100;
+
+ res_block.stat.stat = nlm_granted;
+ res_block.cookie.n_bytes = "hello";
+ res_block.cookie.n_len = 5;
#if 0
- if (nlm_lock_res_1(&res_block, cli)) printf("Success!\n");
- else printf("Fail\n");
+ if (nlm_lock_res_1(&res_block, cli))
+ printf("Success!\n");
+ else
+ printf("Fail\n");
#else
- if (out = nlm_lock_msg_1(&arg, cli))
- {
- printf("Success!\n");
- printf("out->stat = %d", out->stat);
- }
- else
- {
- printf("Fail\n");
- }
+ if (out = nlm_lock_msg_1(&arg, cli)) {
+ printf("Success!\n");
+ printf("out->stat = %d", out->stat);
+ } else {
+ printf("Fail\n");
+ }
#endif
- return 0;
+ return 0;
}
diff --git a/usr.sbin/rpc.statd/statd.h b/usr.sbin/rpc.statd/statd.h
index 7b4e659..7bf7b1d 100644
--- a/usr.sbin/rpc.statd/statd.h
+++ b/usr.sbin/rpc.statd/statd.h
@@ -29,26 +29,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
+ * $FreeBSD$
*/
#include "sm_inter.h"
-/* These pieces are missing from the distributed sm_inter.x, which */
-/* omits the SM_NOTIFY procedure used between cooperating rpc.statd's */
-
-#define SM_NOTIFY ((u_long)6)
-extern void *sm_notify_1();
-
-struct stat_chge
-{
- char *mon_name;
- int state;
-};
-typedef struct stat_chge stat_chge;
-bool_t xdr_stat_chge();
-
/* ------------------------------------------------------------------------- */
/*
Data structures for recording monitored hosts
diff --git a/usr.sbin/rpc.umntall/rpc.umntall.c b/usr.sbin/rpc.umntall/rpc.umntall.c
index c59c776..5129ba9 100644
--- a/usr.sbin/rpc.umntall/rpc.umntall.c
+++ b/usr.sbin/rpc.umntall/rpc.umntall.c
@@ -171,28 +171,23 @@ main(int argc, char **argv) {
int
do_umntall(char *hostname) {
enum clnt_stat clnt_stat;
- struct hostent *hp;
- struct sockaddr_in saddr;
- struct timeval pertry, try;
- int so;
+ struct addrinfo *ai, hints;
+ struct timeval try;
+ int so, ecode;
CLIENT *clp;
- if ((hp = gethostbyname(hostname)) == NULL) {
- warnx("gethostbyname(%s) failed", hostname);
- return (0);
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_NUMERICHOST;
+ ecode = getaddrinfo(hostname, NULL, &hints, &ai);
+ if (ecode != 0) {
+ warnx("can't get net id for host/nfs: %s",
+ gai_strerror(ecode));
+ return (1);
}
- memset(&saddr, 0, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = 0;
- memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
- sizeof(saddr.sin_addr)));
- pertry.tv_sec = 3;
- pertry.tv_usec = 0;
- so = RPC_ANYSOCK;
- if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
- pertry, &so)) == NULL) {
- clnt_pcreateerror("Cannot send MNT PRC");
- return (0);
+ clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp");
+ if (clp == NULL) {
+ clnt_pcreateerror("Cannot MNT PRC");
+ return (1);
}
clp->cl_auth = authunix_create_default();
try.tv_sec = 3;
@@ -212,30 +207,25 @@ do_umntall(char *hostname) {
int
do_umount(char *hostname, char *dirp) {
enum clnt_stat clnt_stat;
- struct hostent *hp;
- struct sockaddr_in saddr;
- struct timeval pertry, try;
+ struct addrinfo *ai, hints;
+ struct timeval try;
CLIENT *clp;
- int so;
+ int so, ecode;
- if ((hp = gethostbyname(hostname)) == NULL) {
- warnx("gethostbyname(%s) failed", hostname);
- return (0);
+ memset(&hints, 0, sizeof hints);
+ hints.ai_flags = AI_NUMERICHOST;
+ ecode = getaddrinfo(hostname, NULL, &hints, &ai);
+ if (ecode != 0) {
+ warnx("can't get net id for host/nfs: %s",
+ gai_strerror(ecode));
+ return (1);
}
- memset(&saddr, 0, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = 0;
- memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
- sizeof(saddr.sin_addr)));
- pertry.tv_sec = 3;
- pertry.tv_usec = 0;
- so = RPC_ANYSOCK;
- if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
- pertry, &so)) == NULL) {
- clnt_pcreateerror("Cannot send MNT PRC");
- return (0);
+ clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp");
+ if (clp == NULL) {
+ clnt_pcreateerror("Cannot MNT PRC");
+ return (1);
}
- clp->cl_auth = authunix_create_default();
+ clp->cl_auth = authsys_create_default();
try.tv_sec = 3;
try.tv_usec = 0;
clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp,
diff --git a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c
index 03b4825..51f9621 100644
--- a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c
+++ b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c
@@ -298,7 +298,18 @@ the %s domain -- aborting", yppasswd_domain);
}
unlink(sockname);
- transp = svcunix_create(sock, 0, 0, sockname);
+ if (svc_create(yppasswdprog_1, YPPASSWDPROG, YPPASSWDVERS,
+ "netpath") == 0) {
+ (void) fprintf(stderr,
+ "%s: unable to create service\n", argv[0]);
+ exit(1);
+ }
+ if (svc_create(master_yppasswdprog_1, MASTER_YPPASSWDPROG,
+ MASTER_YPPASSWDVERS, "netpath") == 0) {
+ (void) fprintf(stderr,
+ "%s: unable to create service\n", argv[0]);
+ exit(1);
+ }
if (transp == NULL) {
yp_error("cannot create AF_LOCAL service.");
exit(1);
diff --git a/usr.sbin/rpc.ypupdated/ypupdated_extern.h b/usr.sbin/rpc.ypupdated/ypupdated_extern.h
index 28ea7ac..17e9ee9 100644
--- a/usr.sbin/rpc.ypupdated/ypupdated_extern.h
+++ b/usr.sbin/rpc.ypupdated/ypupdated_extern.h
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
#include <db.h>
#define YPOP_CHANGE 1 /* change, do not add */
diff --git a/usr.sbin/rpc.ypupdated/ypupdated_server.c b/usr.sbin/rpc.ypupdated/ypupdated_server.c
index f0c5bff..b306268 100644
--- a/usr.sbin/rpc.ypupdated/ypupdated_server.c
+++ b/usr.sbin/rpc.ypupdated/ypupdated_server.c
@@ -43,7 +43,6 @@ static const char rcsid[] =
#include <stdio.h>
#include <rpc/rpc.h>
-#include <rpc/auth_des.h>
#include <rpc/key_prot.h>
#include <sys/param.h>
#include <sys/cdefs.h>
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
+}
diff --git a/usr.sbin/ypbind/yp_ping.c b/usr.sbin/ypbind/yp_ping.c
index 558843f..744eda0 100644
--- a/usr.sbin/ypbind/yp_ping.c
+++ b/usr.sbin/ypbind/yp_ping.c
@@ -310,7 +310,7 @@ get_reply:
} /* end successful completion */
else {
/* maybe our credentials need to be refreshed ... */
- if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
+ if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth, &reply_msg)) {
nrefreshes--;
goto call_again;
}
@@ -502,7 +502,7 @@ int __yp_ping(restricted_addrs, cnt, dom, port)
clnt->cl_auth = authunix_create_default();
cu = (struct cu_data *)clnt->cl_private;
tv.tv_sec = 0;
- clnt_control(clnt, CLSET_TIMEOUT, &tv);
+ clnt_control(clnt, CLSET_TIMEOUT, (char *)&tv);
ioctl(sock, FIONBIO, &dontblock);
oldfunc = clnt->cl_ops->cl_call;
clnt->cl_ops->cl_call = clntudp_a_call;
diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c
index d6e5e2be..5304422 100644
--- a/usr.sbin/ypbind/ypbind.c
+++ b/usr.sbin/ypbind/ypbind.c
@@ -743,7 +743,7 @@ struct _dom_binding *ypdb;
ptr = (char *)&ypdb->dom_domain;
stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK,
xdr_domainname, (char *)&ptr, xdr_bool, (char *)&out,
- broadcast_result);
+ (resultproc_t)broadcast_result);
}
if (stat != RPC_SUCCESS) {
diff --git a/usr.sbin/yppush/yppush_main.c b/usr.sbin/yppush/yppush_main.c
index 39b5bdf..ba25dda 100644
--- a/usr.sbin/yppush/yppush_main.c
+++ b/usr.sbin/yppush/yppush_main.c
@@ -415,7 +415,7 @@ int yp_push(server, map, tid)
job->stat = 0;
job->tid = tid;
job->port = xprt->xp_port;
- job->sock = xprt->xp_sock; /*XXX: Evil!! EEEEEEEVIL!!! */
+ job->sock = xprt->xp_fd; /*XXX: Evil!! EEEEEEEVIL!!! */
job->server = strdup(server);
job->map = strdup(map);
job->prognum = prognum;
@@ -437,8 +437,8 @@ int yp_push(server, map, tid)
* 2) Even in this day and age, there are still some *NIXes
* that don't support async socket I/O.
*/
- if (fcntl(xprt->xp_sock, F_SETOWN, getpid()) == -1 ||
- fcntl(xprt->xp_sock, F_SETFL, O_ASYNC) == -1) {
+ if (fcntl(xprt->xp_fd, F_SETOWN, getpid()) == -1 ||
+ fcntl(xprt->xp_fd, F_SETFL, O_ASYNC) == -1) {
yp_error("failed to set async I/O mode: %s",
strerror(errno));
yppush_exit(1);
diff --git a/usr.sbin/ypserv/yp_dnslookup.c b/usr.sbin/ypserv/yp_dnslookup.c
index 5aa03e7..fdbac25 100644
--- a/usr.sbin/ypserv/yp_dnslookup.c
+++ b/usr.sbin/ypserv/yp_dnslookup.c
@@ -434,7 +434,7 @@ ypstat yp_async_lookup_name(rqstp, name)
/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
type = -1; len = sizeof(type);
- if (getsockopt(rqstp->rq_xprt->xp_sock, SOL_SOCKET,
+ if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
SO_TYPE, &type, &len) == -1) {
yp_error("getsockopt failed: %s", strerror(errno));
return(YP_YPERR);
@@ -490,7 +490,7 @@ ypstat yp_async_lookup_addr(rqstp, addr)
/* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
type = -1; len = sizeof(type);
- if (getsockopt(rqstp->rq_xprt->xp_sock, SOL_SOCKET,
+ if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
SO_TYPE, &type, &len) == -1) {
yp_error("getsockopt failed: %s", strerror(errno));
return(YP_YPERR);
OpenPOWER on IntegriCloud