Project import
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..163a3ea --- /dev/null +++ b/Makefile
@@ -0,0 +1,102 @@ +# +# Copyright (c) 2010-2011 Nest, Inc. +# All rights reserved. +# +# This document is the property of Nest. It is considered +# confidential and proprietary information. +# +# This document may not be reproduced or transmitted in any form, +# in whole or in part, without the express written permission of +# Nest. +# +# Description: +# This file is the makefile for the TCP/IP port number to RPC +# number mapper daemon and utilities. +# + +BuildConfigSpecialized := No +BuildProductSpecialized := No + +include pre.mak + +PackageName := portmap + +PackageExtension := tar.gz +PackageSeparator := _ + +PackagePatchArgs := -p1 + +PackageArchive := $(PackageName).$(PackageExtension) +PackageSourceDir := $(PackageName)$(PackageSeparator)$(PackageVersion) + +PackageBuildMakefile = $(call GenerateBuildPaths,Makefile) + +CleanPaths += $(PackageLicenseFile) + +all: $(PackageDefaultGoal) + +# Generate the package license contents. + +$(PackageSourceDir)/portmap.c: source + +$(PackageLicenseFile): $(PackageSourceDir)/portmap.c + $(Verbose)$(SED) -n -e '/^\/\*-$$/,/\*\/$$/{;p;/\*\/$$/q;}' < $< > $@ + +# Extract the source from the archive and apply patches, if any. + +$(PackageSourceDir): $(PackageArchive) $(PackagePatchPaths) + $(expand-and-patch-package) + +# Prepare the sources. + +.PHONY: source +source: | $(PackageSourceDir) + +# Patch the sources, if necessary. + +.PHONY: patch +patch: source + +# Generate the package build makefile. + +$(PackageBuildMakefile): | $(PackageSourceDir) $(BuildDirectory) + $(call create-links,$(CURDIR)/$(PackageSourceDir),$(BuildDirectory)) + +# Configure the source for building. + +.PHONY: configure +configure: source $(PackageBuildMakefile) + +# Build the source. +# +# We have to unset MAKEFLAGS since they confuse the package build otherwise. + +.PHONY: build +build: configure + $(Verbose)unset MAKEFLAGS && \ + $(MAKE) $(JOBSFLAG) -C $(BuildDirectory) \ + WRAP_INC="-I$(call GenerateResultPaths,sw/tps/tcp_wrappers,usr/include)" \ + WRAP_LIB="-L$(call GenerateResultPaths,sw/tps/tcp_wrappers,usr/lib) -lwrap" \ + INSTALL="$(INSTALL) $(INSTALLFLAGS)" \ + CC="$(CC)" \ + all + +# Stage the build to a temporary installation area. +# +# We have to unset MAKEFLAGS since they confuse the package build otherwise. + +.PHONY: stage +stage: build | $(ResultDirectory) + $(Verbose)unset MAKEFLAGS && \ + $(MAKE) $(JOBSFLAG) \ + -C $(BuildDirectory) \ + BASEDIR=$(ResultDirectory) \ + INSTALL="$(INSTALL) $(INSTALLFLAGS)" \ + install + +clean: + $(Verbose)$(RM) $(RMFLAGS) -r $(PackageSourceDir) + $(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory) + $(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory) + +include post.mak
diff --git a/portmap.patches/portmap-50.description b/portmap.patches/portmap-50.description new file mode 100644 index 0000000..4049b94 --- /dev/null +++ b/portmap.patches/portmap-50.description
@@ -0,0 +1,3 @@ +This patch adds support for specifying a non-standard location for TCP +Wrappers headers, disables stripping binaries and setting user/group +attributes (which fails for non-privileged users).
diff --git a/portmap.patches/portmap-50.patch b/portmap.patches/portmap-50.patch new file mode 100644 index 0000000..7aa8bd5 --- /dev/null +++ b/portmap.patches/portmap-50.patch
@@ -0,0 +1,32 @@ +diff -r -N -u portmap_6.0/Makefile portmap_6.0.N/Makefile +--- portmap_6.0/Makefile 2007-05-10 20:02:10.000000000 -0700 ++++ portmap_6.0.N/Makefile 2008-01-22 16:09:21.000000000 -0800 +@@ -128,6 +128,7 @@ + portmap: CFLAGS += -fpie + portmap: LDLIBS += $(WRAP_LIB) + portmap: LDFLAGS += -pie ++portmap: CPPFLAGS += $(WRAP_INC) + portmap: portmap.o pmap_check.o from_local.o + + from_local: CPPFLAGS += -DTEST +@@ -136,12 +137,14 @@ + sed $(MAN_SED) < portmap.8 > portmap.man + + install: all +- install -o root -g root -m 0755 -s portmap ${BASEDIR}/sbin +- install -o root -g root -m 0755 -s pmap_dump ${BASEDIR}/sbin +- install -o root -g root -m 0755 -s pmap_set ${BASEDIR}/sbin +- install -o root -g root -m 0644 portmap.man ${BASEDIR}/usr/share/man/man8/portmap.8 +- install -o root -g root -m 0644 pmap_dump.8 ${BASEDIR}/usr/share/man/man8 +- install -o root -g root -m 0644 pmap_set.8 ${BASEDIR}/usr/share/man/man8 ++ mkdir -p ${BASEDIR}/sbin ++ install -m 0755 portmap ${BASEDIR}/sbin ++ install -m 0755 pmap_dump ${BASEDIR}/sbin ++ install -m 0755 pmap_set ${BASEDIR}/sbin ++ mkdir -p ${BASEDIR}/usr/share/man/man8 ++ install -m 0644 portmap.man ${BASEDIR}/usr/share/man/man8/portmap.8 ++ install -m 0644 pmap_dump.8 ${BASEDIR}/usr/share/man/man8 ++ install -m 0644 pmap_set.8 ${BASEDIR}/usr/share/man/man8 + + clean: + rm -f *.o portmap pmap_dump pmap_set from_local \
diff --git a/portmap.tar.gz b/portmap.tar.gz new file mode 100644 index 0000000..e517542 --- /dev/null +++ b/portmap.tar.gz Binary files differ
diff --git a/portmap.url b/portmap.url new file mode 100644 index 0000000..6b2aff3 --- /dev/null +++ b/portmap.url
@@ -0,0 +1 @@ +http://neil.brown.name/portmap/portmap-6.0.tgz
diff --git a/portmap.version b/portmap.version new file mode 100644 index 0000000..e0ea36f --- /dev/null +++ b/portmap.version
@@ -0,0 +1 @@ +6.0
diff --git a/portmap_6.0/BLURBv5 b/portmap_6.0/BLURBv5 new file mode 100644 index 0000000..ce28af8 --- /dev/null +++ b/portmap_6.0/BLURBv5
@@ -0,0 +1,42 @@ +@(#) 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
diff --git a/portmap_6.0/CHANGES b/portmap_6.0/CHANGES new file mode 100644 index 0000000..0e88d45 --- /dev/null +++ b/portmap_6.0/CHANGES
@@ -0,0 +1,36 @@ +Changes with release 6.0 (May 2007) + +- compile and runtime selection of uid to 'setuid' to +- mapping table is stored in a file and can be restored on restart +- If a privilege program registers a non-privileged port, and + non-privileged program can no-longer unregister it. +- add man pages +- allow portmap to bind to a local address only +- support 'chroot' +- various cleanups and minor bug fixes + + +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.
diff --git a/portmap_6.0/Makefile b/portmap_6.0/Makefile new file mode 100644 index 0000000..aa5e0b0 --- /dev/null +++ b/portmap_6.0/Makefile
@@ -0,0 +1,157 @@ + +#################################### +### 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_DAEMON + +# 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. +# By default, access control does not do hostname lookup as there is a risk +# that will require portmap access, hence deadlock. If you are sure the +# target system will never user NIS for hostname lookup, you can define +# USE_DNS to add hostname tests in hosts.allow/deny. + +ifeq ($(NO_TCP_WRAPPER),) +CPPFLAGS += -DHOSTS_ACCESS +WRAP_LIB = -lwrap +ifdef USE_DNS +CPPFLAGS += -DENABLE_DNS +MAN_SED += -e 's/USE_DNS/yes/' +endif +endif + +# 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. + +CPPFLAGS += -DCHECK_PORT + +# The portmap daemon runs a uid=1/gid=1 by default. You can change that +# be defining DAEMON_UID and DAMEON_GID to numbers, or RPCUSER to a +# name, though you must be sure that name lookup will not require use +# of portmap. +ifdef RPCUSER +CPPFLAGS += -DRPCUSER=\"$(RPCUSER)\" +MAN_SED += -e 's/RPCUSER/$(RPCUSER)/' +else +MAN_SED += -e 's/RPCUSER//' +endif +ifdef DAEMON_UID +CPPFLAGS += -DDAEMON_UID=$(DAEMON_UID) -DDAEMON_GID=$(DAEMON_GID) +MAN_SED += -e 's/DAEMON_UID/$(DAEMON_UID)/' -e 's/DAEMON_GID/$(DAEMON_GID)/' +else +MAN_SED += -e 's/DAEMON_UID/1/' -e 's/DAEMON_GID/1/' +endif + +# 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. +# +# CPPFLAGS += -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. +# +# CPPFLAGS += -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. +# +CPPFLAGS += -DIGNORE_SIGCHLD # AIX 4.x, HP-UX 9.x + +# Uncomment the following macro if your system does not have u_long. +# +# CPPFLAGS +=-Du_long="unsigned long" + +# +# LDLIBS += -m +# CFLAGS += -arch m68k -arch i386 -arch hppa + +# Auxiliary libraries that you may have to specify +# +# LDLIBS += -lrpc + +# Comment out if your compiler talks ANSI and understands const +# +# CPPFLAGS += -Dconst= + +### End of configurable stuff. +############################## + +CPPFLAGS += -DFACILITY=$(FACILITY) +CFLAGS ?= -O2 +CFLAGS += -Wall -Wstrict-prototypes + +all: portmap pmap_dump pmap_set portmap.man + +CPPFLAGS += $(HOSTS_ACCESS) +portmap: CFLAGS += -fpie +portmap: LDLIBS += $(WRAP_LIB) +portmap: LDFLAGS += -pie +portmap: CPPFLAGS += $(WRAP_INC) +portmap: portmap.o pmap_check.o from_local.o + +from_local: CPPFLAGS += -DTEST + +portmap.man : portmap.8 + sed $(MAN_SED) < portmap.8 > portmap.man + +install: all + mkdir -p ${BASEDIR}/sbin + install -m 0755 portmap ${BASEDIR}/sbin + install -m 0755 pmap_dump ${BASEDIR}/sbin + install -m 0755 pmap_set ${BASEDIR}/sbin + mkdir -p ${BASEDIR}/usr/share/man/man8 + install -m 0644 portmap.man ${BASEDIR}/usr/share/man/man8/portmap.8 + install -m 0644 pmap_dump.8 ${BASEDIR}/usr/share/man/man8 + install -m 0644 pmap_set.8 ${BASEDIR}/usr/share/man/man8 + +clean: + rm -f *.o portmap pmap_dump pmap_set from_local \ + core portmap.man + +-include .depend +.depend: *.c + $(CC) -MM $(CFLAGS) *.c > .depend + +.PHONY: all clean install
diff --git a/portmap_6.0/README b/portmap_6.0/README new file mode 100644 index 0000000..0da54cc --- /dev/null +++ b/portmap_6.0/README
@@ -0,0 +1,32 @@ + +portmap-6.0 is the first release in 10 year of portmap based on the code +from Wietse Venema. + +It consolidates patches that various Linux distributions were shipping +with their versions of portmap, and add some more functionality. + +This version is currently maintained by + Neil Brown <neilb@suse.de> +and can be found at + git://neil.brown.name/portmap + http://neil.brown.name/git/portmap + http://neil.brown.name/portmap/ + +NeilBrown - 11may2007 + +There is no "./configure", just use "make". + +Some make variable can be used to control compilation. + + NO_TCP_WRAPPER= if non-empty, doen't use tcp_wrappers + USE_DNS= if set, tcp_wrappers can check peers based on hostname + as well as IP address. This should only be used if you + are certain that gethostbyname will never trigger a + called to portmap (as it might if 'nis' is used for hostnames). + RPCUSER= is set, portmap will use getpwnam to find the user for + that user, and will setuid to that user before listening + for incoming messages + DAEMON_UID= Can be set to a number to override the default UID + to setuid to. Default is '1'. + DAEMON_GID= As above, but for setgid. +
diff --git a/portmap_6.0/README.5 b/portmap_6.0/README.5 new file mode 100644 index 0000000..c2b0c0b --- /dev/null +++ b/portmap_6.0/README.5
@@ -0,0 +1,214 @@ +@(#) 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
diff --git a/portmap_6.0/from_local.c b/portmap_6.0/from_local.c new file mode 100644 index 0000000..da851c6 --- /dev/null +++ b/portmap_6.0/from_local.c
@@ -0,0 +1,180 @@ + /* + * 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 + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdio.h> +#include <stdlib.h> +#include <netdb.h> +#include <netinet/in.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <syslog.h> +#include <string.h> +#include <unistd.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(void) +{ + 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 */ + +static int +find_local(void) +{ + 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 */ + +int from_local(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
diff --git a/portmap_6.0/pmap_check.c b/portmap_6.0/pmap_check.c new file mode 100644 index 0000000..84f2c12 --- /dev/null +++ b/portmap_6.0/pmap_check.c
@@ -0,0 +1,328 @@ + /* + * 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. + */ + + +#include <sys/types.h> +#include <unistd.h> +#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 +#include <tcpd.h> +#include <arpa/inet.h> +#include <grp.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) +#define NFS_PORT 2049 + +static void logit(int severity, struct sockaddr_in *addr, + u_long procnum, u_long prognum, char *text); +static void toggle_verboselog(int sig); +int verboselog __attribute ((visibility ("hidden"))) = 0; +int allow_severity __attribute ((visibility ("hidden"))) = LOG_INFO; +int deny_severity __attribute ((visibility ("hidden"))) = LOG_WARNING; + +/* A handful of macros for "readability". */ + +#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(void) +{ + + /* + * Give up root privileges so that we can never allocate a privileged + * port when forwarding an rpc request. + */ + setgid(daemon_gid); + setgroups(0, NULL); + if (setuid(daemon_uid) == -1) { + syslog(LOG_ERR, "setuid(1) failed: %m"); + exit(1); + } + (void) signal(SIGINT, toggle_verboselog); +} + + +#ifdef HOSTS_ACCESS +static int +good_client(struct sockaddr_in *addr) +{ + if (hosts_ctl("portmap", "", inet_ntoa(addr->sin_addr), "")) + return 1; +#ifdef ENABLE_DNS +{ + struct hostent *hp; + char **sp; + char *tmpname; + + /* Check the hostname. */ + hp = gethostbyaddr ((const char *) &(addr->sin_addr), + sizeof (addr->sin_addr), AF_INET); + + if (!hp) + return 0; + + /* must make sure the hostent is authoritative. */ + tmpname = alloca (strlen (hp->h_name) + 1); + strcpy (tmpname, hp->h_name); + hp = gethostbyname(tmpname); + if (hp) { + /* now make sure the "addr->sin_addr" is on the list */ + for (sp = hp->h_addr_list ; *sp ; sp++) { + if (memcmp(*sp, &(addr->sin_addr), hp->h_length)==0) + break; + } + if (!*sp) + /* it was a FAKE. */ + return 0; + } else + /* never heard of it. misconfigured DNS? */ + return 0; + + /* Check the official name first. */ + if (hosts_ctl("portmap", "", hp->h_name, "")) + return 1; + + /* Check aliases. */ + for (sp = hp->h_aliases; *sp ; sp++) { + if (hosts_ctl("portmap", "", *sp, "")) + return 1; + } +} +#endif /* ENABLE_DNS */ + return 0; +} +#endif /* HOSTS_ACCESS */ + +/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */ + +int +check_default(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 */ + +int +check_privileged_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 + +int +check_setunset(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 + +int +check_setunset(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 */ + +int +check_callit(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(int sig) +{ + (void) signal(sig, toggle_verboselog); + verboselog = !verboselog; +} + +/* logit - report events of interest via the syslog daemon */ + +static void logit(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); + } +}
diff --git a/portmap_6.0/pmap_check.h b/portmap_6.0/pmap_check.h new file mode 100644 index 0000000..bc21dfd --- /dev/null +++ b/portmap_6.0/pmap_check.h
@@ -0,0 +1,33 @@ +/* pmap_check.h */ + +extern int from_local(struct sockaddr_in *addr); +extern void check_startup(void); +extern int check_default(struct sockaddr_in *addr, + u_long proc, u_long prog); +#ifdef LOOPBACK_SETUNSET +extern int +check_setunset(SVCXPRT *xprt, SVCXPRT *ludp_xprt, SVCXPRT *ltcp_xprt, + u_long proc, u_long prog, u_long port); +#else +extern int +check_setunset(struct sockaddr_in *addr, u_long proc, + u_long prog, u_long port); +#endif +extern int check_privileged_port(struct sockaddr_in *addr, + u_long proc, + u_long prog, u_long port); +extern int check_callit(struct sockaddr_in *addr, u_long proc, + u_long prog, u_long aproc); +extern int verboselog __attribute__ ((visibility ("hidden"))); +extern int allow_severity __attribute__ ((visibility ("hidden"))); +extern int deny_severity __attribute__ ((visibility ("hidden"))); + +#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 + +extern int daemon_uid; +extern int daemon_gid;
diff --git a/portmap_6.0/pmap_dump.8 b/portmap_6.0/pmap_dump.8 new file mode 100644 index 0000000..0da5162 --- /dev/null +++ b/portmap_6.0/pmap_dump.8
@@ -0,0 +1,24 @@ +.TH PMAP_DUMP 8 "21th June 1997" Linux "Linux Programmer's Manual" +.SH NAME +pmap_dump \- print a list of all registered RPC programs +.SH SYNOPSIS +.B pmap_dump +.SH DESCRIPTION +The +.B pmap_dump +command can be used to restart a running portmapper or to print +a list of all registered RPC programs on the local host. If you +want to use the program to restart the portmapper you have to +redirect the output of +.B pmap_dump +to a file. After this you can restart the portmapper and restore +the list of the registered RPC programs by feeding the output +of +.B pmap_dump +to the +.B pmap_set +command. +.SH SEE ALSO +.BR pmap_set (8), +.BR portmap (8) +
diff --git a/portmap_6.0/pmap_dump.c b/portmap_6.0/pmap_dump.c new file mode 100644 index 0000000..333f41d --- /dev/null +++ b/portmap_6.0/pmap_dump.c
@@ -0,0 +1,59 @@ + /* + * 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. + */ + +#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(u_long proto); + +int +main(int argc, char **argv) +{ + struct sockaddr_in addr; + struct pmaplist *list; + struct rpcent *rpc; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_port = htons(PMAPPORT); + + 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 : ""); + } + return (fclose(stdout) ? (perror(argv[0]), 1) : 0); +} + +static char *protoname(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/portmap_6.0/pmap_set.8 b/portmap_6.0/pmap_set.8 new file mode 100644 index 0000000..c4da65d --- /dev/null +++ b/portmap_6.0/pmap_set.8
@@ -0,0 +1,24 @@ +.TH PMAP_SET 8 "21th June 1997" Linux "Linux Programmer's Manual" +.SH NAME +pmap_set \- set the list of registered RPC programs +.SH SYNOPSIS +.B pmap_set +.SH DESCRIPTION +The +.B pmap_set +command can be used to restart a running portmapper or to set +the list of registered RPC programs on the local host. If you +want to use the program to restart the portmapper you have to +redirect the output of +.B pmap_dump +to a file. After this you can restart the portmapper and restore +the list of the registered RPC programs by feeding the output +of +.B pmap_dump +to the +.B pmap_set +command. +.SH SEE ALSO +.BR pmap_dump (8), +.BR portmap (8) +
diff --git a/portmap_6.0/pmap_set.c b/portmap_6.0/pmap_set.c new file mode 100644 index 0000000..017a359 --- /dev/null +++ b/portmap_6.0/pmap_set.c
@@ -0,0 +1,63 @@ + /* + * 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. + */ + +#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(char *buf, u_long *prog, u_long *vers, + int *prot, unsigned *port); + +int +main(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 */ + +static int +parse_line(char *buf, u_long *prog, u_long *vers, + int *prot, unsigned *port) +{ + char proto_name[256]; + + if (sscanf(buf, "%lu %lu %255s %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/portmap_6.0/portmap.8 b/portmap_6.0/portmap.8 new file mode 100644 index 0000000..4c92cac --- /dev/null +++ b/portmap_6.0/portmap.8
@@ -0,0 +1,224 @@ +.\" Copyright (c) 1987 Sun Microsystems +.\" Copyright (c) 1990, 1991 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. +.\" +.\" from: @(#)portmap.8 5.3 (Berkeley) 3/16/91 +.\" $Id: portmap.8,v 1.2 2004/04/03 09:30:21 herbert Exp $ +.\" +.Dd Apr 20, 2007 +.Dt PORTMAP 8 +.Os BSD 4.3 +.Sh NAME +.Nm portmap +.Nd +.Tn DARPA +port to +.Tn RPC +program number mapper +.Sh SYNOPSIS +.Nm portmap +.Op Fl d +.Op Fl f +.Op Fl t Ar dir +.Op Fl v +.Op Fl V +.Op Fl i Ar address +.Op Fl l +.Op Fl u Ar uid +.Op Fl g Ar gid +.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 portmap +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 portmap +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 +Normally +.Nm portmap +forks and dissociates itself from the terminal +like any other daemon. +.Nm Portmap +then logs errors using +.Xr syslog 3 . +.Pp +.Nm Portmap +records all current mapping in the file +.Nm /var/run/portmap_mapping +so that if it gets killed and restarted, it can reload the mapping for +currently active services. +.Pp +Options available: +.Bl -tag -width Ds +.It Fl V +Display version number and exit. +.It Fl d +(debug) prevents +.Nm portmap +from running as a daemon, +and causes errors and debugging information +to be printed to the standard error output. +.It Fl f +(foreground) prevents +.Nm portmap +from running as a daemon, +and causes log messages +to be printed to the standard error output. +.It Fl t Ar dir +(chroot) tell +.Nm portmap +to +.Xr chroot 2 +into +.Ar dir . +.Ar dir +should be empty, not writeable by the daemon user, and preferably on a +filesystem mounted read-only, noexec, nodev, and nosuid. +.It Fl u Ar uid +.It Fl g Ar gid +Set the user-id and group-id of the running process to those given, +rather than the compiled-in defaults of DAEMON_UID/DAEMON_GID. +.if 'RPCUSER'' .ig +If neither are set, then +.Nm portmap +will look up the user +.Nm RPCUSER +and use the uid and gid of that user. +.. +.It Fl v +(verbose) run +.Nm portmap +in verbose mode. +.It Fl i Ar address +bind +.Nm portmap +to address. If you specify 127.0.0.1 it will bind to the loopback +interface only. +.It Fl l +bind +.Nm portmap +to the loop-back address 127.0.0.1. This is a shorthand for +specifying 127.0.0.1 with -i. +.El + +This +.Nm portmap +version is protected by the +.Nm tcp_wrapper +library. You have to give the clients access to +.Nm portmap +if they should be allowed to use it. +.if 'USE_DNS'yes' .ig +To allow connects from clients of the network 192.168. you could use +the following line in /etc/hosts.allow: + +portmap: 192.168. + +In order to avoid deadlocks, the +.Nm portmap +program does not attempt to look up the remote host name or user name, nor will +it try to match NIS netgroups. As a consequence only network number patterns +(or IP addresses) will work for portmap access control, do not use hostnames. +Notice that localhost will always be allowed access to the portmapper. + +You have to use the daemon name +.Nm portmap +for the daemon name (even if the binary has a different name). For the +client names you can only use the keyword ALL or IP addresses (NOT +host or domain names). +.. +.if !'USE_DNS'yes' .ig +To allow connects from clients of +the .bar.com domain you could use the following line in /etc/hosts.allow: +.Pp +portmap: .bar.com +.Pp +You have to use the daemon name +.Nm portmap +for the daemon name (even if the binary has a different name). For the +client names you can use the keyword ALL, IP addresses, hostnames or domain +names. Using netgroup names will likely cause +.Nm portmap +to deadlock. +Note that localhost will always be allowed access to the portmapper. +.. + +For further information please have a look at the +.Xr tcpd 8 , +.Xr hosts_allow 5 +and +.Xr hosts_access 5 +manual pages. + +.Sh SEE ALSO +.Xr inetd.conf 5 , +.Xr rpcinfo 8 , +.Xr pmap_set 8 , +.Xr pmap_dump 8 , +.Xr inetd 8 , +.Xr tcpd 8 , +.Xr hosts_access 5 , +.Xr hosts_options 5 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 +.Sh AUTHORS +This +manual page was changed by +.An Anibal Monsalve Salazar +for the Debian Project.
diff --git a/portmap_6.0/portmap.c b/portmap_6.0/portmap.c new file mode 100644 index 0000000..2a98881 --- /dev/null +++ b/portmap_6.0/portmap.c
@@ -0,0 +1,864 @@ +/*- + * 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 */ + +/* +@(#)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 <unistd.h> +#include <syslog.h> +#include <netdb.h> +#include <errno.h> +#include <fcntl.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> +#include <sys/types.h> +#ifdef SYSV40 +#include <netinet/in.h> +#endif +#include <arpa/inet.h> + +#include <stdlib.h> +#include <pwd.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 + +static void reg_service(struct svc_req *rqstp, SVCXPRT *xprt); +#ifndef IGNORE_SIGCHLD /* Lionel Cons <cons@dxcern.cern.ch> */ +static void reap(int); +#endif +static void callit(struct svc_req *rqstp, SVCXPRT *xprt); +struct pmaplist *pmaplist; +int debugging = 0; +int store_fd = -1; +static void dump_table(void); +static void load_table(void); + +#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 + +#ifdef DAEMON_UID +int daemon_uid = DAEMON_UID; +int daemon_gid = DAEMON_GID; +#else +int daemon_uid = 1; +int daemon_gid = 1; +#endif + +/* + * We record with each registration a flag telling whether it was + * registered with a privilege port or not. + * If it was, it can only be unregistered with a privileged port. + * So that we can still use standard pmap xdr routines, we store + * this flag in a structure wrapped around a pmaplist. + */ +struct flagged_pml { + struct pmaplist pml; + int priv; +}; + +int +main(int argc, char **argv) +{ + SVCXPRT *xprt; + int sock, c; + struct sockaddr_in addr; + int len = sizeof(struct sockaddr_in); + struct pmaplist *pml; + struct flagged_pml *fpml; + char *chroot_path = NULL; + struct in_addr bindaddr; + int have_bindaddr = 0; + int foreground = 0; + int have_uid = 0; + + while ((c = getopt(argc, argv, "Vdflt:vi:u:g:")) != EOF) { + switch (c) { + + case 'V': + printf("portmap version 6.0 - 2007-May-11\n"); + exit(1); + + case 'u': + daemon_uid = atoi(optarg); + if (daemon_uid <= 0) { + fprintf(stderr, + "portmap: illegal uid: %s\n", optarg); + exit(1); + } + have_uid = 1; + break; + case 'g': + daemon_gid = atoi(optarg); + if (daemon_gid <= 0) { + fprintf(stderr, + "portmap: illegal gid: %s\n", optarg); + exit(1); + } + have_uid = 1; + break; + case 'd': + debugging = 1; + case 'f': + foreground = 1; + break; + + case 't': + chroot_path = optarg; + break; + + case 'v': + verboselog = 1; + break; + + case 'l': + optarg = "127.0.0.1"; + /* FALL THROUGH */ + case 'i': + have_bindaddr = inet_aton(optarg, &bindaddr); + break; + default: + fprintf(stderr, + "usage: %s [-dflv] [-t dir] [-i address] " + "[-u uid] [-g gid]\n", + argv[0]); + fprintf(stderr, "-d: debugging mode\n"); + fprintf(stderr, + "-f: don't daemonize, log to standard error\n"); + fprintf(stderr, "-t dir: chroot into dir\n"); + fprintf(stderr, "-v: verbose logging\n"); + fprintf(stderr, "-i address: bind to address\n"); + fprintf(stderr, "-l: same as -i 127.0.0.1\n"); + fprintf(stderr, "-u uid : setuid to this uid\n"); + fprintf(stderr, "-g uid : setgid to this gid\n"); + exit(1); + } + } + + if (!foreground && daemon(0, 0)) { + (void) fprintf(stderr, "portmap: fork: %s", strerror(errno)); + exit(1); + } + +#ifdef LOG_DAEMON + openlog("portmap", LOG_PID|LOG_NDELAY | ( foreground ? LOG_PERROR : 0), + FACILITY); +#else + openlog("portmap", LOG_PID|LOG_NDELAY | ( foreground ? LOG_PERROR : 0)); +#endif + +#ifdef RPCUSER + if (!have_uid) { + struct passwd *pwent; + pwent = getpwnam(RPCUSER); + if (pwent) { + daemon_uid = pwent->pw_uid; + daemon_gid = pwent->pw_gid; + } else + syslog(LOG_WARNING, "user '" RPCUSER + "' not found, reverting to default uid"); + } +#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 (have_bindaddr) + memcpy(&addr.sin_addr, &bindaddr, sizeof(bindaddr)); + + 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 */ + fpml = malloc(sizeof(struct flagged_pml)); + pml = &fpml->pml; + fpml->priv = 1; + pml->pml_next = NULL; + 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 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 */ + fpml = malloc(sizeof(struct flagged_pml)); + pml = &fpml->pml; + fpml->priv = 1; + 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); + + store_fd = open("/var/run/portmap_mapping", O_RDWR|O_CREAT, 0600); + load_table(); + + /* additional initializations */ + if (chroot_path) { + if (chroot(chroot_path) < 0) { + syslog(LOG_ERR, "couldn't do chroot"); + exit(1); + } + } + check_startup(); +#ifdef IGNORE_SIGCHLD /* Lionel Cons <cons@dxcern.cern.ch> */ + (void)signal(SIGCHLD, SIG_IGN); +#else + (void)signal(SIGCHLD, reap); +#endif + (void)signal(SIGPIPE, SIG_IGN); + svc_run(); + syslog(LOG_ERR, "run_svc returned unexpectedly"); + abort(); +} + +/* need to override perror calls in rpc library */ +void perror(const char *what) +{ + + syslog(LOG_ERR, "%s: %m", what); +} + +static struct pmaplist * +find_service(u_long prog, u_long vers, u_long prot) +{ + struct pmaplist *hit = NULL; + 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(struct svc_req *rqstp, SVCXPRT *xprt) +{ + struct pmap reg; + struct pmaplist *pml, *prevpml, *fnd; + struct flagged_pml *fpml; + 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, (xdrproc_t) xdr_void, (caddr_t)0) + && debugging) { + abort(); + } + break; + + case PMAPPROC_SET: + /* + * Set a program,version to port mapping + */ + if (!svc_getargs(xprt, (xdrproc_t) xdr_pmap, (caddr_t)®)) + 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 + */ + fpml = (struct flagged_pml *) + malloc((u_int)sizeof(struct flagged_pml)); + pml = &fpml->pml; + fpml->priv = + (ntohs(svc_getcaller(xprt)->sin_port) + < IPPORT_RESERVED); + 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; + dump_table(); + } + done: + if ((!svc_sendreply(xprt, (xdrproc_t)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, (xdrproc_t)xdr_pmap, (caddr_t)®)) + 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; + } + fpml = (struct flagged_pml*)pml; + if (fpml->priv && + (ntohs(svc_getcaller(xprt)->sin_port) + >= IPPORT_RESERVED)) { + 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); + dump_table(); + } + if ((!svc_sendreply(xprt, (xdrproc_t)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, (xdrproc_t)xdr_pmap, (caddr_t)®)) + 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, (xdrproc_t)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, (xdrproc_t)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, (xdrproc_t)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(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(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(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(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(XDR *xdrs, struct rmtcallargs *cap) +{ + 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(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, (xdrproc_t)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, (xdrproc_t)xdr_opaque_parms, + (caddr_t)&a, (xdrproc_t)xdr_len_opaque_parms, + (caddr_t)&a, timeout) == RPC_SUCCESS) { + svc_sendreply(xprt, (xdrproc_t)xdr_rmtcall_result, + (caddr_t)&a); + } + AUTH_DESTROY(client->cl_auth); + clnt_destroy(client); + } + (void)close(so); + exit(0); +} + +#ifndef IGNORE_SIGCHLD /* Lionel Cons <cons@dxcern.cern.ch> */ +static void reap(int ignore) +{ + int save_errno = errno; + while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0); + errno = save_errno; +} +#endif + +/* Dump and restore mapping table so that we can survive kill/restart. + * To cope with chroot, an fd is opened early and we just write to that. + * If we are killed while writing the file, we lose, but that isn't + * very likely... + */ + +static void dump_table(void) +{ + FILE *f; + struct pmaplist *pml; + + if (store_fd < 0) + return; + ftruncate(store_fd, 0); + lseek(store_fd, 0, 0); + f = fdopen(dup(store_fd), "w"); + if (!f) + return; + + for (pml = pmaplist ; pml ; pml = pml->pml_next) { + struct flagged_pml *fpml = (struct flagged_pml*)pml; + + fprintf(f, "%lu %lu %lu %lu %d\n", + pml->pml_map.pm_prog, + pml->pml_map.pm_vers, + pml->pml_map.pm_prot, + pml->pml_map.pm_port, + fpml->priv); + } + fclose(f); +} + +static void load_table(void) +{ + FILE *f; + struct pmaplist **ep; + struct flagged_pml fpml, *fpmlp; + + ep = &pmaplist; + while ((*ep)->pml_next) + ep = & (*ep)->pml_next; + + if (store_fd < 0) + return; + lseek(store_fd, 0, 0); + f = fdopen(dup(store_fd), "r"); + if (f == NULL) + return; + + while (fscanf(f, "%lu %lu %lu %lu %d\n", + &fpml.pml.pml_map.pm_prog, + &fpml.pml.pml_map.pm_vers, + &fpml.pml.pml_map.pm_prot, + &fpml.pml.pml_map.pm_port, + &fpml.priv) == 5) { + if (fpml.pml.pml_map.pm_port == PMAPPORT) + continue; + fpmlp = malloc(sizeof(struct flagged_pml)); + if (!fpmlp) + break; + *fpmlp = fpml; + *ep = &fpmlp->pml; + ep = &fpmlp->pml.pml_next; + *ep = NULL; + } + fclose(f); +}