--- /dev/null
+@(#) BLURB 1.5 96/07/06 23:09:45
+
+This is the fifth replacement portmapper release.
+
+There is an increasing interest in access control for the NIS, mount
+and other RPC-based services that are normally registered with the
+portmap process. Possible attacks on RPC daemons involve:
+
+ - theft of NIS (YP) password files
+
+ - ypset to force hosts to bind to a rogue NIS (YP) server
+
+ - theft of NFS file handles
+
+My contribution is a replacement portmap program, derived from source
+code in the RPCSRC 4.0 and the TIRPC source distributions. Access
+control (optional) is in the style of my tcp wrapper (log_tcp) package.
+
+Supported platforms: this program is known to work with all SunOS 4.x
+releases. With some Makefile editing it should also work on Ultrix 4.x,
+HP-UX 9.x, AIX 3.x and AIX 4.x, and Digital UNIX (OSF/1).
+
+Solaris 2.x and other System V.4 UNIXes should use use my rpcbind
+replacement (ftp.win.tue.nl:/pub/security/rpcbind_*.tar.Z).
+
+This portmap version attempts to close all portmap security problems
+that are known to me. The README file gives a complete list of
+security features.
+
+Without the availability of portmap source, possible alternatives are
+1) packet filtering with a smart router (which we do anyway); 2)
+linking the portmap executable against the securelib shared library.
+Linking RPC daemons against the securelib library is a good idea,
+anyway.
+
+The source is available for anonymous FTP from ftp.win.tue.nl directory
+/pub/security/portmap_*.tar.gz.
+
+ Wietse Venema (wietse@wzv.win.tue.nl)
+ Mathematics and Computing Science
+ Eindhoven University of Technology
+ The Netherlands
--- /dev/null
+@(#) CHANGES 1.2 96/07/06 23:06:17
+
+Changes with release 5 (July 1996)
+
+Unprivileged clients can no longer unset or set the nfsd port.
+
+The really desperate can force all set/unset requests to arrive via the
+loopback interface and block set/unset requests from outside. Besides
+changes to the portmapper, this requires changes to system libraries,
+to statically linked rpc servers, to the kernel configuration (no IP
+source routing), and perhaps even to system startup procedures. Not for
+the faint of hart.
+
+Changes with release 4 (May 1996)
+
+The old code could not handle more than 16 interface addresses per
+host. With virtual hosting, a system can have more than 16 addresses.
+We now allocate memory dynamically.
+
+Support for AIX 4.1. Just like 4.4 BSD, it has variable-length sockaddr
+structures. Build with -DHAS_SA_LEN.
+
+Support for NextStep 3.2. This is a pre-posix system without setsid().
+
+Support for Digital UNIX on the Alpha. On these machines, long and int
+are not interchangeable.
--- /dev/null
+# @(#) Makefile 1.6 96/07/06 23:06:17
+
+####################################
+### Beginning of configurable stuff.
+
+# By default, logfile entries are written to the same file as used for
+# sendmail transaction logs. Change the definition of the following macro
+# if you disagree. See `man 3 syslog' for examples. Some syslog versions
+# do not provide this flexibility.
+#
+FACILITY=LOG_MAIL
+
+# To disable tcp-wrapper style access control, comment out the following
+# macro definitions. Access control can also be turned off by providing
+# no access control tables. The local system, since it runs the portmap
+# daemon, is always treated as an authorized host.
+
+HOSTS_ACCESS= -DHOSTS_ACCESS
+WRAP_LIB = $(WRAP_DIR)/libwrap.a
+
+# Comment out if your RPC library does not allocate privileged ports for
+# requests from processes with root privilege, or the new portmap will
+# always reject requests to register/unregister services on privileged
+# ports. You can find out by running "rpcinfo -p"; if all mountd and NIS
+# daemons use a port >= 1024 you should probably disable the next line.
+
+CHECK_PORT = -DCHECK_PORT
+
+# Warning: troublesome feature ahead!! Enable only when you are really
+# desperate!!
+#
+# It is possible to prevent an attacker from manipulating your portmapper
+# tables from outside with requests that contain spoofed source addresses.
+# The countermeasure is to force all rpc servers to register and
+# unregister with the portmapper via the loopback network interface,
+# instead of via the primary network interface that every host can talk
+# to. For this countermeasure to work it is necessary to uncomment the
+# LOOPBACK definition below, and to take the following additional steps:
+#
+# (1) Modify the libc library (or librpc if you have one) and replace
+# get_myaddress() by a version that selects the loopback address instead
+# of the primary network interface address. A suitable version is
+# provided in the file get_myaddress.c. This forces rpc servers to send
+# all set/unset requests to the loopback address.
+#
+# (2) Rebuild all statically-linked rpc servers with the modified
+# library.
+#
+# (3) Disable IP source routing in the kernel (otherwise an outside
+# attacker can still send requests that appear to come from the local
+# machine).
+#
+# Instead of (1) it may be sufficient to run the rpc servers with a
+# preload shared object that implements the alternate get_myaddress()
+# behavior (see Makefile.shlib). You still need to disable IP source
+# routing, though.
+#
+# I warned you, you need to be really desperate to do this. It is
+# probably much easier to just block port UDP and TCP ports 111 on
+# your routers.
+#
+# LOOPBACK = -DLOOPBACK_SETUNSET
+
+# When the portmapper cannot find any local interfaces (it will complain
+# to the syslog daemon) your system probably has variable-length socket
+# address structures (struct sockaddr has a sa_len component; examples:
+# AIX 4.1 and 4.4BSD). Uncomment next macro definition in that case.
+#
+# SA_LEN = -DHAS_SA_LEN # AIX 4.x, BSD 4.4, FreeBSD, NetBSD
+
+# With verbose logging on, HP-UX 9.x and AIX 4.1 leave zombies behind when
+# SIGCHLD is not ignored. Enable next macro for a fix.
+#
+# ZOMBIES = -DIGNORE_SIGCHLD # AIX 4.x, HP-UX 9.x
+
+# Uncomment the following macro if your system does not have u_long.
+#
+# ULONG =-Du_long="unsigned long"
+
+# Later versions of the tcp wrapper (log_tcp package) come with a
+# libwrap.a object library. WRAP_DIR should specify the directory with
+# that library.
+
+WRAP_DIR= ../tcp_wrappers
+
+# Auxiliary object files that may be missing from your C library.
+#
+AUX = daemon.o strerror.o
+
+# NEXTSTEP is a little different. The following seems to work with NS 3.2
+#
+# SETPGRP =-DUSE_SETPGRP00
+# LIBS = -m
+# NSARCHS = -arch m68k -arch i386 -arch hppa
+
+# Auxiliary libraries that you may have to specify
+#
+# LIBS = -lrpc
+
+# Comment out if your compiler talks ANSI and understands const
+#
+CONST = -Dconst=
+
+### End of configurable stuff.
+##############################
+
+SHELL = /bin/sh
+
+COPT = $(CONST) -Dperror=xperror $(HOSTS_ACCESS) $(CHECK_PORT) \
+ $(SYS) -DFACILITY=$(FACILITY) $(ULONG) $(ZOMBIES) $(SA_LEN) \
+ $(LOOPBACK) $(SETPGRP)
+CFLAGS = $(COPT) -O $(NSARCHS)
+OBJECTS = portmap.o pmap_check.o from_local.o $(AUX)
+
+all: portmap pmap_dump pmap_set
+
+portmap: $(OBJECTS) $(WRAP_DIR)/libwrap.a
+ $(CC) $(CFLAGS) -o $@ $(OBJECTS) $(WRAP_LIB) $(LIBS)
+
+pmap_dump: pmap_dump.c
+ $(CC) $(CFLAGS) -o $@ $? $(LIBS)
+
+pmap_set: pmap_set.c
+ $(CC) $(CFLAGS) -o $@ $? $(LIBS)
+
+from_local: from_local.c
+ cc $(CFLAGS) -DTEST -o $@ from_local.c
+
+get_myaddress: get_myaddress.c
+ cc $(CFLAGS) -DTEST -o $@ get_myaddress.c $(LIBS)
+
+lint:
+ lint $(COPT) $(OBJECTS:%.o=%.c)
+
+clean:
+ rm -f *.o portmap pmap_dump pmap_set from_local get_myaddress \
+ get_myaddress.so core
+
+tidy: clean
+ chmod 755 . ; chmod -R a+r .
+
+deps:
+ @$(CC) -M $(CFLAGS) *.c | grep -v /usr/include |sed 's/\.\///'
+
+daemon.o: daemon.c
+from_local.o: from_local.c
+get_myaddress.o: get_myaddress.c
+pmap_check.o: pmap_check.c
+pmap_check.o: pmap_check.h Makefile
+pmap_dump.o: pmap_dump.c
+pmap_set.o: pmap_set.c
+portmap.o: portmap.c
+portmap.o: pmap_check.h Makefile
+strerror.o: strerror.c
--- /dev/null
+# @(#) Makefile.shlib 1.1 96/07/06 23:00:53
+#
+# Warning: don't do this unless you are really desperate!!
+#
+# Makefile to build a shared object that forces RPC servers to register
+# and unregister with the portmapper through the loopback interface
+# instead of via the primary network interface address.
+#
+# This is a desperate attempt to prevent an attacker from using source
+# address spoofing to manipulate your portmapper tables. For this to be
+# effective you need to build the portmapper with -DLOOPBACK_SETUNSET,
+# and you need to disable IP source routing in the UNIX kernel.
+#
+# Quick summary of what to do to trick your rpc servers into cooperation:
+#
+# 1 - In the text below, uncomment the SH_CC and SH_LD definitions that are
+# appropriate for your environment. Then type:
+#
+# make -f Makefile.shcc
+#
+# 2 - Install the get_myaddress.so shared object in a suitable place, for
+# example in the /usr/local/lib directory.
+#
+# 3 - Edit your system startup files so that the rpc servers use the
+# get_myaddress.so shared object. For several environments, the text below
+# gives an example in bourne-shell syntax of how how to start an rpc server.
+
+# SunOS 4
+# /bin/sh syntax: LD_PRELOAD=/some/where/get_myaddress.so rpcserver...
+SH_CC = cc -pic
+SH_LD = ld -assert pure-text
+
+# NetBSD, FreeBSD
+# /bin/sh syntax: LD_PRELOAD=/some/where/get_myaddress.so rpcserver...
+#SH_CC = cc -fpic
+#SH_LD = ld -Bshareable
+
+# Digital UNIX
+# /bin/sh syntax: _RLD_LIST=/some/where/get_myaddress.so:DEFAULT rpcserver...
+#SH_CC = cc -pic
+#SH_LD = ld -shared
+
+# Build the shared object
+get_myaddress.so: get_myaddress.c
+ $(SH_CC) -c get_myaddress.c
+ $(SH_LD) -o get_myaddress.so get_myaddress.o
--- /dev/null
+@(#) README 1.7 96/07/06 23:06:19
+
+This is the README file for the 5th enhanced portmapper release.
+
+Description
+-----------
+
+This README describes a replacement portmapper that prevents theft of
+NIS (YP), NFS, and other sensitive information via the portmapper. As
+an option, the program supports access control in the style of the tcp
+wrapper (log_tcp) package.
+
+Like all portmappers, this one is intended to be started at boot time.
+Daemons that offer RPC services tell the portmapper on what port they
+listen. Unlike the well-known services registered with the inetd, RPC
+network port numbers may change each time the system is booted.
+Whenever a client wants to use an RPC service it is supposed to first
+ask the portmapper on what port the corresponding daemon is listening.
+The rpcinfo command can tell you what RPC services your system offers.
+
+As described in the features section below, the replacement portmapper
+can prevent undesirable client-server interactions. In some cases,
+better or equivalent alternatives are available:
+
+ The SunOS portmap that is provided with patch id 100482-02 should
+ close the same security holes. In addition, it provides an YPSERV
+ daemon with its own access control list. This is better than just
+ portmapper access control.
+
+ The "securelib" shared library (eecs.nwu.edu:/pub/securelib.tar)
+ implements access control for all kinds of (RPC) services, not
+ just the portmapper.
+
+However, vendors still ship portmap implementations that allow anyone
+to read or modify its tables and that will happily forward any request
+so that it appears to come from the local system.
+
+Features
+--------
+
+- optional: host access control. The local host is always considered
+authorized. Access control requires the libwrap.a library that comes
+with recent tcp wrapper (log_tcp) implementations.
+
+- requests to change the portmap tables are accepted only when they
+come from the local system.
+
+- optional: requests to (un)register services that listen on privileged
+ports (port < 1024) are accepted only when the requests themselves come
+from a privileged port. This feature is optional because of older RPC
+implementations.
+
+- requests that are forwarded by the portmapper will be forwarded
+through an unprivileged port.
+
+- the portmapper refuses to forward requests to rpc daemons that do (or
+should) verify the origin of each request: when the portmapper forwards
+a request it appears to come from the local machine. At present, the
+portmapper refuses to forward all RPC calls to itself, and most RPC
+calls to the NFS mountd/nfsd daemons, and to the NIS daemons.
+
+- the really desperate can harden the portmapper even more by requiring
+that requests to modify its tables arrive via the loopback network
+interface, instead of via the primary network interface that every host
+can talk to. The cost is high: besides changes to the portmapper, this
+requires changes to system libraries, to statically-linked rpc servers,
+to the kernel to disable IP source routing, and perhaps even to system
+startup procedures. Don't do this unless you're desperate. Details
+are given in the Makefile.
+
+Restrictions
+------------
+
+Limiting access to the portmapper does not protect you from direct
+attacks on the rpc daemons; the main task of portmap is to maintain a
+table of available RPC services and of the network ports that they are
+listening on. The securelib can be used to protect individual RPC
+daemons, and the latest SunOS portmap+NIS fix already protects the NIS
+daemons and implements limited forwarding.
+
+On the other hand, even though a portmapper with access control only
+makes an attack more difficult, it still provides an excellent early
+warning system.
+
+Origin and portability
+----------------------
+
+The sources in this distribution are derived from code on the second
+BSD networking tape, which was derived from Sun's RPCSRC 4.0 code, and
+from Sun's TIRPC (transport-independent rpc) distribution.
+
+The code compiles fine with SunOS 4.1.x, Ultrix 4.x, HP-UX 9.x, AIX 3.x
+and AIX 4.x, and Digital UNIX (OSF/1). See the notes in the Makefile.
+
+Solaris 2.x (and other true System V.4 clones) use a different program
+called rpcbind. I have written a replacement for that program, too.
+The primary achive is ftp.win.tue.nl:/pub/security/rpcbind_xx.tar.Z.
+
+Installation
+------------
+
+(1) Follow the instructions in the Makefile, then build the portmap and
+auxiliary executables.
+
+(2) Before killing the present portmap process, save the present
+portmapper tables using the command:
+
+ ./pmap_dump >table
+
+If you kill the portmap process without saving its tables you will have
+to reboot the machine.
+
+Note: the information in the portmap tables is dynamic: For example, it
+will be different after each reboot. On a Sun, it even changes each
+time a windowing system is started that uses the selection service.
+
+(3) Kill the running portmap process and start the new portmap
+program. Then (still as root) initialize the portmap tables with:
+
+ ./pmap_set <table
+
+(4) If you get error messages of the form: "not registered: xxxx",
+disable the CHECK_PORT feature in the Makefile, remove pmap_check.o and
+rebuild the portmap program. Then proceed with step 3.
+
+If the portmapper complains that it cannot find all machine interfaces
+you will have to rebuild it with -DHAS_SA_LEN set (see Makefile). You
+can test this with the "from_local" command (to build: make from_local).
+
+In order to revert to the original portmap daemon, kill off the running
+one, restart the original portmapper and reload its tables using the
+"pmap_set" command as shown above.
+
+Access control:
+---------------
+
+By default, host access control is enabled. However, the host that runs
+the portmapper is always considered authorized. The host access control
+tables are never consulted with requests from the local system itself;
+they are always consulted with requests from other hosts.
+
+In order to avoid deadlocks, the portmap program does not attempt to
+look up the remote host name or user name, nor will it try to match NIS
+netgroups. The upshot of all this is that only network number patterns
+will work for portmap access control.
+
+Sample entries for the host access-control files are:
+
+ /etc/hosts.allow:
+ portmap: your.sub.net.number/your.sub.net.mask
+ portmap: 255.255.255.255 0.0.0.0
+
+ /etc/hosts.deny
+ portmap: ALL: (/some/where/safe_finger -l @%h | mail root) &
+
+The syntax of the access-control files is described in the
+hosts_access.5 manual page that comes with the tcp wrapper (log_tcp)
+sources. The safe_finger command comes with later wrapper releases.
+
+The first line in the hosts.allow file permits access from all systems
+within your own subnet. Some rpc services rely on broadcasts and will
+contact your portmapper anyway; and once an intruder has access to your
+local network segment you're already in deep trouble.
+
+The second line in the hosts.allow file may be needed if there are
+any PC-NFS systems on your network segment.
+
+For security reasons, the portmap process drops root privilegs after
+initialization. The access control files should therefore be readable
+for group or world.
+
+Testing:
+--------
+
+Normally, only rejected requests will be reported via the syslog
+daemon. Logging is done in a child process, in order to avoid
+possible deadlock in case the logging code needs assistance from
+the portmapper.
+
+By default, the portmapper will be utterly silent. In fact, the portmap
+daemon is not consulted that often. Sending a SIGINT signal to the
+portmap process will enable the logging of all requests.
+
+Another way to enable verbose logging is to start the daemon with the
+"-v" option. See above, steps (2) and later, on how to stop and restart
+the portmapper without having to reboot.
+
+Warning: with some HP-UX and AIX versions, when verbose logging is on,
+the system fills up with zombie processes. This can be fixed by
+compiling with -DIGNORE_SIGCHLD (see instructions in the Makefile).
+
+With verbose logging turned on, requests such as "ypcat" or "rpcinfo
+-p" should show up with log file entries such as:
+
+ MMM dd hh:mm:ss hostname portmap[pid]: connect from x.x.x.x to getport(ypserv)
+ MMM dd hh:mm:ss hostname portmap[pid]: connect from y.y.y.y to dump()
+
+Send SIGINT to the portmapper to turn the verbose logging off.
+
+Acknowledgements
+----------------
+
+Casper H.S. Dik (casper@fwi.uva.nl) provided valuable information on
+RPC security and tested an intermediate version of the portmapper with
+SunOS 4.1.2. Lyford D. Rich (rich@ece.nps.navy.mil) was helpful with
+porting the daemon to Ultrix 3.x. Lionel Cons (cons@dxcern.cern.ch)
+solved the HP-UX problem. Fabrice Gonton (Fabrice.Gonton@sagem.fr)
+figured out how to make the program work on AIX 4.1, and Michael
+Matthews took care of the DEC Alpha platform.
+
+ Wietse Venema (wietse@wzv.win.tue.nl)
+ Mathematics and Computing Science
+ Eindhoven University of Technology
+ The Netherlands
--- /dev/null
+/*-
+ * Copyright (c) 1990 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)daemon.c 5.3 (Berkeley) 12/28/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <fcntl.h>
+
+/* From unistd.h */
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+/* From paths.h */
+#define _PATH_DEVNULL "/dev/null"
+
+daemon(nochdir, noclose)
+ int nochdir, noclose;
+{
+ int cpid;
+
+ if ((cpid = fork()) == -1)
+ return (-1);
+ if (cpid)
+ exit(0);
+ (void) setsid();
+ if (!nochdir)
+ (void) chdir("/");
+ if (!noclose) {
+ int devnull = open(_PATH_DEVNULL, O_RDWR, 0);
+
+ if (devnull != -1) {
+ (void) dup2(devnull, STDIN_FILENO);
+ (void) dup2(devnull, STDOUT_FILENO);
+ (void) dup2(devnull, STDERR_FILENO);
+ if (devnull > 2)
+ (void) close(devnull);
+ }
+ }
+ return(0);
+}
--- /dev/null
+ /*
+ * 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
+static char sccsid[] = "@(#) from_local.c 1.3 96/05/31 15:52:57";
+#endif
+
+#ifdef TEST
+#undef perror
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+ /*
+ * With virtual hosting, each hardware network interface can have multiple
+ * network addresses. On such machines the number of machine addresses can
+ * be surprisingly large.
+ */
+static int num_local;
+static int num_addrs;
+static struct in_addr *addrs;
+
+/* grow_addrs - extend list of local interface addresses */
+
+static int grow_addrs()
+{
+ struct in_addr *new_addrs;
+ int new_num;
+
+ /*
+ * Keep the previous result if we run out of memory. The system would
+ * really get hosed if we simply give up.
+ */
+ new_num = (addrs == 0) ? 1 : num_addrs + num_addrs;
+ new_addrs = (struct in_addr *) malloc(sizeof(*addrs) * new_num);
+ if (new_addrs == 0) {
+ perror("portmap: out of memory");
+ return (0);
+ } else {
+ if (addrs != 0) {
+ memcpy((char *) new_addrs, (char *) addrs,
+ sizeof(*addrs) * num_addrs);
+ free((char *) addrs);
+ }
+ num_addrs = new_num;
+ addrs = new_addrs;
+ return (1);
+ }
+}
+
+/* find_local - find all IP addresses for this host */
+
+find_local()
+{
+ struct ifconf ifc;
+ struct ifreq ifreq;
+ struct ifreq *ifr;
+ struct ifreq *the_end;
+ int sock;
+ char buf[BUFSIZ];
+
+ /*
+ * Get list of network interfaces. We use a huge buffer to allow for the
+ * presence of non-IP interfaces.
+ */
+
+ if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return (0);
+ }
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
+ perror("SIOCGIFCONF");
+ (void) close(sock);
+ return (0);
+ }
+ /* Get IP address of each active IP network interface. */
+
+ the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ num_local = 0;
+ for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
+ if (ifr->ifr_addr.sa_family == AF_INET) { /* IP net interface */
+ ifreq = *ifr;
+ if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
+ perror("SIOCGIFFLAGS");
+ } else if (ifreq.ifr_flags & IFF_UP) { /* active interface */
+ if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
+ perror("SIOCGIFADDR");
+ } else {
+ if (num_local >= num_addrs)
+ if (grow_addrs() == 0)
+ break;
+ addrs[num_local++] = ((struct sockaddr_in *)
+ & ifreq.ifr_addr)->sin_addr;
+ }
+ }
+ }
+ /* Support for variable-length addresses. */
+#ifdef HAS_SA_LEN
+ ifr = (struct ifreq *) ((caddr_t) ifr
+ + ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
+#endif
+ }
+ (void) close(sock);
+ return (num_local);
+}
+
+/* from_local - determine whether request comes from the local system */
+
+from_local(addr)
+struct sockaddr_in *addr;
+{
+ int i;
+
+ if (addrs == 0 && 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
+
+main()
+{
+ char *inet_ntoa();
+ int i;
+
+ find_local();
+ for (i = 0; i < num_local; i++)
+ printf("%s\n", inet_ntoa(addrs[i]));
+}
+
+#endif
--- /dev/null
+ /*
+ * get_myaddress - alternative version that picks the loopback interface.
+ *
+ * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
+ * Computing Science, Eindhoven University of Technology, The Netherlands.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) get_myaddress.c 1.1 23:00:53";
+#endif
+
+#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>
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK ntohl(inet_addr("127.0.0.1"))
+#endif
+
+void get_myaddress(addrp)
+struct sockaddr_in *addrp;
+{
+ memset((char *) addrp, 0, sizeof(*addrp));
+ addrp->sin_family = AF_INET;
+ addrp->sin_port = htons(PMAPPORT);
+ addrp->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+}
+
+#ifdef TEST
+
+#include <stdio.h>
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ struct sockaddr_in addr;
+
+ get_myaddress(&addr);
+ printf("%s\n", inet_ntoa(addr.sin_addr));
+ exit(0);
+}
+
+#endif
--- /dev/null
+ /*
+ * 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. Also, require
+ * that requests to set/unset the NFSD port come form a privileged port.
+ *
+ * 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
+static char sccsid[] = "@(#) pmap_check.c 1.8 96/07/07 10:49:10";
+#endif
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <sys/signal.h>
+#ifdef SYSV40
+#include <netinet/in.h>
+#include <rpc/rpcent.h>
+#endif
+
+extern char *inet_ntoa();
+
+#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)
+#define NFS_PORT 2049
+
+static void logit();
+static void toggle_verboselog();
+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 reserved_port(p) (IPPORT_RESERVED/2 < (p) && (p) < IPPORT_RESERVED)
+
+#define unreserved_port(p) (IPPORT_RESERVED <= (p) && (p) != NFS_PORT)
+
+#define legal_port(a,p) \
+ (reserved_port(ntohs((a)->sin_port)) || unreserved_port(p))
+
+#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 */
+
+check_default(addr, proc, prog)
+struct sockaddr_in *addr;
+u_long proc;
+u_long 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 */
+
+check_privileged_port(addr, proc, prog, port)
+struct sockaddr_in *addr;
+u_long proc;
+u_long prog;
+u_long 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 */
+
+#ifdef LOOPBACK_SETUNSET
+
+check_setunset(xprt, ludp_xprt, ltcp_xprt, proc, prog, port)
+SVCXPRT *xprt;
+SVCXPRT *ludp_xprt;
+SVCXPRT *ltcp_xprt;
+u_long proc;
+u_long prog;
+u_long port;
+{
+ struct sockaddr_in *addr = svc_getcaller(xprt);
+
+ if (xprt != ludp_xprt && xprt != ltcp_xprt) {
+#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);
+}
+
+#else
+
+check_setunset(addr, proc, prog, port)
+struct sockaddr_in *addr;
+u_long proc;
+u_long prog;
+u_long 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);
+}
+
+#endif
+
+/* check_callit - additional checks for forwarded requests */
+
+check_callit(addr, proc, prog, aproc)
+struct sockaddr_in *addr;
+u_long proc;
+u_long prog;
+u_long 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;
+u_long prognum;
+char *text;
+{
+ char *procname;
+ char procbuf[4 * sizeof(u_long)];
+ char *progname;
+ char progbuf[4 * sizeof(u_long)];
+ struct rpcent *rpc;
+ struct proc_map {
+ u_long code;
+ 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(progname = progbuf, "%lu", prognum);
+ }
+
+ /* Try to map procedure number to name. */
+
+ for (procp = procmap; procp->proc && procp->code != procnum; procp++)
+ /* void */ ;
+ if ((procname = procp->proc) == 0)
+ sprintf(procname = procbuf, "%lu", (u_long) procnum);
+
+ /* Write syslog record. */
+
+ syslog(severity, "connect from %s to %s(%s)%s",
+ inet_ntoa(addr->sin_addr), procname, progname, text);
+ exit(0);
+ }
+}
--- /dev/null
+/* @(#) pmap_check.h 1.4 96/07/06 23:06:22 */
+
+extern int from_local();
+extern void check_startup();
+extern int check_default();
+extern int check_setunset();
+extern int check_privileged_port();
+extern int check_callit();
+extern int verboselog;
+extern int allow_severity;
+extern int deny_severity;
+
+#ifdef LOOPBACK_SETUNSET
+#define CHECK_SETUNSET check_setunset
+#else
+#define CHECK_SETUNSET(xprt,ludp,ltcp,proc,prog,port) \
+ check_setunset(svc_getcaller(xprt),proc,prog,port)
+#endif
--- /dev/null
+ /*
+ * 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
+static char sccsid[] = "@(#) pmap_dump.c 1.1 92/06/11 22:53:15";
+#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 char *protoname();
+
+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 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);
+ }
+}
--- /dev/null
+ /*
+ * 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
+static char sccsid[] = "@(#) pmap_set.c 1.2 96/07/06 23:06:23";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef SYSV40
+#include <netinet/in.h>
+#endif
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ char buf[BUFSIZ];
+ u_long prog;
+ u_long vers;
+ int prot;
+ unsigned port;
+
+ while (fgets(buf, sizeof(buf), stdin)) {
+ if (parse_line(buf, &prog, &vers, &prot, &port) == 0) {
+ fprintf(stderr, "%s: malformed line: %s", argv[0], buf);
+ return (1);
+ }
+ if (pmap_set(prog, vers, prot, (unsigned short) port) == 0)
+ fprintf(stderr, "not registered: %s", buf);
+ }
+ return (0);
+}
+
+/* parse_line - convert line to numbers */
+
+parse_line(buf, prog, vers, prot, port)
+char *buf;
+u_long *prog;
+u_long *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);
+}
--- /dev/null
+/*-
+ * Copyright (c) 1990 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
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#) portmap.c 1.6 96/07/06 23:06:23";
+#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 <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#ifdef SYSV40
+#include <netinet/in.h>
+#endif
+
+extern char *strerror();
+#include <stdlib.h>
+
+#ifndef LOG_PERROR
+#define LOG_PERROR 0
+#endif
+
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+
+/* Older SYSV. */
+#if !defined(SIGCHLD) && defined(SIGCLD)
+#define SIGCHLD SIGCLD
+#endif
+
+#ifndef svc_getcaller /* SYSV4 */
+# define svc_getcaller svc_getrpccaller
+#endif
+
+#ifdef USE_SETPGRP00
+#define setsid() setpgrp(0,0)
+#endif
+
+void reg_service();
+void reap();
+static void callit();
+struct pmaplist *pmaplist;
+int debugging = 0;
+extern int errno;
+
+#include "pmap_check.h"
+
+ /*
+ * How desperate can one be. It is possible to prevent an attacker from
+ * manipulating your portmapper tables from outside with requests that
+ * contain spoofed source address information. The countermeasure is to
+ * force all rpc servers to register and unregister with the portmapper via
+ * the loopback network interface, instead of via the primary network
+ * interface that every host can talk to. For this countermeasure to work it
+ * is necessary to #define LOOPBACK_SETUNSET, to disable source routing in
+ * the kernel, and to modify libc so that get_myaddress() chooses the
+ * loopback interface address.
+ */
+
+#ifdef LOOPBACK_SETUNSET
+static SVCXPRT *ludpxprt, *ltcpxprt;
+static int on = 1;
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK ntohl(inet_addr("127.0.0.1"))
+#endif
+#endif
+
+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")) != EOF) {
+ switch (c) {
+
+ case 'd':
+ debugging = 1;
+ break;
+
+ case 'v':
+ verboselog = 1;
+ break;
+
+ default:
+ (void) fprintf(stderr, "usage: %s [-dv]\n", argv[0]);
+ (void) fprintf(stderr, "-d: debugging mode\n");
+ (void) fprintf(stderr, "-v: verbose logging\n");
+ exit(1);
+ }
+ }
+
+ if (!debugging && daemon(0, 0)) {
+ (void) fprintf(stderr, "portmap: fork: %s", strerror(errno));
+ exit(1);
+ }
+
+#ifdef LOG_MAIL
+ openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID,
+ FACILITY);
+#else
+ openlog("portmap", debugging ? LOG_PID | LOG_PERROR : LOG_PID);
+#endif
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ syslog(LOG_ERR, "cannot create udp socket: %m");
+ exit(1);
+ }
+#ifdef LOOPBACK_SETUNSET
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
+#endif
+
+ memset((char *) &addr, 0, sizeof(addr));
+ 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);
+ }
+#ifdef LOOPBACK_SETUNSET
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
+#endif
+ if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
+ syslog(LOG_ERR, "cannot bind udp: %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;
+
+#ifdef LOOPBACK_SETUNSET
+ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ syslog(LOG_ERR, "cannot create udp socket: %m");
+ exit(1);
+ }
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
+
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
+ syslog(LOG_ERR, "cannot bind udp: %m");
+ exit(1);
+ }
+
+ if ((ludpxprt = svcudp_create(sock)) == (SVCXPRT *)NULL) {
+ syslog(LOG_ERR, "couldn't do udp_create");
+ exit(1);
+ }
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ syslog(LOG_ERR, "cannot create tcp socket: %m");
+ exit(1);
+ }
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
+ if (bind(sock, (struct sockaddr *)&addr, len) != 0) {
+ syslog(LOG_ERR, "cannot bind tcp: %m");
+ exit(1);
+ }
+ if ((ltcpxprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
+ == (SVCXPRT *)NULL) {
+ syslog(LOG_ERR, "couldn't do tcp_create");
+ exit(1);
+ }
+#endif
+
+ (void)svc_register(xprt, PMAPPROG, PMAPVERS, reg_service, FALSE);
+
+ /* additional initializations */
+ check_startup();
+#ifdef IGNORE_SIGCHLD /* Lionel Cons <cons@dxcern.cern.ch> */
+ (void)signal(SIGCHLD, SIG_IGN);
+#else
+ (void)signal(SIGCHLD, reap);
+#endif
+ svc_run();
+ syslog(LOG_ERR, "run_svc returned unexpectedly");
+ abort();
+}
+
+#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
+ */
+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 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, ®))
+ svcerr_decode(xprt);
+ else {
+ /* reject non-local requests, protect priv. ports */
+ if (!CHECK_SETUNSET(xprt, ludpxprt, ltcpxprt,
+ 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_int, (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, ®))
+ svcerr_decode(xprt);
+ else {
+ ans = 0;
+ /* reject non-local requests */
+ if (!CHECK_SETUNSET(xprt, ludpxprt, ltcpxprt,
+ 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_int, (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, ®))
+ 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_int, (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)
+ register XDR *xdrs;
+ register 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)
+ register XDR *xdrs;
+ register 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)
+ register 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, &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);
+}
+
+void
+reap()
+{
+ while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
+}
--- /dev/null
+/*
+ * Copyright (c) 1988 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strerror.c 5.6 (Berkeley) 5/4/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <string.h>
+
+char *
+strerror(num)
+ int num;
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+#define UPREFIX "Unknown error: "
+ static char ebuf[40] = UPREFIX; /* 64-bit number + slop */
+ register unsigned int errnum;
+ register char *p, *t;
+ char tmp[40];
+
+ errnum = num; /* convert to unsigned */
+ if (errnum < sys_nerr)
+ return(sys_errlist[errnum]);
+
+ /* Do this by hand, so we don't include stdio(3). */
+ t = tmp;
+ do {
+ *t++ = "0123456789"[errnum % 10];
+ } while (errnum /= 10);
+ for (p = ebuf + sizeof(UPREFIX) - 1;;) {
+ *p++ = *--t;
+ if (t <= tmp)
+ break;
+ }
+ return(ebuf);
+}