aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/ypserv
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ypserv')
-rw-r--r--usr.sbin/ypserv/Makefile51
-rw-r--r--usr.sbin/ypserv/Makefile.depend18
-rw-r--r--usr.sbin/ypserv/Makefile.depend.options5
-rw-r--r--usr.sbin/ypserv/Makefile.yp694
-rw-r--r--usr.sbin/ypserv/common/yplib_host.c353
-rw-r--r--usr.sbin/ypserv/common/yplib_host.h51
-rw-r--r--usr.sbin/ypserv/yp_access.c332
-rw-r--r--usr.sbin/ypserv/yp_dblookup.c727
-rw-r--r--usr.sbin/ypserv/yp_dnslookup.c545
-rw-r--r--usr.sbin/ypserv/yp_error.c71
-rw-r--r--usr.sbin/ypserv/yp_extern.h115
-rw-r--r--usr.sbin/ypserv/yp_main.c578
-rw-r--r--usr.sbin/ypserv/yp_server.c985
-rw-r--r--usr.sbin/ypserv/yp_svc_udp.c71
-rw-r--r--usr.sbin/ypserv/ypinit.8198
-rw-r--r--usr.sbin/ypserv/ypinit.sh386
-rw-r--r--usr.sbin/ypserv/ypserv.8461
17 files changed, 5641 insertions, 0 deletions
diff --git a/usr.sbin/ypserv/Makefile b/usr.sbin/ypserv/Makefile
new file mode 100644
index 000000000000..b4e59b719692
--- /dev/null
+++ b/usr.sbin/ypserv/Makefile
@@ -0,0 +1,51 @@
+.include <src.opts.mk>
+
+RPCDIR= ${SRCTOP}/include/rpcsvc
+.PATH: ${RPCDIR} ${.CURDIR}/common
+
+PACKAGE= yp
+PROG= ypserv
+MAN= ypserv.8 ypinit.8
+SRCS= yp_svc.c yp_server.c yp_dblookup.c yp_dnslookup.c \
+ ypxfr_clnt.c yp.h yp_main.c yp_error.c yp_access.c yp_svc_udp.c \
+ yplib_host.c
+
+CFLAGS+= -DDB_CACHE -I.
+
+WARNS?= 0
+
+.if ${MK_TCP_WRAPPERS} != "no"
+CFLAGS+= -DTCP_WRAPPER
+LIBADD+= wrap
+.endif
+
+CLEANFILES= yp_svc.c ypxfr_clnt.c yp.h
+
+RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -I -C
+
+# We need to remove the 'static' keyword from _rpcsvcstate so that
+# yp_main.c can see it.
+yp_svc.c: yp.x
+ rm -f ${.TARGET}
+ ${RPCGEN} -DYPSERV_ONLY -m ${RPCDIR}/yp.x | \
+ sed s/"static int _rpcsvcstate"/"int _rpcsvcstate"/g > ${.TARGET}
+
+ypxfr_clnt.c: yp.x
+ ${RPCGEN} -DYPPUSH_ONLY -l -o ${.TARGET} ${RPCDIR}/yp.x
+
+yp.h: yp.x
+ ${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/yp.x
+
+FILES= Makefile.yp
+FILESNAME= Makefile.dist
+FILESDIR= /var/yp
+SCRIPTS= ypinit.sh
+
+# If NO_ROOT is defined, we are doing a stage install and always need to
+# install the symlink, otherwise, don't overwrite the user's existing
+# symlink.
+.if defined(NO_ROOT) || !exists(${DESTDIR}${FILESDIR}/Makefile)
+SYMLINKS= ${FILESNAME} ${FILESDIR}/Makefile
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ypserv/Makefile.depend b/usr.sbin/ypserv/Makefile.depend
new file mode 100644
index 000000000000..732a025c9552
--- /dev/null
+++ b/usr.sbin/ypserv/Makefile.depend
@@ -0,0 +1,18 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/arpa \
+ include/rpc \
+ include/rpcsvc \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ypserv/Makefile.depend.options b/usr.sbin/ypserv/Makefile.depend.options
new file mode 100644
index 000000000000..fbc21670804e
--- /dev/null
+++ b/usr.sbin/ypserv/Makefile.depend.options
@@ -0,0 +1,5 @@
+# This file is not autogenerated - take care!
+
+DIRDEPS_OPTIONS= TCP_WRAPPERS
+
+.include <dirdeps-options.mk>
diff --git a/usr.sbin/ypserv/Makefile.yp b/usr.sbin/ypserv/Makefile.yp
new file mode 100644
index 000000000000..18d6509a9fa7
--- /dev/null
+++ b/usr.sbin/ypserv/Makefile.yp
@@ -0,0 +1,694 @@
+#
+# Makefile for the NIS databases
+#
+#
+# This Makefile should only be run on the NIS master server of a domain.
+# All updated maps will be pushed to all NIS slave servers listed in the
+# /var/yp/ypservers file. Please make sure that the hostnames of all
+# NIS servers in your domain are listed in /var/yp/ypservers.
+#
+# This Makefile can be modified to support more NIS maps if desired.
+#
+
+# If this machine is an NIS master, reset this variable (NOPUSH=)
+# in Makefile.local so that changes to the NIS maps can be propagated to
+# the slave servers. (By default we assume that we are only serving a
+# small domain with only one server.)
+#
+NOPUSH = "True"
+
+# If this machine does not wish to generate a linux-style shadow map
+# from the master.passwd file, reset this variable (SHADOW=) in
+# Makefile.local.
+SHADOW = "True"
+
+# If you want to use a FreeBSD NIS server to serve non-FreeBSD clients
+# (i.e. clients who expect the password field in the passwd maps to be
+# valid) then set this variable (UNSECURE="True") in Makefile.local.
+# This will cause $YPDIR/passwd to be generated with valid password
+# fields. This is insecure: FreeBSD normally only serves the
+# master.passwd and shadow maps (which have real encrypted passwords
+# in them) to the superuser on other FreeBSD machines, but non-FreeBSD
+# clients (e.g. SunOS, Solaris (without NIS+), IRIX, HP-UX, etc...)
+# will only work properly in 'unsecure' mode.
+#
+#UNSECURE = "True"
+
+# The following line encodes the YP_INTERDOMAIN key into the hosts.byname
+# and hosts.byaddr maps so that ypserv(8) will do DNS lookups to resolve
+# hosts not in the current domain. Resetting this variable in
+# Makefile.local (B=) will disable the DNS lookups.
+B=-b
+
+# Normally, the master.passwd.* and shadow.* maps are guarded against access
+# from non-privileged users. By resetting S in Makefile.local (S=), the
+# YP_SECURE key will be removed from these maps, allowing anyone to access
+# them.
+S=-s
+
+# These are commands which this Makefile needs to properly rebuild the
+# NIS databases. Don't change these unless you have a good reason. Also
+# be sure not to place an @ in front of /usr/bin/awk: it isn't necessary
+# and it'll break everything in sight.
+#
+AWK = /usr/bin/awk
+RM = @/bin/rm -f
+MV = @/bin/mv -f
+RMV = /bin/mv -f
+
+MKDB = /usr/sbin/yp_mkdb
+DBLOAD = $(MKDB) -m `hostname`
+MKNETID = /usr/libexec/mknetid
+NEWALIASES = /usr/bin/newaliases
+YPPUSH = /usr/sbin/yppush
+.if !defined(UPDATE_DOMAIN)
+DOMAIN = `/bin/domainname`
+.else
+DOMAIN = $(UPDATE_DOMAIN)
+.endif
+REVNETGROUP = /usr/libexec/revnetgroup
+TMP = `echo $@.$$$$`
+
+# It is advisable to create a separate directory to contain the
+# source files used to generate your NIS maps. If you intend to
+# support multiple domains, something like /src/dir/$DOMAIN
+# would work well.
+YPSRCDIR = /etc
+.if !defined(YP_DIR)
+YPDIR = /var/yp
+.else
+YPDIR = $(YP_DIR)
+.endif
+YPMAPDIR = $(YPDIR)/$(DOMAIN)
+
+# These are the files from which the NIS databases are built. You may edit
+# these to taste in the event that you wish to keep your NIS source files
+# separate from your NIS server's actual configuration files. Note that the
+# NIS passwd and master.passwd files are stored in /var/yp: the server's
+# real password database is not used by default. However, you may use
+# the real /etc/passwd and /etc/master.passwd files by:
+#
+#
+# - invoking yppasswdd with `-t /etc/master.passwd' (yppasswdd will do a
+# 'pwd_mkdb' as needed if /etc/master.passwd is thus specified).
+# - Specifying the location of the master.passwd file using the
+# MASTER_PASSWD variable, i.e.:
+#
+# # make MASTER_PASSWD=/path/to/some/other/master.passwd
+#
+# - (optionally): editing this Makefile to change the default location.
+#
+# To add a user, edit $(YPDIR)/master.passwd and type 'make'. The raw
+# passwd file will be generated from the master.passwd file automagically.
+#
+ETHERS = $(YPSRCDIR)/ethers # ethernet addresses (for rarpd)
+EUI64 = $(YPSRCDIR)/eui64 # eui64 addresses (for firewire)
+BOOTPARAMS= $(YPSRCDIR)/bootparams # for booting Sun boxes (bootparamd)
+HOSTS = $(YPSRCDIR)/hosts
+IPNODES = $(YPDIR)/ipnodes
+NETWORKS = $(YPSRCDIR)/networks
+PROTOCOLS = $(YPSRCDIR)/protocols
+RPC = $(YPSRCDIR)/rpc
+SERVICES = $(YPSRCDIR)/services
+SHELLS = $(YPSRCDIR)/shells
+GROUP = $(YPSRCDIR)/group
+ALIASES = $(YPSRCDIR)/mail/aliases
+NETGROUP = $(YPDIR)/netgroup
+PASSWD = $(YPDIR)/passwd
+.if !defined(MASTER_PASSWD)
+MASTER = $(YPDIR)/master.passwd
+.else
+MASTER = $(MASTER_PASSWD)
+.endif
+YPSERVERS = $(YPDIR)/ypservers # List of all NIS servers for a domain
+PUBLICKEY = $(YPSRCDIR)/publickey
+NETID = $(YPSRCDIR)/netid
+AMDHOST = $(YPSRCDIR)/amd.map
+
+target:
+ @if [ ! -d $(DOMAIN) ]; then mkdir $(DOMAIN); fi; \
+ cd $(DOMAIN) ; echo "NIS Map update started on `date` for domain $(DOMAIN)" ; \
+ make -f ../Makefile all; echo "NIS Map update completed."
+
+# Read overrides. Note, the current directory will be /var/yp/<domain>
+# when 'all' is built.
+.if exists(${YPDIR}/Makefile.local)
+.include "${YPDIR}/Makefile.local"
+.endif
+
+# List of maps that are always built.
+# If you want to omit some of them, feel free to comment
+# them out from this list.
+TARGETS= servers hosts networks protocols rpc services shells group
+TARGETS+= ipnodes
+#TARGETS+= aliases
+
+# Sanity checks: filter out targets we can't build
+# Note that we don't build the ethers, eui64, or boorparams maps by default
+# since /etc/ethers, /etc/eui64 and /etc/bootparams are not likely to be present
+# on all systems.
+.if exists($(ETHERS))
+TARGETS+= ethers
+.else
+ETHERS= /dev/null
+.endif
+
+.if exists($(EUI64))
+TARGETS+= eui64
+.else
+EUI64= /dev/null
+.endif
+
+.if exists($(BOOTPARAMS))
+TARGETS+= bootparams
+.else
+BOOTPARAMS= /dev/null
+.endif
+
+.if exists($(NETGROUP))
+TARGETS+= netgrp
+.else
+NETGROUP= /dev/null
+.endif
+
+.if exists($(MASTER))
+TARGETS+= passwd master.passwd netid
+.if ${SHADOW} == "\"True\""
+TARGETS+= shadow
+.endif
+.else
+MASTER= /dev/null
+TARGETS+= nopass
+.endif
+
+.if exists($(PUBLICKEY))
+TARGETS+= publickey
+.else
+PUBLICKEY= /dev/null
+.endif
+
+.if exists($(AMDHOST))
+TARGETS+= amd.map
+.else
+AMDHOST= /dev/null
+.endif
+
+.if !exists($(IPNODES))
+IPNODES= $(HOSTS)
+.endif
+
+all: $(TARGETS)
+
+ethers: ethers.byname ethers.byaddr
+eui64: eui64.byname eui64.byid
+bootparam: bootparams
+hosts: hosts.byname hosts.byaddr
+ipnodes: ipnodes.byname ipnodes.byaddr
+networks: networks.byaddr networks.byname
+protocols: protocols.bynumber protocols.byname
+rpc: rpc.byname rpc.bynumber
+services: services.byname
+passwd: passwd.byname passwd.byuid
+shadow: shadow.byname shadow.byuid
+group: group.byname group.bygid
+netgrp: netgroup
+netid: netid.byname
+servers: ypservers
+publickey: publickey.byname
+aliases: mail.aliases
+
+master.passwd: master.passwd.byname master.passwd.byuid
+
+#
+# This is a special target used only when doing in-place updates with
+# rpc.yppasswdd. In this case, the maps will be updated by the rpc.yppasswdd
+# server and won't need to be remade. They will have to be pushed to the
+# slaves however. Calling this target implicitly insures that this will
+# happen.
+#
+pushpw:
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) master.passwd.byname ; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) master.passwd.byuid ; fi
+.if ${SHADOW} == "\"True\""
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) shadow.byname ; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) shadow.byuid ; fi
+.endif
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) passwd.byname ; fi
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) passwd.byuid ; fi
+
+pushmap:
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $(PUSHMAP) ; fi
+
+nopass:
+ @echo ""
+ @echo " ********WARNING********"
+ @echo " Couldn't find the master.passwd source file. This file"
+ @echo " is needed to generate the master.passwd and passwd maps."
+ @echo " The default location is /var/yp/master.passwd. You should"
+ @echo " edit /var/yp/Makefile and set the MASTER variable to point"
+ @echo " to the source file you wish to use for building the passwd"
+ @echo " maps, or else invoke make(1) in the following manner:"
+ @echo ""
+ @echo " make MASTER_PASSWD=/path/to/master.passwd"
+ @echo ""
+
+mail.aliases: $(ALIASES)
+ @echo "Updating $@..."
+ @$(NEWALIASES) -oA$(ALIASES)
+ @$(MKDB) -u $(ALIASES).db \
+ | $(DBLOAD) -i $(ALIASES) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+ypservers: $(YPSERVERS)
+ @echo "Updating $@..."
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*") print $$0"\t"$$0 }' \
+ $(YPSERVERS) \
+ | $(DBLOAD) -i $(YPSERVERS) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+ethers.byname: $(ETHERS)
+ @echo "Updating $@..."
+.if ${ETHERS} == "/dev/null"
+ @echo "Ethers source file not found -- skipping"
+.else
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$2"\t"$$0 }' $(ETHERS) | $(DBLOAD) -i $(ETHERS) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+ethers.byaddr: $(ETHERS)
+ @echo "Updating $@..."
+.if ${ETHERS} == "/dev/null"
+ @echo "Ethers source file not found -- skipping"
+.else
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1"\t"$$0 }' $(ETHERS) | $(DBLOAD) -i $(ETHERS) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+eui64.byname: $(EUI64)
+ @echo "Updating $@..."
+.if ${EUI64} == "/dev/null"
+ @echo "EUI64 source file not found -- skipping"
+.else
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$2"\t"$$0 }' $(EUI64) | $(DBLOAD) -i $(EUI64) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+eui64.byid: $(EUI64)
+ @echo "Updating $@..."
+.if ${EUI64} == "/dev/null"
+ @echo "EUI64 source file not found -- skipping"
+.else
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1"\t"$$0 }' $(EUI64) | $(DBLOAD) -i $(EUI64) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+bootparams: $(BOOTPARAMS)
+ @echo "Updating $@..."
+.if ${BOOTPARAMS} == "/dev/null"
+ @echo "Bootparams source file not found -- skipping"
+.else
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$0 }' $(BOOTPARAMS) | $(DBLOAD) -i $(BOOTPARAMS) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+netgroup: $(NETGROUP) netgroup.byhost netgroup.byuser
+ @echo "Updating $@..."
+.if ${NETGROUP} == "/dev/null"
+ @echo "Netgroup source file not found -- skipping"
+.else
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$0 }' $(NETGROUP) | $(DBLOAD) -i $(NETGROUP) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+netgroup.byhost: $(NETGROUP)
+ @echo "Updating $@..."
+.if ${NETGROUP} == "/dev/null"
+ @echo "Netgroup source file not found -- skipping"
+.else
+ @$(REVNETGROUP) -h -f $(NETGROUP) | \
+ $(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$0 }' | $(DBLOAD) -i $(NETGROUP) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+netgroup.byuser: $(NETGROUP)
+ @echo "Updating $@..."
+.if ${NETGROUP} == "/dev/null"
+ @echo "Netgroup source file not found -- skipping"
+.else
+ @$(REVNETGROUP) -u -f $(NETGROUP) | \
+ $(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$0 }' | $(DBLOAD) -i $(NETGROUP) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+# Solaris 8 does the following:
+# - /etc/hosts and hosts.{byname,byaddr} are IPv4 only.
+# - /etc/inet/ipnodes and ipnodes.{byname,byaddr} are used for protocol
+# independent name-to-address mapping.
+#
+# For local name resolution, we made /etc/hosts protocol independent.
+# For NIS name resolution, we obey Solaris 8 practice.
+# - We keep hosts.{byname,byaddr} IPv4 only, to be friendly with Solaris 8
+# clients.
+# - ipnodes.{byname,byaddr} is used for protocol independent mapping.
+# We generate all the mappings from /etc/hosts unless /var/yp/ipnodes
+# exists, for compatibility with FreeBSD local name resolution.
+#
+hosts.byname: $(HOSTS)
+ @echo "Updating $@..."
+ @$(AWK) '/^[0-9.]+[\t ]/ { for (n=2; n<=NF && $$n !~ "^#.*"; n++) \
+ print $$n"\t"$$0 }' $(HOSTS) | $(DBLOAD) ${B} -i $(HOSTS) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+hosts.byaddr: $(HOSTS)
+ @echo "Updating $@..."
+ @$(AWK) '/^[0-9.]+[\t ]/ { print $$1"\t"$$0 }' $(HOSTS) \
+ | $(DBLOAD) ${B} -i $(HOSTS) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+ipnodes.byname: $(IPNODES)
+ @echo "Updating $@..."
+ @$(AWK) '/^[0-9a-fA-F:]/ { for (n=2; n<=NF && $$n !~ "^#.*"; n++) \
+ print $$n"\t"$$0 }' $(IPNODES) | $(DBLOAD) ${B} -i $(IPNODES) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+ipnodes.byaddr: $(IPNODES)
+ @echo "Updating $@..."
+ @$(AWK) '$$1 !~ "^#.*" { print $$1"\t"$$0 }' $(IPNODES) \
+ | $(DBLOAD) ${B} -i $(IPNODES) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+networks.byname: $(NETWORKS)
+ @echo "Updating $@..."
+ @$(AWK) \
+ '$$1 !~ "^#.*" { print $$1"\t"$$0; \
+ for (n=3; n<=NF && $$n !~ "^#.*"; n++) \
+ print $$n"\t"$$0 \
+ }' $(NETWORKS) \
+ | $(DBLOAD) -i $(NETWORKS) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+networks.byaddr: $(NETWORKS)
+ @echo "Updating $@..."
+ @$(AWK) '$$1 !~ "^#.*" { print $$2"\t"$$0 }' $(NETWORKS) \
+ | $(DBLOAD) -i $(NETWORKS) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+protocols.byname: $(PROTOCOLS)
+ @echo "Updating $@..."
+ @$(AWK) \
+ '$$1 !~ "^#.*" { print $$1"\t"$$0; \
+ for (n=3; n<=NF && $$n !~ "^#.*"; n++) \
+ print $$n"\t"$$0 \
+ }' $(PROTOCOLS) | $(DBLOAD) -i $(PROTOCOLS) \
+ -o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+protocols.bynumber: $(PROTOCOLS)
+ @echo "Updating $@..."
+ @$(AWK) '$$1 !~ "^#.*" { print $$2"\t"$$0 }' $(PROTOCOLS) \
+ | $(DBLOAD) -i $(PROTOCOLS) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+rpc.byname: $(RPC)
+ @echo "Updating $@..."
+ @$(AWK) \
+ '$$1 !~ "^#.*" { print $$1"\t"$$0; \
+ for (n=3; n<=NF && $$n !~ "^#.*"; n++) \
+ print $$n"\t"$$0 \
+ }' $(RPC) | $(DBLOAD) -i $(RPC) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+rpc.bynumber: $(RPC)
+ @echo "Updating $@..."
+ @$(AWK) '$$1 !~ "^#.*" { print $$2"\t"$$0 }' $(RPC) \
+ | $(DBLOAD) -i $(RPC) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+services.byname: $(SERVICES)
+ @echo "Updating $@..."
+ @$(AWK) \
+ '$$1 !~ "^#.*" { for (n=1; n<=NF && $$n !~ "^#.*"; n++) { \
+ if (split($$2, t, "/")) { \
+ printf("%s/%s", $$n, t[2]) }; \
+ print "\t"$$0; \
+ if (n == 1) n = 2; \
+ } ; print $$2"\t"$$0 ; \
+ }' $(SERVICES) \
+ | $(DBLOAD) -i $(SERVICES) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+shells: $(SHELLS)
+ @echo "Updating $@..."
+ @$(AWK) '{ if ($$1 != "" && $$1 !~ "^#.*") print $$0"\t"$$0 }' \
+ $(SHELLS) \
+ | $(DBLOAD) -i $(SHELLS) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+publickey.byname: $(PUBLICKEY)
+ @echo "Updating $@..."
+.if ${PUBLICKEY} == "/dev/null"
+ @echo "Publickey source file not found -- skipping"
+.else
+ @$(AWK) '$$1 !~ "^#.*" { print $$1"\t"$$2 }' $(PUBLICKEY) \
+ | $(DBLOAD) -i $(PUBLICKEY) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+$(PASSWD): $(MASTER)
+ @echo "Creating new $@ file from $(MASTER)..."
+ @if [ ! $(UNSECURE) ]; then \
+ $(AWK) -F: '{if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1":*:"$$3":"$$4":"$$8":"$$9":"$$10}' $(MASTER) \
+ > $(PASSWD) ; \
+ else \
+ $(AWK) -F: '{if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1":"$$2":"$$3":"$$4":"$$8":"$$9":"$$10}' $(MASTER) \
+ > $(PASSWD) ; fi
+
+
+passwd.byname: $(PASSWD)
+ @echo "Updating $@..."
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1"\t"$$0 }' $(PASSWD) \
+ | $(DBLOAD) -f -i $(PASSWD) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+passwd.byuid: $(PASSWD)
+ @echo "Updating $@..."
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$3"\t"$$0 }' $(PASSWD) \
+ | $(DBLOAD) -f -i $(PASSWD) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+group.byname: $(GROUP)
+ @echo "Updating $@..."
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1"\t"$$0 }' $(GROUP) \
+ | $(DBLOAD) -f -i $(GROUP) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+group.bygid: $(GROUP)
+ @echo "Updating $@..."
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$3"\t"$$0 }' $(GROUP) \
+ | $(DBLOAD) -f -i $(GROUP) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+netid.byname: $(GROUP) $(PASSWD) $(HOSTS)
+ @echo "Updating $@..."
+ @$(MKNETID) -q -p $(PASSWD) -g $(GROUP) -h $(HOSTS) -n $(NETID) \
+ -d $(DOMAIN) | $(DBLOAD) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+
+
+master.passwd.byname: $(MASTER)
+ @echo "Updating $@..."
+.if ${MASTER} == "/dev/null"
+ @echo "Master.passwd source file not found -- skipping"
+.else
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1"\t"$$0 }' $(MASTER) \
+ | $(DBLOAD) ${S} -f -i $(MASTER) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+master.passwd.byuid: $(MASTER)
+ @echo "Updating $@..."
+.if ${MASTER} == "/dev/null"
+ @echo "Master.passwd source file not found -- skipping"
+.else
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$3"\t"$$0 }' $(MASTER) \
+ | $(DBLOAD) ${S} -f -i $(MASTER) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+
+shadow.byname: $(MASTER)
+ @echo "Updating $@..."
+.if ${MASTER} == "/dev/null"
+ @echo "Master.passwd source file not found -- skipping"
+.else
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$1"\t"$$1":"$$2":12000:0:99999:7:::" }' $(MASTER) \
+ | sed 's/\( [^:]*:\)\*:/\1!:/' \
+ | $(DBLOAD) ${S} -f -i $(PASSWD) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+shadow.byuid: $(MASTER)
+ @echo "Updating $@..."
+.if ${MASTER} == "/dev/null"
+ @echo "Master.passwd source file not found -- skipping"
+.else
+ @$(AWK) -F: '{ if ($$1 != "" && $$1 !~ "^#.*" && $$1 != "+") \
+ print $$3"\t"$$1":"$$2":12000:0:99999:7:::" }' $(MASTER) \
+ | sed 's/\( [^:]*:\)\*:/\1!:/' \
+ | $(DBLOAD) ${S} -f -i $(PASSWD) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
+.endif
+
+amd.map: $(AMDHOST)
+ @echo "Updating $@..."
+ @$(AWK) '$$1 !~ "^#.*" { \
+ for (i = 1; i <= NF; i++) \
+ if (i == NF) { \
+ if (substr($$i, length($$i), 1) == "\\") \
+ printf("%s", substr($$i, 1, length($$i) - 1)); \
+ else \
+ printf("%s\n", $$i); \
+ } \
+ else \
+ printf("%s ", $$i); \
+ }' $(AMDHOST) | \
+ $(DBLOAD) -i $(AMDHOST) -o $(YPMAPDIR)/$@ - $(TMP); \
+ $(RMV) $(TMP) $@
+ @$(DBLOAD) -c
+ @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
+ @if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
diff --git a/usr.sbin/ypserv/common/yplib_host.c b/usr.sbin/ypserv/common/yplib_host.c
new file mode 100644
index 000000000000..2751c5950d87
--- /dev/null
+++ b/usr.sbin/ypserv/common/yplib_host.c
@@ -0,0 +1,353 @@
+/* $OpenBSD: yplib_host.c,v 1.18 2015/01/16 06:40:22 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "yplib_host.h"
+
+extern bool_t xdr_ypresp_all_seq(XDR *, unsigned long *);
+
+extern int (*ypresp_allfn)(u_long, char *, int, char *, int, void *);
+extern void *ypresp_data;
+
+static int _yplib_host_timeout = 10;
+
+CLIENT *
+yp_bind_host(char *server, u_long program, u_long version, u_short port,
+ int usetcp)
+{
+ struct sockaddr_in rsrv_sin;
+ static CLIENT *client;
+ struct hostent *h;
+ struct timeval tv;
+ int rsrv_sock;
+
+ memset(&rsrv_sin, 0, sizeof rsrv_sin);
+ rsrv_sin.sin_len = sizeof rsrv_sin;
+ rsrv_sin.sin_family = AF_INET;
+ rsrv_sock = RPC_ANYSOCK;
+ if (port != 0)
+ rsrv_sin.sin_port = htons(port);
+
+ if (*server >= '0' && *server <= '9') {
+ if (inet_aton(server, &rsrv_sin.sin_addr) == 0) {
+ errx(1, "inet_aton: invalid address %s.",
+ server);
+ }
+ } else {
+ h = gethostbyname(server);
+ if (h == NULL) {
+ errx(1, "gethostbyname: unknown host %s.",
+ server);
+ }
+ rsrv_sin.sin_addr.s_addr = *(u_int32_t *)h->h_addr;
+ }
+
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ if (usetcp)
+ client = clnttcp_create(&rsrv_sin, program, version,
+ &rsrv_sock, 0, 0);
+ else
+ client = clntudp_create(&rsrv_sin, program, version, tv,
+ &rsrv_sock);
+
+ if (client == NULL) {
+ errx(1, "clntudp_create: no contact with host %s.",
+ server);
+ }
+
+ return (client);
+}
+
+CLIENT *
+yp_bind_local(u_long program, u_long version)
+{
+ struct sockaddr_in rsrv_sin;
+ static CLIENT *client;
+ struct timeval tv;
+ int rsrv_sock;
+
+ memset(&rsrv_sin, 0, sizeof rsrv_sin);
+ rsrv_sin.sin_len = sizeof rsrv_sin;
+ rsrv_sin.sin_family = AF_INET;
+ rsrv_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ rsrv_sock = RPC_ANYSOCK;
+
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ client = clntudp_create(&rsrv_sin, program, version, tv, &rsrv_sock);
+ if (client == NULL) {
+ errx(1, "clntudp_create: no contact with localhost.");
+ }
+
+ return (client);
+}
+
+int
+yp_match_host(CLIENT *client, char *indomain, char *inmap, const char *inkey,
+ int inkeylen, char **outval, int *outvallen)
+{
+ struct ypresp_val yprv;
+ struct ypreq_key yprk;
+ struct timeval tv;
+ int r;
+
+ *outval = NULL;
+ *outvallen = 0;
+
+ tv.tv_sec = _yplib_host_timeout;
+ tv.tv_usec = 0;
+
+ yprk.domain = indomain;
+ yprk.map = inmap;
+ yprk.key.keydat_val = (char *)inkey;
+ yprk.key.keydat_len = inkeylen;
+
+ memset(&yprv, 0, sizeof yprv);
+
+ r = clnt_call(client, YPPROC_MATCH,
+ (xdrproc_t)xdr_ypreq_key, &yprk,
+ (xdrproc_t)xdr_ypresp_val, &yprv, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_match_host: clnt_call");
+ if ( !(r = ypprot_err(yprv.stat)) ) {
+ *outvallen = yprv.val.valdat_len;
+ *outval = malloc(*outvallen + 1);
+ memcpy(*outval, yprv.val.valdat_val, *outvallen);
+ (*outval)[*outvallen] = '\0';
+ }
+ xdr_free((xdrproc_t)xdr_ypresp_val, (char *)&yprv);
+
+ return (r);
+}
+
+int
+yp_first_host(CLIENT *client, char *indomain, char *inmap, char **outkey,
+ int *outkeylen, char **outval, int *outvallen)
+{
+ struct ypresp_key_val yprkv;
+ struct ypreq_nokey yprnk;
+ struct timeval tv;
+ int r;
+
+ *outkey = *outval = NULL;
+ *outkeylen = *outvallen = 0;
+
+ tv.tv_sec = _yplib_host_timeout;
+ tv.tv_usec = 0;
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+ memset(&yprkv, 0, sizeof yprkv);
+
+ r = clnt_call(client, YPPROC_FIRST,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_first_host: clnt_call");
+ if ( !(r = ypprot_err(yprkv.stat)) ) {
+ *outkeylen = yprkv.key.keydat_len;
+ *outkey = malloc(*outkeylen+1);
+ memcpy(*outkey, yprkv.key.keydat_val, *outkeylen);
+ (*outkey)[*outkeylen] = '\0';
+ *outvallen = yprkv.val.valdat_len;
+ *outval = malloc(*outvallen+1);
+ memcpy(*outval, yprkv.val.valdat_val, *outvallen);
+ (*outval)[*outvallen] = '\0';
+ }
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, (char *)&yprkv);
+
+ return (r);
+}
+
+int
+yp_next_host(CLIENT *client, char *indomain, char *inmap, char *inkey,
+ int inkeylen, char **outkey, int *outkeylen, char **outval, int *outvallen)
+{
+ struct ypresp_key_val yprkv;
+ struct ypreq_key yprk;
+ struct timeval tv;
+ int r;
+
+ *outkey = *outval = NULL;
+ *outkeylen = *outvallen = 0;
+
+ tv.tv_sec = _yplib_host_timeout;
+ tv.tv_usec = 0;
+
+ yprk.domain = indomain;
+ yprk.map = inmap;
+ yprk.key.keydat_val = inkey;
+ yprk.key.keydat_len = inkeylen;
+ memset(&yprkv, 0, sizeof yprkv);
+
+ r = clnt_call(client, YPPROC_NEXT,
+ (xdrproc_t)xdr_ypreq_key, &yprk,
+ (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_next_host: clnt_call");
+ if ( !(r = ypprot_err(yprkv.stat)) ) {
+ *outkeylen = yprkv.key.keydat_len;
+ *outkey = malloc(*outkeylen+1);
+ memcpy(*outkey, yprkv.key.keydat_val, *outkeylen);
+ (*outkey)[*outkeylen] = '\0';
+ *outvallen = yprkv.val.valdat_len;
+ *outval = malloc(*outvallen+1);
+ memcpy(*outval, yprkv.val.valdat_val, *outvallen);
+ (*outval)[*outvallen] = '\0';
+ }
+ xdr_free((xdrproc_t)xdr_ypresp_key_val, (char *)&yprkv);
+
+ return (r);
+}
+
+int
+yp_all_host(CLIENT *client, char *indomain, char *inmap,
+ struct ypall_callback *incallback)
+{
+ struct ypreq_nokey yprnk;
+ struct timeval tv;
+ u_long status;
+
+ tv.tv_sec = _yplib_host_timeout;
+ tv.tv_usec = 0;
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+ ypresp_allfn = incallback->foreach;
+ ypresp_data = (void *)incallback->data;
+
+ (void) clnt_call(client, YPPROC_ALL,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_all_seq, &status, tv);
+ if (status != YP_FALSE)
+ return ypprot_err(status);
+
+ return (0);
+}
+
+int
+yp_order_host(CLIENT *client, char *indomain, char *inmap, u_int32_t *outorder)
+{
+ struct ypresp_order ypro;
+ struct ypreq_nokey yprnk;
+ struct timeval tv;
+ int r;
+
+ tv.tv_sec = _yplib_host_timeout;
+ tv.tv_usec = 0;
+
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+
+ memset(&ypro, 0, sizeof ypro);
+
+ r = clnt_call(client, YPPROC_ORDER,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_order, &ypro, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_order_host: clnt_call");
+ *outorder = ypro.ordernum;
+ xdr_free((xdrproc_t)xdr_ypresp_order, (char *)&ypro);
+
+ return ypprot_err(ypro.stat);
+}
+
+int
+yp_master_host(CLIENT *client, char *indomain, char *inmap, char **outname)
+{
+ struct ypresp_master yprm;
+ struct ypreq_nokey yprnk;
+ struct timeval tv;
+ int r;
+
+ tv.tv_sec = _yplib_host_timeout;
+ tv.tv_usec = 0;
+ yprnk.domain = indomain;
+ yprnk.map = inmap;
+
+ memset(&yprm, 0, sizeof yprm);
+
+ r = clnt_call(client, YPPROC_MASTER,
+ (xdrproc_t)xdr_ypreq_nokey, &yprnk,
+ (xdrproc_t)xdr_ypresp_master, &yprm, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_master: clnt_call");
+ if (!(r = ypprot_err(yprm.stat)))
+ *outname = strdup(yprm.peer);
+ xdr_free((xdrproc_t)xdr_ypresp_master, (char *)&yprm);
+
+ return (r);
+}
+
+int
+yp_maplist_host(CLIENT *client, char *indomain, struct ypmaplist **outmaplist)
+{
+ struct ypresp_maplist ypml;
+ struct timeval tv;
+ int r;
+
+ tv.tv_sec = _yplib_host_timeout;
+ tv.tv_usec = 0;
+
+ memset(&ypml, 0, sizeof ypml);
+
+ r = clnt_call(client, YPPROC_MAPLIST,
+ (xdrproc_t)xdr_domainname, &indomain,
+ (xdrproc_t)xdr_ypresp_maplist, &ypml, tv);
+ if (r != RPC_SUCCESS)
+ clnt_perror(client, "yp_maplist: clnt_call");
+ *outmaplist = ypml.maps;
+ /* NO: xdr_free(xdr_ypresp_maplist, &ypml);*/
+
+ return ypprot_err(ypml.stat);
+}
diff --git a/usr.sbin/ypserv/common/yplib_host.h b/usr.sbin/ypserv/common/yplib_host.h
new file mode 100644
index 000000000000..eabafae9c1b9
--- /dev/null
+++ b/usr.sbin/ypserv/common/yplib_host.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: yplib_host.h,v 1.8 2003/06/02 04:12:38 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@theos.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 _YPLIB_HOST_H_
+#define _YPLIB_HOST_H_
+
+int yp_match_host(CLIENT *client, char *indomain, char *inmap,
+ const char *inkey, int inkeylen, char **outval, int *outvallen);
+int yp_first_host(CLIENT *client, char *indomain, char *inmap,
+ char **outkey, int *outkeylen, char **outval, int *outvallen);
+int yp_next_host(CLIENT *client, char *indomain, char *inmap, char *inkey,
+ int inkeylen, char **outkey, int *outkeylen, char **outval,
+ int *outvallen);
+int yp_master_host(CLIENT *client, char *indomain, char *inmap,
+ char **outname);
+int yp_order_host(CLIENT *client, char *indomain, char *inmap,
+ u_int32_t *outorder);
+int yp_all_host(CLIENT *client, char *indomain, char *inmap,
+ struct ypall_callback *incallback);
+int yp_maplist_host(CLIENT *client, char *indomain,
+ struct ypmaplist **outmaplist);
+CLIENT *yp_bind_local(u_long program, u_long version);
+CLIENT *yp_bind_host(char *server, u_long program, u_long version,
+ u_short port, int usetcp);
+
+#endif /* _YPLIB_HOST_H_ */
diff --git a/usr.sbin/ypserv/yp_access.c b/usr.sbin/ypserv/yp_access.c
new file mode 100644
index 000000000000..fefe96076092
--- /dev/null
+++ b/usr.sbin/ypserv/yp_access.c
@@ -0,0 +1,332 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+#include <stdlib.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/yppasswd.h>
+#include <rpcsvc/ypxfrd.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <db.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <paths.h>
+#include <errno.h>
+#include <sys/param.h>
+#include "yp_extern.h"
+#ifdef TCP_WRAPPER
+#include "tcpd.h"
+#endif
+
+static const char *yp_procs[] = {
+ /* NIS v1 */
+ "ypoldproc_null",
+ "ypoldproc_domain",
+ "ypoldproc_domain_nonack",
+ "ypoldproc_match",
+ "ypoldproc_first",
+ "ypoldproc_next",
+ "ypoldproc_poll",
+ "ypoldproc_push",
+ "ypoldproc_get",
+ "badproc1", /* placeholder */
+ "badproc2", /* placeholder */
+ "badproc3", /* placeholder */
+
+ /* NIS v2 */
+ "ypproc_null",
+ "ypproc_domain",
+ "ypproc_domain_nonack",
+ "ypproc_match",
+ "ypproc_first",
+ "ypproc_next",
+ "ypproc_xfr",
+ "ypproc_clear",
+ "ypproc_all",
+ "ypproc_master",
+ "ypproc_order",
+ "ypproc_maplist"
+};
+
+struct securenet {
+ struct in_addr net;
+ struct in_addr mask;
+ struct securenet *next;
+};
+
+static struct securenet *securenets;
+
+#define LINEBUFSZ 1024
+
+#ifdef TCP_WRAPPER
+int hosts_ctl(char *, char *, char *, char *);
+#endif
+
+/*
+ * Read /var/yp/securenets file and initialize the securenets
+ * list. If the file doesn't exist, we set up a dummy entry that
+ * allows all hosts to connect.
+ */
+void
+load_securenets(void)
+{
+ FILE *fp;
+ char path[MAXPATHLEN + 2];
+ char linebuf[1024 + 2];
+ struct securenet *tmp;
+
+ /*
+ * If securenets is not NULL, we are being called to reload
+ * the list; free the existing list before re-reading the
+ * securenets file.
+ */
+ while (securenets) {
+ tmp = securenets->next;
+ free(securenets);
+ securenets = tmp;
+ }
+
+ snprintf(path, MAXPATHLEN, "%s/securenets", yp_dir);
+
+ if ((fp = fopen(path, "r")) == NULL) {
+ if (errno == ENOENT) {
+ securenets = malloc(sizeof(struct securenet));
+ securenets->net.s_addr = INADDR_ANY;
+ securenets->mask.s_addr = INADDR_ANY;
+ securenets->next = NULL;
+ return;
+ } else {
+ yp_error("fopen(%s) failed: %s", path, strerror(errno));
+ exit(1);
+ }
+ }
+
+ securenets = NULL;
+
+ while (fgets(linebuf, LINEBUFSZ, fp)) {
+ char addr1[20], addr2[20];
+
+ if ((linebuf[0] == '#')
+ || (strspn(linebuf, " \t\r\n") == strlen(linebuf)))
+ continue;
+ if (sscanf(linebuf, "%s %s", addr1, addr2) < 2) {
+ yp_error("badly formatted securenets entry: %s",
+ linebuf);
+ continue;
+ }
+
+ tmp = malloc(sizeof(struct securenet));
+
+ if (!inet_aton((char *)&addr1, (struct in_addr *)&tmp->net)) {
+ yp_error("badly formatted securenets entry: %s", addr1);
+ free(tmp);
+ continue;
+ }
+
+ if (!inet_aton((char *)&addr2, (struct in_addr *)&tmp->mask)) {
+ yp_error("badly formatted securenets entry: %s", addr2);
+ free(tmp);
+ continue;
+ }
+
+ tmp->next = securenets;
+ securenets = tmp;
+ }
+
+ fclose(fp);
+
+}
+
+/*
+ * Access control functions.
+ *
+ * yp_access() checks the mapname and client host address and watches for
+ * the following things:
+ *
+ * - If the client is referencing one of the master.passwd.* or shadow.* maps,
+ * it must be using a privileged port to make its RPC to us. If it is, then
+ * we can assume that the caller is root and allow the RPC to succeed. If it
+ * isn't access is denied.
+ *
+ * - The client's IP address is checked against the securenets rules.
+ * There are two kinds of securenets support: the built-in support,
+ * which is very simple and depends on the presence of a
+ * /var/yp/securenets file, and tcp-wrapper support, which requires
+ * Wietse Venema's libwrap.a and tcpd.h. (Since the tcp-wrapper
+ * package does not ship with FreeBSD, we use the built-in support
+ * by default. Users can recompile the server with the tcp-wrapper library
+ * if they already have it installed and want to use hosts.allow and
+ * hosts.deny to control access instead of having a separate securenets
+ * file.)
+ *
+ * If no /var/yp/securenets file is present, the host access checks
+ * are bypassed and all hosts are allowed to connect.
+ *
+ * The yp_validdomain() function checks the domain specified by the caller
+ * to make sure it's actually served by this server. This is more a sanity
+ * check than an a security check, but this seems to be the best place for
+ * it.
+ */
+
+#ifdef DB_CACHE
+int
+yp_access(const char *map, const char *domain, const struct svc_req *rqstp)
+#else
+int
+yp_access(const char *map, const struct svc_req *rqstp)
+#endif
+{
+ struct sockaddr_in *rqhost;
+ int status_securenets = 0;
+#ifdef TCP_WRAPPER
+ int status_tcpwrap;
+#endif
+ static unsigned long oldaddr = 0;
+ struct securenet *tmp;
+ const char *yp_procedure = NULL;
+ char procbuf[50];
+
+ if (rqstp->rq_prog != YPPASSWDPROG && rqstp->rq_prog != YPPROG) {
+ snprintf(procbuf, sizeof(procbuf), "#%lu/#%lu",
+ (unsigned long)rqstp->rq_prog,
+ (unsigned long)rqstp->rq_proc);
+ yp_procedure = (char *)&procbuf;
+ } else {
+ yp_procedure = rqstp->rq_prog == YPPASSWDPROG ?
+ "yppasswdprog_update" :
+ yp_procs[rqstp->rq_proc + (12 * (rqstp->rq_vers - 1))];
+ }
+
+ rqhost = svc_getcaller(rqstp->rq_xprt);
+
+ if (debug) {
+ yp_error("procedure %s called from %s:%d", yp_procedure,
+ inet_ntoa(rqhost->sin_addr),
+ ntohs(rqhost->sin_port));
+ if (map != NULL)
+ yp_error("client is referencing map \"%s\".", map);
+ }
+
+ /* Check the map name if one was supplied. */
+ if (map != NULL) {
+ if (strchr(map, '/')) {
+ yp_error("embedded slash in map name \"%s\" -- \
+possible spoof attempt from %s:%d",
+ map, inet_ntoa(rqhost->sin_addr),
+ ntohs(rqhost->sin_port));
+ return(1);
+ }
+#ifdef DB_CACHE
+ if ((yp_testflag((char *)map, (char *)domain, YP_SECURE) ||
+#else
+ if ((strstr(map, "master.passwd.") || strstr(map, "shadow.") ||
+#endif
+ (rqstp->rq_prog == YPPROG &&
+ rqstp->rq_proc == YPPROC_XFR) ||
+ (rqstp->rq_prog == YPXFRD_FREEBSD_PROG &&
+ rqstp->rq_proc == YPXFRD_GETMAP)) &&
+ ntohs(rqhost->sin_port) >= IPPORT_RESERVED) {
+ yp_error("access to %s denied -- client %s:%d \
+not privileged", map, inet_ntoa(rqhost->sin_addr), ntohs(rqhost->sin_port));
+ return(1);
+ }
+ }
+
+#ifdef TCP_WRAPPER
+ status_tcpwrap = hosts_ctl("ypserv", STRING_UNKNOWN,
+ inet_ntoa(rqhost->sin_addr), "");
+#endif
+ tmp = securenets;
+ while (tmp) {
+ if (((rqhost->sin_addr.s_addr & ~tmp->mask.s_addr)
+ | tmp->net.s_addr) == rqhost->sin_addr.s_addr) {
+ status_securenets = 1;
+ break;
+ }
+ tmp = tmp->next;
+ }
+
+#ifdef TCP_WRAPPER
+ if (status_securenets == 0 || status_tcpwrap == 0) {
+#else
+ if (status_securenets == 0) {
+#endif
+ /*
+ * One of the following two events occurred:
+ *
+ * (1) The /var/yp/securenets exists and the remote host does not
+ * match any of the networks specified in it.
+ * (2) The hosts.allow file has denied access and TCP_WRAPPER is
+ * defined.
+ *
+ * In either case deny access.
+ */
+ if (rqhost->sin_addr.s_addr != oldaddr) {
+ yp_error("connect from %s:%d to procedure %s refused",
+ inet_ntoa(rqhost->sin_addr),
+ ntohs(rqhost->sin_port),
+ yp_procedure);
+ oldaddr = rqhost->sin_addr.s_addr;
+ }
+ return(1);
+ }
+ return(0);
+
+}
+
+int
+yp_validdomain(const char *domain)
+{
+ struct stat statbuf;
+ char dompath[MAXPATHLEN + 2];
+
+ if (domain == NULL || strstr(domain, "binding") ||
+ !strcmp(domain, ".") || !strcmp(domain, "..") ||
+ strchr(domain, '/') || strlen(domain) > YPMAXDOMAIN)
+ return(1);
+
+ snprintf(dompath, sizeof(dompath), "%s/%s", yp_dir, domain);
+
+ if (stat(dompath, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode))
+ return(1);
+
+
+ return(0);
+}
diff --git a/usr.sbin/ypserv/yp_dblookup.c b/usr.sbin/ypserv/yp_dblookup.c
new file mode 100644
index 000000000000..c0aefb048cb9
--- /dev/null
+++ b/usr.sbin/ypserv/yp_dblookup.c
@@ -0,0 +1,727 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <rpcsvc/yp.h>
+#include "yp_extern.h"
+
+int ypdb_debug = 0;
+enum ypstat yp_errno = YP_TRUE;
+
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+HASHINFO openinfo = {
+ 4096, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ 2048 * 512, /* cachesize */
+ NULL, /* hash */
+ 0, /* lorder */
+};
+
+#ifdef DB_CACHE
+#include <sys/queue.h>
+
+#ifndef MAXDBS
+#define MAXDBS 20
+#endif
+
+static int numdbs = 0;
+
+struct dbent {
+ DB *dbp;
+ char *name;
+ char *key;
+ int size;
+ int flags;
+};
+
+static TAILQ_HEAD(circlehead, circleq_entry) qhead;
+
+struct circleq_entry {
+ struct dbent *dbptr;
+ TAILQ_ENTRY(circleq_entry) links;
+};
+
+/*
+ * Initialize the circular queue.
+ */
+void
+yp_init_dbs(void)
+{
+ TAILQ_INIT(&qhead);
+}
+
+/*
+ * Dynamically allocate an entry for the circular queue.
+ * Return a NULL pointer on failure.
+ */
+static struct circleq_entry *
+yp_malloc_qent(void)
+{
+ register struct circleq_entry *q;
+
+ q = malloc(sizeof(struct circleq_entry));
+ if (q == NULL) {
+ yp_error("failed to malloc() circleq entry");
+ return(NULL);
+ }
+ bzero((char *)q, sizeof(struct circleq_entry));
+ q->dbptr = malloc(sizeof(struct dbent));
+ if (q->dbptr == NULL) {
+ yp_error("failed to malloc() circleq entry");
+ free(q);
+ return(NULL);
+ }
+ bzero((char *)q->dbptr, sizeof(struct dbent));
+
+ return(q);
+}
+
+/*
+ * Free a previously allocated circular queue
+ * entry.
+ */
+static void
+yp_free_qent(struct circleq_entry *q)
+{
+ /*
+ * First, close the database. In theory, this is also
+ * supposed to free the resources allocated by the DB
+ * package, including the memory pointed to by q->dbptr->key.
+ * This means we don't have to free q->dbptr->key here.
+ */
+ if (q->dbptr->dbp) {
+ (void)(q->dbptr->dbp->close)(q->dbptr->dbp);
+ q->dbptr->dbp = NULL;
+ }
+ /*
+ * Then free the database name, which was strdup()'ed.
+ */
+ free(q->dbptr->name);
+
+ /*
+ * Free the rest of the dbent struct.
+ */
+ free(q->dbptr);
+ q->dbptr = NULL;
+
+ /*
+ * Free the circleq struct.
+ */
+ free(q);
+ q = NULL;
+}
+
+/*
+ * Zorch a single entry in the dbent queue and release
+ * all its resources. (This always removes the last entry
+ * in the queue.)
+ */
+static void
+yp_flush(void)
+{
+ register struct circleq_entry *qptr;
+
+ qptr = TAILQ_LAST(&qhead, circlehead);
+ TAILQ_REMOVE(&qhead, qptr, links);
+ yp_free_qent(qptr);
+ numdbs--;
+}
+
+/*
+ * Close all databases, erase all database names and empty the queue.
+ */
+void
+yp_flush_all(void)
+{
+ register struct circleq_entry *qptr;
+
+ while (!TAILQ_EMPTY(&qhead)) {
+ qptr = TAILQ_FIRST(&qhead); /* save this */
+ TAILQ_REMOVE(&qhead, qptr, links);
+ yp_free_qent(qptr);
+ }
+ numdbs = 0;
+
+}
+
+static char *inter_string = "YP_INTERDOMAIN";
+static char *secure_string = "YP_SECURE";
+static int inter_sz = sizeof("YP_INTERDOMAIN") - 1;
+static int secure_sz = sizeof("YP_SECURE") - 1;
+
+static int
+yp_setflags(DB *dbp)
+{
+ DBT key = { NULL, 0 }, data = { NULL, 0 };
+ int flags = 0;
+
+ key.data = inter_string;
+ key.size = inter_sz;
+
+ if (!(dbp->get)(dbp, &key, &data, 0))
+ flags |= YP_INTERDOMAIN;
+
+ key.data = secure_string;
+ key.size = secure_sz;
+
+ if (!(dbp->get)(dbp, &key, &data, 0))
+ flags |= YP_SECURE;
+
+ return(flags);
+}
+
+int
+yp_testflag(char *map, char *domain, int flag)
+{
+ char buf[MAXPATHLEN + 2];
+ register struct circleq_entry *qptr;
+
+ if (map == NULL || domain == NULL)
+ return(0);
+
+ strcpy(buf, domain);
+ strcat(buf, "/");
+ strcat(buf, map);
+
+ TAILQ_FOREACH(qptr, &qhead, links) {
+ if (!strcmp(qptr->dbptr->name, buf)) {
+ if (qptr->dbptr->flags & flag)
+ return(1);
+ else
+ return(0);
+ }
+ }
+
+ if (yp_open_db_cache(domain, map, NULL, 0) == NULL)
+ return(0);
+
+ if (TAILQ_FIRST(&qhead)->dbptr->flags & flag)
+ return(1);
+
+ return(0);
+}
+
+/*
+ * Add a DB handle and database name to the cache. We only maintain
+ * fixed number of entries in the cache, so if we're asked to store
+ * a new entry when all our slots are already filled, we have to kick
+ * out the entry in the last slot to make room.
+ */
+static int
+yp_cache_db(DB *dbp, char *name, int size)
+{
+ register struct circleq_entry *qptr;
+
+ if (numdbs == MAXDBS) {
+ if (ypdb_debug)
+ yp_error("queue overflow -- releasing last slot");
+ yp_flush();
+ }
+
+ /*
+ * Allocate a new queue entry.
+ */
+
+ if ((qptr = yp_malloc_qent()) == NULL) {
+ yp_error("failed to allocate a new cache entry");
+ return(1);
+ }
+
+ qptr->dbptr->dbp = dbp;
+ qptr->dbptr->name = strdup(name);
+ qptr->dbptr->size = size;
+ qptr->dbptr->key = NULL;
+
+ qptr->dbptr->flags = yp_setflags(dbp);
+
+ TAILQ_INSERT_HEAD(&qhead, qptr, links);
+ numdbs++;
+
+ return(0);
+}
+
+/*
+ * Search the list for a database matching 'name.' If we find it,
+ * move it to the head of the list and return its DB handle. If
+ * not, just fail: yp_open_db_cache() will subsequently try to open
+ * the database itself and call yp_cache_db() to add it to the
+ * list.
+ *
+ * The search works like this:
+ *
+ * - The caller specifies the name of a database to locate. We try to
+ * find an entry in our queue with a matching name.
+ *
+ * - If the caller doesn't specify a key or size, we assume that the
+ * first entry that we encounter with a matching name is returned.
+ * This will result in matches regardless of the key/size values
+ * stored in the queue entry.
+ *
+ * - If the caller also specifies a key and length, we check to see
+ * if the key and length saved in the queue entry also matches.
+ * This lets us return a DB handle that's already positioned at the
+ * correct location within a database.
+ *
+ * - Once we have a match, it gets migrated to the top of the queue
+ * so that it will be easier to find if another request for
+ * the same database comes in later.
+ */
+static DB *
+yp_find_db(const char *name, const char *key, int size)
+{
+ register struct circleq_entry *qptr;
+
+ TAILQ_FOREACH(qptr, &qhead, links) {
+ if (!strcmp(qptr->dbptr->name, name)) {
+ if (size) {
+ if (size != qptr->dbptr->size ||
+ strncmp(qptr->dbptr->key, key, size))
+ continue;
+ } else {
+ if (qptr->dbptr->size)
+ continue;
+ }
+ if (qptr != TAILQ_FIRST(&qhead)) {
+ TAILQ_REMOVE(&qhead, qptr, links);
+ TAILQ_INSERT_HEAD(&qhead, qptr, links);
+ }
+ return(qptr->dbptr->dbp);
+ }
+ }
+
+ return(NULL);
+}
+
+/*
+ * Open a DB database and cache the handle for later use. We first
+ * check the cache to see if the required database is already open.
+ * If so, we fetch the handle from the cache. If not, we try to open
+ * the database and save the handle in the cache for later use.
+ */
+DB *
+yp_open_db_cache(const char *domain, const char *map, const char *key,
+ const int size)
+{
+ DB *dbp = NULL;
+ char buf[MAXPATHLEN + 2];
+/*
+ snprintf(buf, sizeof(buf), "%s/%s", domain, map);
+*/
+ yp_errno = YP_TRUE;
+
+ strcpy(buf, domain);
+ strcat(buf, "/");
+ strcat(buf, map);
+
+ if ((dbp = yp_find_db(buf, key, size)) != NULL) {
+ return(dbp);
+ } else {
+ if ((dbp = yp_open_db(domain, map)) != NULL) {
+ if (yp_cache_db(dbp, buf, size)) {
+ (void)(dbp->close)(dbp);
+ yp_errno = YP_YPERR;
+ return(NULL);
+ }
+ }
+ }
+
+ return (dbp);
+}
+#endif
+
+/*
+ * Open a DB database.
+ */
+DB *
+yp_open_db(const char *domain, const char *map)
+{
+ DB *dbp = NULL;
+ char buf[MAXPATHLEN + 2];
+
+ yp_errno = YP_TRUE;
+
+ if (map[0] == '.' || strchr(map, '/')) {
+ yp_errno = YP_BADARGS;
+ return (NULL);
+ }
+
+#ifdef DB_CACHE
+ if (yp_validdomain(domain)) {
+ yp_errno = YP_NODOM;
+ return(NULL);
+ }
+#endif
+ snprintf(buf, sizeof(buf), "%s/%s/%s", yp_dir, domain, map);
+
+#ifdef DB_CACHE
+again:
+#endif
+ dbp = dbopen(buf, O_RDONLY, PERM_SECURE, DB_HASH, NULL);
+
+ if (dbp == NULL) {
+ switch (errno) {
+#ifdef DB_CACHE
+ case ENFILE:
+ /*
+ * We ran out of file descriptors. Nuke an
+ * open one and try again.
+ */
+ yp_error("ran out of file descriptors");
+ yp_flush();
+ goto again;
+ break;
+#endif
+ case ENOENT:
+ yp_errno = YP_NOMAP;
+ break;
+ case EFTYPE:
+ yp_errno = YP_BADDB;
+ break;
+ default:
+ yp_errno = YP_YPERR;
+ break;
+ }
+ }
+
+ return (dbp);
+}
+
+/*
+ * Database access routines.
+ *
+ * - yp_get_record(): retrieve an arbitrary key/data pair given one key
+ * to match against.
+ *
+ * - yp_first_record(): retrieve first key/data base in a database.
+ *
+ * - yp_next_record(): retrieve key/data pair that sequentially follows
+ * the supplied key value in the database.
+ */
+
+#ifdef DB_CACHE
+int
+yp_get_record(DB *dbp, const DBT *key, DBT *data, int allow)
+#else
+int
+yp_get_record(const char *domain, const char *map,
+ const DBT *key, DBT *data, int allow)
+#endif
+{
+#ifndef DB_CACHE
+ DB *dbp;
+#endif
+ int rval = 0;
+#ifndef DB_CACHE
+ static unsigned char buf[YPMAXRECORD];
+#endif
+
+ if (ypdb_debug)
+ yp_error("looking up key [%.*s]",
+ (int)key->size, (char *)key->data);
+
+ /*
+ * Avoid passing back magic "YP_*" entries unless
+ * the caller specifically requested them by setting
+ * the 'allow' flag.
+ */
+ if (!allow && !strncmp(key->data, "YP_", 3))
+ return(YP_NOKEY);
+
+#ifndef DB_CACHE
+ if ((dbp = yp_open_db(domain, map)) == NULL) {
+ return(yp_errno);
+ }
+#endif
+
+ if ((rval = (dbp->get)(dbp, key, data, 0)) != 0) {
+#ifdef DB_CACHE
+ TAILQ_FIRST(&qhead)->dbptr->size = 0;
+#else
+ (void)(dbp->close)(dbp);
+#endif
+ if (rval == 1)
+ return(YP_NOKEY);
+ else
+ return(YP_BADDB);
+ }
+
+ if (ypdb_debug)
+ yp_error("result of lookup: key: [%.*s] data: [%.*s]",
+ (int)key->size, (char *)key->data,
+ (int)data->size, (char *)data->data);
+
+#ifdef DB_CACHE
+ if (TAILQ_FIRST(&qhead)->dbptr->size) {
+ TAILQ_FIRST(&qhead)->dbptr->key = "";
+ TAILQ_FIRST(&qhead)->dbptr->size = 0;
+ }
+#else
+ bcopy(data->data, &buf, data->size);
+ data->data = &buf;
+ (void)(dbp->close)(dbp);
+#endif
+
+ return(YP_TRUE);
+}
+
+int
+yp_first_record(const DB *dbp, DBT *key, DBT *data, int allow)
+{
+ int rval;
+#ifndef DB_CACHE
+ static unsigned char buf[YPMAXRECORD];
+#endif
+
+ if (ypdb_debug)
+ yp_error("retrieving first key in map");
+
+ if ((rval = (dbp->seq)(dbp,key,data,R_FIRST)) != 0) {
+#ifdef DB_CACHE
+ TAILQ_FIRST(&qhead)->dbptr->size = 0;
+#endif
+ if (rval == 1)
+ return(YP_NOKEY);
+ else
+ return(YP_BADDB);
+ }
+
+ /* Avoid passing back magic "YP_*" records. */
+ while (!strncmp(key->data, "YP_", 3) && !allow) {
+ if ((rval = (dbp->seq)(dbp,key,data,R_NEXT)) != 0) {
+#ifdef DB_CACHE
+ TAILQ_FIRST(&qhead)->dbptr->size = 0;
+#endif
+ if (rval == 1)
+ return(YP_NOKEY);
+ else
+ return(YP_BADDB);
+ }
+ }
+
+ if (ypdb_debug)
+ yp_error("result of lookup: key: [%.*s] data: [%.*s]",
+ (int)key->size, (char *)key->data,
+ (int)data->size, (char *)data->data);
+
+#ifdef DB_CACHE
+ if (TAILQ_FIRST(&qhead)->dbptr->size) {
+ TAILQ_FIRST(&qhead)->dbptr->key = key->data;
+ TAILQ_FIRST(&qhead)->dbptr->size = key->size;
+ }
+#else
+ bcopy(data->data, &buf, data->size);
+ data->data = &buf;
+#endif
+
+ return(YP_TRUE);
+}
+
+int
+yp_next_record(const DB *dbp, DBT *key, DBT *data, int all, int allow)
+{
+ static DBT lkey = { NULL, 0 };
+ static DBT ldata = { NULL, 0 };
+ int rval;
+#ifndef DB_CACHE
+ static unsigned char keybuf[YPMAXRECORD];
+ static unsigned char datbuf[YPMAXRECORD];
+#endif
+
+ if (key == NULL || !key->size || key->data == NULL) {
+ rval = yp_first_record(dbp,key,data,allow);
+ if (rval == YP_NOKEY)
+ return(YP_NOMORE);
+ else {
+#ifdef DB_CACHE
+ TAILQ_FIRST(&qhead)->dbptr->key = key->data;
+ TAILQ_FIRST(&qhead)->dbptr->size = key->size;
+#endif
+ return(rval);
+ }
+ }
+
+ if (ypdb_debug)
+ yp_error("retrieving next key, previous was: [%.*s]",
+ (int)key->size, (char *)key->data);
+
+ if (!all) {
+#ifdef DB_CACHE
+ if (TAILQ_FIRST(&qhead)->dbptr->key == NULL) {
+#endif
+ (dbp->seq)(dbp,&lkey,&ldata,R_FIRST);
+ while (key->size != lkey.size ||
+ strncmp(key->data, lkey.data,
+ (int)key->size))
+ if ((dbp->seq)(dbp,&lkey,&ldata,R_NEXT)) {
+#ifdef DB_CACHE
+ TAILQ_FIRST(&qhead)->dbptr->size = 0;
+#endif
+ return(YP_NOKEY);
+ }
+
+#ifdef DB_CACHE
+ }
+#endif
+ }
+
+ if ((dbp->seq)(dbp,key,data,R_NEXT)) {
+#ifdef DB_CACHE
+ TAILQ_FIRST(&qhead)->dbptr->size = 0;
+#endif
+ return(YP_NOMORE);
+ }
+
+ /* Avoid passing back magic "YP_*" records. */
+ while (!strncmp(key->data, "YP_", 3) && !allow)
+ if ((dbp->seq)(dbp,key,data,R_NEXT)) {
+#ifdef DB_CACHE
+ TAILQ_FIRST(&qhead)->dbptr->size = 0;
+#endif
+ return(YP_NOMORE);
+ }
+
+ if (ypdb_debug)
+ yp_error("result of lookup: key: [%.*s] data: [%.*s]",
+ (int)key->size, (char *)key->data,
+ (int)data->size, (char *)data->data);
+
+#ifdef DB_CACHE
+ if (TAILQ_FIRST(&qhead)->dbptr->size) {
+ TAILQ_FIRST(&qhead)->dbptr->key = key->data;
+ TAILQ_FIRST(&qhead)->dbptr->size = key->size;
+ }
+#else
+ bcopy(key->data, &keybuf, key->size);
+ lkey.data = &keybuf;
+ lkey.size = key->size;
+ bcopy(data->data, &datbuf, data->size);
+ data->data = &datbuf;
+#endif
+
+ return(YP_TRUE);
+}
+
+#ifdef DB_CACHE
+/*
+ * Database glue functions.
+ */
+
+static DB *yp_currmap_db = NULL;
+static int yp_allow_db = 0;
+
+ypstat
+yp_select_map(char *map, char *domain, keydat *key, int allow)
+{
+ if (key == NULL)
+ yp_currmap_db = yp_open_db_cache(domain, map, NULL, 0);
+ else
+ yp_currmap_db = yp_open_db_cache(domain, map,
+ key->keydat_val,
+ key->keydat_len);
+
+ yp_allow_db = allow;
+ return(yp_errno);
+}
+
+ypstat
+yp_getbykey(keydat *key, valdat *val)
+{
+ DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
+ ypstat rval;
+
+ db_key.data = key->keydat_val;
+ db_key.size = key->keydat_len;
+
+ rval = yp_get_record(yp_currmap_db,
+ &db_key, &db_val, yp_allow_db);
+
+ if (rval == YP_TRUE) {
+ val->valdat_val = db_val.data;
+ val->valdat_len = db_val.size;
+ }
+
+ return(rval);
+}
+
+ypstat
+yp_firstbykey(keydat *key, valdat *val)
+{
+ DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
+ ypstat rval;
+
+ rval = yp_first_record(yp_currmap_db, &db_key, &db_val, yp_allow_db);
+
+ if (rval == YP_TRUE) {
+ key->keydat_val = db_key.data;
+ key->keydat_len = db_key.size;
+ val->valdat_val = db_val.data;
+ val->valdat_len = db_val.size;
+ }
+
+ return(rval);
+}
+
+ypstat
+yp_nextbykey(keydat *key, valdat *val)
+{
+ DBT db_key = { NULL, 0 }, db_val = { NULL, 0 };
+ ypstat rval;
+
+ db_key.data = key->keydat_val;
+ db_key.size = key->keydat_len;
+
+ rval = yp_next_record(yp_currmap_db, &db_key, &db_val, 0, yp_allow_db);
+
+ if (rval == YP_TRUE) {
+ key->keydat_val = db_key.data;
+ key->keydat_len = db_key.size;
+ val->valdat_val = db_val.data;
+ val->valdat_len = db_val.size;
+ }
+
+ return(rval);
+}
+#endif
diff --git a/usr.sbin/ypserv/yp_dnslookup.c b/usr.sbin/ypserv/yp_dnslookup.c
new file mode 100644
index 000000000000..699c4d7e8018
--- /dev/null
+++ b/usr.sbin/ypserv/yp_dnslookup.c
@@ -0,0 +1,545 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1995, 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 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 Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+/*
+ * Do standard and reverse DNS lookups using the resolver library.
+ * Take care of all the dirty work here so the main program only has to
+ * pass us a pointer to an array of characters.
+ *
+ * We have to use direct resolver calls here otherwise the YP server
+ * could end up looping by calling itself over and over again until
+ * it disappeared up its own belly button.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/fcntl.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <resolv.h>
+#include <unistd.h>
+
+#include <rpcsvc/yp.h>
+#include "yp_extern.h"
+
+static char *
+parse(struct hostent *hp)
+{
+ static char result[MAXHOSTNAMELEN * 2];
+ int i;
+ size_t len;
+ char addr[46];
+
+ if (hp == NULL)
+ return(NULL);
+
+ if (inet_ntop(hp->h_addrtype, hp->h_addr, addr, sizeof(addr)) == NULL)
+ return(NULL);
+
+ len = strlen(addr) + 1 + strlen(hp->h_name);
+ for (i = 0; hp->h_aliases[i]; i++)
+ len += strlen(hp->h_aliases[i]) + 1;
+ len++;
+
+ if (len > sizeof(result))
+ return(NULL);
+
+ bzero(result, sizeof(result));
+ snprintf(result, sizeof(result), "%s %s", addr, hp->h_name);
+ for (i = 0; hp->h_aliases[i]; i++) {
+ strcat(result, " ");
+ strcat(result, hp->h_aliases[i]);
+ }
+
+ return ((char *)&result);
+}
+
+#define MAXPACKET (64*1024)
+#define DEF_TTL 50
+
+#define BY_DNS_ID 1
+#define BY_RPC_XID 2
+
+extern struct hostent *__dns_getanswer(char *, int, char *, int);
+
+static TAILQ_HEAD(dns_qhead, circleq_dnsentry) qhead;
+
+struct circleq_dnsentry {
+ SVCXPRT *xprt;
+ unsigned long xid;
+ struct sockaddr_in client_addr;
+ unsigned long ypvers;
+ unsigned long id;
+ unsigned long ttl;
+ unsigned long type;
+ unsigned short prot_type;
+ char **domain;
+ char *name;
+ int addrtype;
+ int addrlen;
+ uint32_t addr[4]; /* IPv4 or IPv6 */
+ TAILQ_ENTRY(circleq_dnsentry) links;
+};
+
+static int pending = 0;
+
+int
+yp_init_resolver(void)
+{
+ TAILQ_INIT(&qhead);
+ if (!(_res.options & RES_INIT) && res_init() == -1) {
+ yp_error("res_init failed");
+ return(1);
+ }
+ if ((resfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ yp_error("couldn't create socket");
+ return(1);
+ }
+ if (fcntl(resfd, F_SETFL, O_NONBLOCK) == -1) {
+ yp_error("couldn't make resolver socket non-blocking");
+ return(1);
+ }
+ return(0);
+}
+
+static struct
+circleq_dnsentry *yp_malloc_dnsent(void)
+{
+ register struct circleq_dnsentry *q;
+
+ q = malloc(sizeof(struct circleq_dnsentry));
+
+ if (q == NULL) {
+ yp_error("failed to malloc() circleq dns entry");
+ return(NULL);
+ }
+
+ return(q);
+}
+
+/*
+ * Transmit a query.
+ */
+static unsigned long
+yp_send_dns_query(char *name, int type)
+{
+ char buf[MAXPACKET];
+ int n;
+ HEADER *hptr;
+ int ns;
+ int rval;
+ unsigned long id;
+
+ bzero(buf, sizeof(buf));
+
+ n = res_mkquery(QUERY,name,C_IN,type,NULL,0,NULL,buf,sizeof(buf));
+
+ if (n <= 0) {
+ yp_error("res_mkquery failed for %s type %d", name, type);
+ return(0);
+ }
+
+ hptr = (HEADER *)&buf;
+ id = ntohs(hptr->id);
+
+ for (ns = 0; ns < _res.nscount; ns++) {
+ rval = sendto(resfd, buf, n, 0,
+ (struct sockaddr *)&_res.nsaddr_list[ns],
+ sizeof(struct sockaddr));
+ if (rval == -1) {
+ yp_error("sendto failed");
+ return(0);
+ }
+ }
+
+ return(id);
+}
+
+static struct circleq_dnsentry *
+yp_find_dnsqent(unsigned long id, int type)
+{
+ register struct circleq_dnsentry *q;
+
+ TAILQ_FOREACH(q, &qhead, links) {
+ switch (type) {
+ case BY_RPC_XID:
+ if (id == q->xid)
+ return(q);
+ break;
+ case BY_DNS_ID:
+ default:
+ if (id == q->id)
+ return(q);
+ break;
+ }
+ }
+ return (NULL);
+}
+
+static void
+yp_send_dns_reply(struct circleq_dnsentry *q, char *buf)
+{
+ ypresponse result_v1;
+ ypresp_val result_v2;
+ unsigned long xid;
+ struct sockaddr_in client_addr;
+ xdrproc_t xdrfunc;
+ char *result;
+
+ /*
+ * Set up correct reply struct and
+ * XDR filter depending on ypvers.
+ */
+ switch (q->ypvers) {
+ case YPVERS:
+ bzero((char *)&result_v2, sizeof(result_v2));
+
+ if (buf == NULL)
+ result_v2.stat = YP_NOKEY;
+ else {
+ result_v2.val.valdat_len = strlen(buf);
+ result_v2.val.valdat_val = buf;
+ result_v2.stat = YP_TRUE;
+ }
+ result = (char *)&result_v2;
+ xdrfunc = (xdrproc_t)xdr_ypresp_val;
+ break;
+ case YPOLDVERS:
+ /*
+ * The odds are we will _never_ execute this
+ * particular code, but we include it anyway
+ * for the sake of completeness.
+ */
+ bzero((char *)&result_v1, sizeof(result_v1));
+ result_v1.yp_resptype = YPRESP_VAL;
+
+#define YPVAL ypresponse_u.yp_resp_valtype
+ if (buf == NULL)
+ result_v1.YPVAL.stat = YP_NOKEY;
+ else {
+ result_v1.YPVAL.val.valdat_len = strlen(buf);
+ result_v1.YPVAL.val.valdat_val = buf;
+ result_v1.YPVAL.stat = YP_TRUE;
+ }
+ result = (char *)&result_v1;
+ xdrfunc = (xdrproc_t)xdr_ypresponse;
+ break;
+ default:
+ yp_error("bad YP program version (%lu)!", q->ypvers);
+ return;
+ break;
+ }
+
+ if (debug)
+ yp_error("sending dns reply to %s (%lu)",
+ inet_ntoa(q->client_addr.sin_addr), q->id);
+ /*
+ * XXX This is disgusting. There's basically one transport
+ * handle for UDP, but we're holding off on replying to a
+ * client until we're ready, by which time we may have received
+ * several other queries from other clients with different
+ * transaction IDs. So to make the delayed response thing work,
+ * we have to save the transaction ID and client address of
+ * each request, then jam them into the transport handle when
+ * we're ready to send a reply. Then after we've send the reply,
+ * we put the old transaction ID and remote address back the
+ * way we found 'em. This is _INCREDIBLY_ non-portable; it's
+ * not even supported by the RPC library.
+ */
+ /*
+ * XXX Don't frob the transaction ID for TCP handles.
+ */
+ if (q->prot_type == SOCK_DGRAM)
+ xid = svcudp_set_xid(q->xprt, q->xid);
+ client_addr = q->xprt->xp_raddr;
+ q->xprt->xp_raddr = q->client_addr;
+
+ if (!svc_sendreply(q->xprt, xdrfunc, result))
+ yp_error("svc_sendreply failed");
+
+ /*
+ * Now that we sent the reply,
+ * put the handle back the way it was.
+ */
+ if (q->prot_type == SOCK_DGRAM)
+ svcudp_set_xid(q->xprt, xid);
+ q->xprt->xp_raddr = client_addr;
+}
+
+/*
+ * Decrement TTL on all queue entries, possibly nuking
+ * any that have been around too long without being serviced.
+ */
+void
+yp_prune_dnsq(void)
+{
+ register struct circleq_dnsentry *q, *n;
+
+ q = TAILQ_FIRST(&qhead);
+ while (q != NULL) {
+ q->ttl--;
+ n = TAILQ_NEXT(q, links);
+ if (!q->ttl) {
+ TAILQ_REMOVE(&qhead, q, links);
+ free(q->name);
+ free(q);
+ pending--;
+ }
+ q = n;
+ }
+
+ if (pending < 0)
+ pending = 0;
+}
+
+/*
+ * Data is pending on the DNS socket; check for valid replies
+ * to our queries and dispatch them to waiting clients.
+ */
+void
+yp_run_dnsq(void)
+{
+ register struct circleq_dnsentry *q;
+ char buf[sizeof(HEADER) + MAXPACKET];
+ struct sockaddr_in sin;
+ socklen_t len;
+ int rval;
+ HEADER *hptr;
+ struct hostent *hent;
+
+ if (debug)
+ yp_error("running dns queue");
+
+ bzero(buf, sizeof(buf));
+
+ len = sizeof(struct sockaddr_in);
+ rval = recvfrom(resfd, buf, sizeof(buf), 0,
+ (struct sockaddr *)&sin, &len);
+
+ if (rval == -1) {
+ yp_error("recvfrom failed: %s", strerror(errno));
+ return;
+ }
+
+ /*
+ * We may have data left in the socket that represents
+ * replies to earlier queries that we don't care about
+ * anymore. If there are no lookups pending or the packet
+ * ID doesn't match any of the queue IDs, just drop it
+ * on the floor.
+ */
+ hptr = (HEADER *)&buf;
+ if (!pending ||
+ (q = yp_find_dnsqent(ntohs(hptr->id), BY_DNS_ID)) == NULL) {
+ /* ignore */
+ return;
+ }
+
+ if (debug)
+ yp_error("got dns reply from %s", inet_ntoa(sin.sin_addr));
+
+ hent = __dns_getanswer(buf, rval, q->name, q->type);
+
+ if (hent != NULL) {
+ if (q->type == T_PTR) {
+ hent->h_addr = (char *)q->addr;
+ hent->h_addrtype = q->addrtype;
+ hent->h_length = q->addrlen;
+ }
+ }
+
+ /* Got an answer ready for a client -- send it off. */
+ yp_send_dns_reply(q, parse(hent));
+ pending--;
+ TAILQ_REMOVE(&qhead, q, links);
+ free(q->name);
+ free(q);
+
+ /* Decrement TTLs on other entries while we're here. */
+ yp_prune_dnsq();
+}
+
+/*
+ * Queue and transmit an asynchronous DNS hostname lookup.
+ */
+ypstat
+yp_async_lookup_name(struct svc_req *rqstp, char *name, int af)
+{
+ register struct circleq_dnsentry *q;
+ socklen_t len;
+ int type;
+
+ /* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
+ type = -1;
+ len = sizeof(type);
+ if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
+ SO_TYPE, &type, &len) == -1) {
+ yp_error("getsockopt failed: %s", strerror(errno));
+ return(YP_YPERR);
+ }
+
+ /* Avoid transmitting dupe requests. */
+ if (type == SOCK_DGRAM &&
+ yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
+ return(YP_TRUE);
+
+ if ((q = yp_malloc_dnsent()) == NULL)
+ return(YP_YPERR);
+
+ q->type = (af == AF_INET) ? T_A : T_AAAA;
+ q->ttl = DEF_TTL;
+ q->xprt = rqstp->rq_xprt;
+ q->ypvers = rqstp->rq_vers;
+ q->prot_type = type;
+ if (q->prot_type == SOCK_DGRAM)
+ q->xid = svcudp_get_xid(q->xprt);
+ q->client_addr = q->xprt->xp_raddr;
+ q->domain = _res.dnsrch;
+ q->id = yp_send_dns_query(name, q->type);
+
+ if (q->id == 0) {
+ yp_error("DNS query failed");
+ free(q);
+ return(YP_YPERR);
+ }
+
+ q->name = strdup(name);
+ TAILQ_INSERT_HEAD(&qhead, q, links);
+ pending++;
+
+ if (debug)
+ yp_error("queueing async DNS name lookup (%lu)", q->id);
+
+ yp_prune_dnsq();
+ return(YP_TRUE);
+}
+
+/*
+ * Queue and transmit an asynchronous DNS IP address lookup.
+ */
+ypstat
+yp_async_lookup_addr(struct svc_req *rqstp, char *addr, int af)
+{
+ register struct circleq_dnsentry *q;
+ char buf[MAXHOSTNAMELEN], *qp;
+ uint32_t abuf[4]; /* IPv4 or IPv6 */
+ u_char *uaddr = (u_char *)abuf;
+ socklen_t len;
+ int type, n;
+
+ /* Check for SOCK_DGRAM or SOCK_STREAM -- we need to know later */
+ type = -1;
+ len = sizeof(type);
+ if (getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET,
+ SO_TYPE, &type, &len) == -1) {
+ yp_error("getsockopt failed: %s", strerror(errno));
+ return(YP_YPERR);
+ }
+
+ /* Avoid transmitting dupe requests. */
+ if (type == SOCK_DGRAM &&
+ yp_find_dnsqent(svcudp_get_xid(rqstp->rq_xprt),BY_RPC_XID) != NULL)
+ return(YP_TRUE);
+
+ switch (af) {
+ case AF_INET:
+ if (inet_aton(addr, (struct in_addr *)uaddr) != 1)
+ return(YP_NOKEY);
+ snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa",
+ (uaddr[3] & 0xff), (uaddr[2] & 0xff),
+ (uaddr[1] & 0xff), (uaddr[0] & 0xff));
+ len = INADDRSZ;
+ break;
+ case AF_INET6:
+ if (inet_pton(af, addr, uaddr) != 1)
+ return(YP_NOKEY);
+ qp = buf;
+ for (n = IN6ADDRSZ - 1; n >= 0; n--) {
+ qp += (size_t)sprintf(qp, "%x.%x.", uaddr[n] & 0xf,
+ (uaddr[n] >> 4) & 0xf);
+ }
+ strlcat(buf, "ip6.arpa", sizeof(buf));
+ len = IN6ADDRSZ;
+ break;
+ default:
+ return(YP_YPERR);
+ }
+
+ if ((q = yp_malloc_dnsent()) == NULL)
+ return(YP_YPERR);
+
+ if (debug)
+ yp_error("DNS address is: %s", buf);
+
+ q->type = T_PTR;
+ q->ttl = DEF_TTL;
+ q->xprt = rqstp->rq_xprt;
+ q->ypvers = rqstp->rq_vers;
+ q->domain = NULL;
+ q->prot_type = type;
+ if (q->prot_type == SOCK_DGRAM)
+ q->xid = svcudp_get_xid(q->xprt);
+ q->client_addr = q->xprt->xp_raddr;
+ q->id = yp_send_dns_query(buf, q->type);
+
+ if (q->id == 0) {
+ yp_error("DNS query failed");
+ free(q);
+ return(YP_YPERR);
+ }
+
+ memcpy(q->addr, uaddr, len);
+ q->addrlen = len;
+ q->addrtype = af;
+ q->name = strdup(buf);
+ TAILQ_INSERT_HEAD(&qhead, q, links);
+ pending++;
+
+ if (debug)
+ yp_error("queueing async DNS address lookup (%lu)", q->id);
+
+ yp_prune_dnsq();
+ return(YP_TRUE);
+}
diff --git a/usr.sbin/ypserv/yp_error.c b/usr.sbin/ypserv/yp_error.c
new file mode 100644
index 000000000000..314c11d2514d
--- /dev/null
+++ b/usr.sbin/ypserv/yp_error.c
@@ -0,0 +1,71 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+/*
+ * error logging/reporting facilities
+ * stolen from /usr/libexec/mail.local via ypserv
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include "yp_extern.h"
+
+extern int _rpcpmstart;
+extern char *progname;
+static void __verr(const char *fmt, va_list ap) __printflike(1, 0);
+
+static void
+__verr(const char *fmt, va_list ap)
+{
+ if (debug && !_rpcpmstart) {
+ fprintf(stderr,"%s: ",progname);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ } else {
+ vsyslog(LOG_NOTICE, fmt, ap);
+ }
+}
+
+void
+yp_error(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ __verr(fmt,ap);
+ va_end(ap);
+}
diff --git a/usr.sbin/ypserv/yp_extern.h b/usr.sbin/ypserv/yp_extern.h
new file mode 100644
index 000000000000..3fe03df71b88
--- /dev/null
+++ b/usr.sbin/ypserv/yp_extern.h
@@ -0,0 +1,115 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <db.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp.h>
+
+#ifndef _PATH_YP
+#define _PATH_YP "/var/yp/"
+#endif
+
+#ifndef _PATH_LIBEXEC
+#define _PATH_LIBEXEC "/usr/libexec/"
+#endif
+
+#ifndef MAX_CHILDREN
+#define MAX_CHILDREN 20
+#endif
+
+#define YP_SECURE 0x1
+#define YP_INTERDOMAIN 0x2
+
+/*
+ * External functions and variables.
+ */
+
+extern int debug;
+extern int ypdb_debug;
+extern int do_dns;
+extern int children;
+extern int resfd;
+extern char *progname;
+extern char *yp_dir;
+extern pid_t yp_pid;
+
+extern enum ypstat yp_errno;
+extern void yp_error(const char *, ...) __printflike(1, 2);
+#ifdef DB_CACHE
+extern int yp_get_record(DB *, const DBT *, DBT *, int);
+#else
+extern int yp_get_record(const char *, const char *, const DBT *, DBT *, int);
+#endif
+extern int yp_first_record(const DB *, DBT *, DBT *, int);
+extern int yp_next_record(const DB *, DBT *, DBT *, int, int);
+extern char *yp_dnsname(char *);
+extern char *yp_dnsaddr(const char *);
+#ifdef DB_CACHE
+extern int yp_access(const char *, const char *, const struct svc_req *);
+#else
+extern int yp_access(const char *, const struct svc_req *);
+#endif
+extern int yp_validdomain(const char *);
+extern DB *yp_open_db(const char *, const char *);
+extern DB *yp_open_db_cache(const char *, const char *, const char *, int);
+extern void yp_flush_all(void);
+extern void yp_init_dbs(void);
+extern int yp_testflag(char *, char *, int);
+extern void load_securenets(void);
+
+#ifdef DB_CACHE
+extern ypstat yp_select_map(char *, char *, keydat *, int);
+extern ypstat yp_getbykey(keydat *, valdat *);
+extern ypstat yp_firstbykey(keydat *, valdat *);
+extern ypstat yp_nextbykey(keydat *, valdat *);
+#endif
+
+extern unsigned long svcudp_set_xid(SVCXPRT *, unsigned long);
+extern unsigned long svcudp_get_xid(SVCXPRT *);
+
+#ifndef RESOLVER_TIMEOUT
+#define RESOLVER_TIMEOUT 3600
+#endif
+
+extern int yp_init_resolver(void);
+extern void yp_run_dnsq(void);
+extern void yp_prune_dnsq(void);
+extern ypstat yp_async_lookup_name(struct svc_req *, char *, int);
+extern ypstat yp_async_lookup_addr(struct svc_req *, char *, int);
diff --git a/usr.sbin/ypserv/yp_main.c b/usr.sbin/ypserv/yp_main.c
new file mode 100644
index 000000000000..d326603a9229
--- /dev/null
+++ b/usr.sbin/ypserv/yp_main.c
@@ -0,0 +1,578 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+/*
+ * ypserv startup function.
+ * We need out own main() since we have to do some additional work
+ * that rpcgen won't do for us. Most of this file was generated using
+ * rpcgen.new, and later modified.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include "yp.h"
+#include <err.h>
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h> /* getenv, exit */
+#include <string.h> /* strcmp */
+#include <syslog.h>
+#include <unistd.h>
+#ifdef __cplusplus
+#include <sysent.h> /* getdtablesize, open */
+#endif /* __cplusplus */
+#include <netinet/in.h>
+#include <netdb.h>
+#include "yp_extern.h"
+#include <netconfig.h>
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+
+#ifndef SIG_PF
+#define SIG_PF void(*)(int)
+#endif
+
+#define _RPCSVC_CLOSEDOWN 120
+int _rpcpmstart; /* Started by a port monitor ? */
+static int _rpcfdtype; /* Whether Stream or Datagram? */
+static int _rpcaf;
+static int _rpcfd;
+
+/* States a server can be in wrt request */
+#define _IDLE 0
+#define _SERVED 1
+#define _SERVING 2
+
+extern void ypprog_1(struct svc_req *, SVCXPRT *);
+extern void ypprog_2(struct svc_req *, SVCXPRT *);
+extern int _rpc_dtablesize(void);
+extern int _rpcsvcstate; /* Set when a request is serviced */
+char *progname = "ypserv";
+char *yp_dir = _PATH_YP;
+int debug;
+int do_dns = 0;
+int resfd;
+
+struct socklistent {
+ int sle_sock;
+ struct sockaddr_storage sle_ss;
+ SLIST_ENTRY(socklistent) sle_next;
+};
+static SLIST_HEAD(, socklistent) sle_head =
+ SLIST_HEAD_INITIALIZER(sle_head);
+
+struct bindaddrlistent {
+ const char *ble_hostname;
+ SLIST_ENTRY(bindaddrlistent) ble_next;
+};
+static SLIST_HEAD(, bindaddrlistent) ble_head =
+ SLIST_HEAD_INITIALIZER(ble_head);
+
+static char *servname = "0";
+
+static
+void _msgout(char* msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ if (debug) {
+ if (_rpcpmstart)
+ vsyslog(LOG_ERR, msg, ap);
+ else
+ vwarnx(msg, ap);
+ } else
+ vsyslog(LOG_ERR, msg, ap);
+ va_end(ap);
+}
+
+pid_t yp_pid;
+
+static void
+yp_svc_run(void)
+{
+#ifdef FD_SETSIZE
+ fd_set readfds;
+#else
+ int readfds;
+#endif /* def FD_SETSIZE */
+ int fd_setsize = _rpc_dtablesize();
+ struct timeval timeout;
+
+ /* Establish the identity of the parent ypserv process. */
+ yp_pid = getpid();
+
+ for (;;) {
+#ifdef FD_SETSIZE
+ readfds = svc_fdset;
+#else
+ readfds = svc_fds;
+#endif /* def FD_SETSIZE */
+
+ FD_SET(resfd, &readfds);
+
+ timeout.tv_sec = RESOLVER_TIMEOUT;
+ timeout.tv_usec = 0;
+ switch (select(fd_setsize, &readfds, NULL, NULL,
+ &timeout)) {
+ case -1:
+ if (errno == EINTR) {
+ continue;
+ }
+ warn("svc_run: - select failed");
+ return;
+ case 0:
+ if (getpid() == yp_pid)
+ yp_prune_dnsq();
+ break;
+ default:
+ if (getpid() == yp_pid) {
+ if (FD_ISSET(resfd, &readfds)) {
+ yp_run_dnsq();
+ FD_CLR(resfd, &readfds);
+ }
+ svc_getreqset(&readfds);
+ }
+ }
+ if (yp_pid != getpid())
+ _exit(0);
+ }
+}
+
+static void
+unregister(void)
+{
+ (void)svc_unreg(YPPROG, YPVERS);
+ (void)svc_unreg(YPPROG, YPOLDVERS);
+}
+
+static void
+reaper(int sig)
+{
+ int status;
+ int saved_errno;
+
+ saved_errno = errno;
+
+ if (sig == SIGHUP) {
+ load_securenets();
+#ifdef DB_CACHE
+ yp_flush_all();
+#endif
+ errno = saved_errno;
+ return;
+ }
+
+ if (sig == SIGCHLD) {
+ while (wait3(&status, WNOHANG, NULL) > 0)
+ children--;
+ } else {
+ unregister();
+ exit(0);
+ }
+ errno = saved_errno;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: ypserv [-h addr] [-d] [-n] [-p path] [-P port]\n");
+ exit(1);
+}
+
+static void
+closedown(int sig)
+{
+ if (_rpcsvcstate == _IDLE) {
+ extern fd_set svc_fdset;
+ static int size;
+ int i, openfd;
+
+ if (_rpcfdtype == SOCK_DGRAM) {
+ unregister();
+ exit(0);
+ }
+ if (size == 0) {
+ size = getdtablesize();
+ }
+ for (i = 0, openfd = 0; i < size && openfd < 2; i++)
+ if (FD_ISSET(i, &svc_fdset))
+ openfd++;
+ if (openfd <= 1) {
+ unregister();
+ exit(0);
+ }
+ }
+ if (_rpcsvcstate == _SERVED)
+ _rpcsvcstate = _IDLE;
+
+ (void) signal(SIGALRM, (SIG_PF) closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN/2);
+}
+
+static int
+create_service(const int sock, const struct netconfig *nconf,
+ const struct __rpc_sockinfo *si)
+{
+ int error;
+
+ SVCXPRT *transp;
+ struct addrinfo hints, *res, *res0;
+ struct socklistent *slep;
+ struct bindaddrlistent *blep;
+ struct netbuf svcaddr;
+
+ SLIST_INIT(&sle_head);
+ memset(&hints, 0, sizeof(hints));
+ memset(&svcaddr, 0, sizeof(svcaddr));
+
+ hints.ai_family = si->si_af;
+ hints.ai_socktype = si->si_socktype;
+ hints.ai_protocol = si->si_proto;
+
+ /*
+ * Build socketlist from bindaddrlist.
+ */
+ if (sock == RPC_ANYFD) {
+ SLIST_FOREACH(blep, &ble_head, ble_next) {
+ if (blep->ble_hostname == NULL)
+ hints.ai_flags = AI_PASSIVE;
+ else
+ hints.ai_flags = 0;
+ error = getaddrinfo(blep->ble_hostname, servname,
+ &hints, &res0);
+ if (error) {
+ _msgout("getaddrinfo(): %s",
+ gai_strerror(error));
+ return -1;
+ }
+ for (res = res0; res; res = res->ai_next) {
+ int s;
+
+ s = __rpc_nconf2fd(nconf);
+ if (s < 0) {
+ if (errno == EAFNOSUPPORT)
+ _msgout("unsupported"
+ " transport: %s",
+ nconf->nc_netid);
+ else
+ _msgout("cannot create"
+ " %s socket: %s",
+ nconf->nc_netid,
+ strerror(errno));
+ freeaddrinfo(res0);
+ return -1;
+ }
+ if (bindresvport_sa(s, res->ai_addr) == -1) {
+ if ((errno != EPERM) ||
+ (bind(s, res->ai_addr,
+ res->ai_addrlen) == -1)) {
+ _msgout("cannot bind "
+ "%s socket: %s",
+ nconf->nc_netid,
+ strerror(errno));
+ freeaddrinfo(res0);
+ close(sock);
+ return -1;
+ }
+ }
+ if (nconf->nc_semantics != NC_TPI_CLTS)
+ listen(s, SOMAXCONN);
+
+ slep = malloc(sizeof(*slep));
+ if (slep == NULL) {
+ _msgout("malloc failed: %s",
+ strerror(errno));
+ freeaddrinfo(res0);
+ close(s);
+ return -1;
+ }
+ memset(slep, 0, sizeof(*slep));
+ memcpy(&slep->sle_ss, res->ai_addr,
+ res->ai_addrlen);
+ slep->sle_sock = s;
+ SLIST_INSERT_HEAD(&sle_head, slep, sle_next);
+
+ /*
+ * If servname == "0", redefine it by using
+ * the bound socket.
+ */
+ if (strncmp("0", servname, 1) == 0) {
+ struct sockaddr *sap;
+ socklen_t slen;
+ char *sname;
+
+ sname = malloc(NI_MAXSERV);
+ if (sname == NULL) {
+ _msgout("malloc(): %s",
+ strerror(errno));
+ freeaddrinfo(res0);
+ close(s);
+ return -1;
+ }
+ memset(sname, 0, NI_MAXSERV);
+
+ sap = (struct sockaddr *)&slep->sle_ss;
+ slen = sizeof(*sap);
+ error = getsockname(s, sap, &slen);
+ if (error) {
+ _msgout("getsockname(): %s",
+ strerror(errno));
+ freeaddrinfo(res0);
+ close(s);
+ free(sname);
+ return -1;
+ }
+ error = getnameinfo(sap, slen,
+ NULL, 0,
+ sname, NI_MAXSERV,
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (error) {
+ _msgout("getnameinfo(): %s",
+ strerror(errno));
+ freeaddrinfo(res0);
+ close(s);
+ free(sname);
+ return -1;
+ }
+ servname = sname;
+ }
+ }
+ freeaddrinfo(res0);
+ }
+ } else {
+ slep = malloc(sizeof(*slep));
+ if (slep == NULL) {
+ _msgout("malloc failed: %s", strerror(errno));
+ return -1;
+ }
+ memset(slep, 0, sizeof(*slep));
+ slep->sle_sock = sock;
+ SLIST_INSERT_HEAD(&sle_head, slep, sle_next);
+ }
+
+ /*
+ * Traverse socketlist and create rpc service handles for each socket.
+ */
+ SLIST_FOREACH(slep, &sle_head, sle_next) {
+ if (nconf->nc_semantics == NC_TPI_CLTS)
+ transp = svc_dg_create(slep->sle_sock, 0, 0);
+ else
+ transp = svc_vc_create(slep->sle_sock, RPC_MAXDATASIZE,
+ RPC_MAXDATASIZE);
+ if (transp == NULL) {
+ _msgout("unable to create service: %s",
+ nconf->nc_netid);
+ continue;
+ }
+ if (!svc_reg(transp, YPPROG, YPOLDVERS, ypprog_1, NULL)) {
+ svc_destroy(transp);
+ close(slep->sle_sock);
+ _msgout("unable to register (YPPROG, YPOLDVERS, %s):"
+ " %s", nconf->nc_netid, strerror(errno));
+ continue;
+ }
+ if (!svc_reg(transp, YPPROG, YPVERS, ypprog_2, NULL)) {
+ svc_destroy(transp);
+ close(slep->sle_sock);
+ _msgout("unable to register (YPPROG, YPVERS, %s): %s",
+ nconf->nc_netid, strerror(errno));
+ continue;
+ }
+ }
+ while(!(SLIST_EMPTY(&sle_head)))
+ SLIST_REMOVE_HEAD(&sle_head, sle_next);
+
+ /*
+ * Register RPC service to rpcbind by using AI_PASSIVE address.
+ */
+ hints.ai_flags = AI_PASSIVE;
+ error = getaddrinfo(NULL, servname, &hints, &res0);
+ if (error) {
+ _msgout("getaddrinfo(): %s", gai_strerror(error));
+ return -1;
+ }
+ svcaddr.buf = res0->ai_addr;
+ svcaddr.len = res0->ai_addrlen;
+
+ if (si->si_af == AF_INET) {
+ /* XXX: ignore error intentionally */
+ rpcb_set(YPPROG, YPOLDVERS, nconf, &svcaddr);
+ }
+ /* XXX: ignore error intentionally */
+ rpcb_set(YPPROG, YPVERS, nconf, &svcaddr);
+ freeaddrinfo(res0);
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ int error;
+ int ntrans;
+
+ void *nc_handle;
+ struct netconfig *nconf;
+ struct __rpc_sockinfo si;
+ struct bindaddrlistent *blep;
+
+ memset(&si, 0, sizeof(si));
+ SLIST_INIT(&ble_head);
+
+ while ((ch = getopt(argc, argv, "dh:np:P:")) != -1) {
+ switch (ch) {
+ case 'd':
+ debug = ypdb_debug = 1;
+ break;
+ case 'h':
+ blep = malloc(sizeof(*blep));
+ if (blep == NULL)
+ err(1, "malloc() failed: -h %s", optarg);
+ blep->ble_hostname = optarg;
+ SLIST_INSERT_HEAD(&ble_head, blep, ble_next);
+ break;
+ case 'n':
+ do_dns = 1;
+ break;
+ case 'p':
+ yp_dir = optarg;
+ break;
+ case 'P':
+ servname = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ /*
+ * Add "anyaddr" entry if no -h is specified.
+ */
+ if (SLIST_EMPTY(&ble_head)) {
+ blep = malloc(sizeof(*blep));
+ if (blep == NULL)
+ err(1, "malloc() failed");
+ memset(blep, 0, sizeof(*blep));
+ SLIST_INSERT_HEAD(&ble_head, blep, ble_next);
+ }
+
+ load_securenets();
+ yp_init_resolver();
+#ifdef DB_CACHE
+ yp_init_dbs();
+#endif
+ nc_handle = setnetconfig();
+ if (nc_handle == NULL)
+ err(1, "cannot read %s", NETCONFIG);
+ if (__rpc_fd2sockinfo(0, &si) != 0) {
+ /* invoked from inetd */
+ _rpcpmstart = 1;
+ _rpcfdtype = si.si_socktype;
+ _rpcaf = si.si_af;
+ _rpcfd = 0;
+ openlog("ypserv", LOG_PID, LOG_DAEMON);
+ } else {
+ /* standalone mode */
+ if (!debug) {
+ if (daemon(0,0)) {
+ err(1,"cannot fork");
+ }
+ openlog("ypserv", LOG_PID, LOG_DAEMON);
+ }
+ _rpcpmstart = 0;
+ _rpcaf = AF_INET;
+ _rpcfd = RPC_ANYFD;
+ unregister();
+ }
+
+ if (madvise(NULL, 0, MADV_PROTECT) != 0)
+ _msgout("madvise(): %s", strerror(errno));
+
+ /*
+ * Create RPC service for each transport.
+ */
+ ntrans = 0;
+ while((nconf = getnetconfig(nc_handle))) {
+ if ((nconf->nc_flag & NC_VISIBLE)) {
+ if (__rpc_nconf2sockinfo(nconf, &si) == 0) {
+ _msgout("cannot get information for %s. "
+ "Ignored.", nconf->nc_netid);
+ continue;
+ }
+ if (_rpcpmstart) {
+ if (si.si_socktype != _rpcfdtype ||
+ si.si_af != _rpcaf)
+ continue;
+ } else if (si.si_af != _rpcaf)
+ continue;
+ error = create_service(_rpcfd, nconf, &si);
+ if (error) {
+ endnetconfig(nc_handle);
+ exit(1);
+ }
+ ntrans++;
+ }
+ }
+ endnetconfig(nc_handle);
+ while(!(SLIST_EMPTY(&ble_head)))
+ SLIST_REMOVE_HEAD(&ble_head, ble_next);
+ if (ntrans == 0) {
+ _msgout("no transport is available. Aborted.");
+ exit(1);
+ }
+ if (_rpcpmstart) {
+ (void) signal(SIGALRM, (SIG_PF) closedown);
+ (void) alarm(_RPCSVC_CLOSEDOWN/2);
+ }
+/*
+ * Make sure SIGPIPE doesn't blow us away while servicing TCP
+ * connections.
+ */
+ (void) signal(SIGPIPE, SIG_IGN);
+ (void) signal(SIGCHLD, (SIG_PF) reaper);
+ (void) signal(SIGTERM, (SIG_PF) reaper);
+ (void) signal(SIGINT, (SIG_PF) reaper);
+ (void) signal(SIGHUP, (SIG_PF) reaper);
+ yp_svc_run();
+ _msgout("svc_run returned");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/usr.sbin/ypserv/yp_server.c b/usr.sbin/ypserv/yp_server.c
new file mode 100644
index 000000000000..62e45e35cbe1
--- /dev/null
+++ b/usr.sbin/ypserv/yp_server.c
@@ -0,0 +1,985 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1995
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+#include "yp.h"
+#include "yp_extern.h"
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+
+int children = 0;
+
+#define MASTER_STRING "YP_MASTER_NAME"
+#define MASTER_SZ sizeof(MASTER_STRING) - 1
+#define ORDER_STRING "YP_LAST_MODIFIED"
+#define ORDER_SZ sizeof(ORDER_STRING) - 1
+
+static pid_t
+yp_fork(void)
+{
+ if (yp_pid != getpid()) {
+ yp_error("child %d trying to fork!", getpid());
+ errno = EEXIST;
+ return(-1);
+ }
+
+ return(fork());
+}
+
+/*
+ * NIS v2 support. This is where most of the action happens.
+ */
+
+void *
+ypproc_null_2_svc(void *argp, struct svc_req *rqstp)
+{
+ static char * result;
+ static char rval = 0;
+
+#ifdef DB_CACHE
+ if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
+#else
+ if (yp_access(NULL, (struct svc_req *)rqstp))
+#endif
+ return(NULL);
+
+ result = &rval;
+
+ return((void *) &result);
+}
+
+bool_t *
+ypproc_domain_2_svc(domainname *argp, struct svc_req *rqstp)
+{
+ static bool_t result;
+
+#ifdef DB_CACHE
+ if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(NULL, (struct svc_req *)rqstp)) {
+#endif
+ result = FALSE;
+ return (&result);
+ }
+
+ if (argp == NULL || yp_validdomain(*argp))
+ result = FALSE;
+ else
+ result = TRUE;
+
+ return (&result);
+}
+
+bool_t *
+ypproc_domain_nonack_2_svc(domainname *argp, struct svc_req *rqstp)
+{
+ static bool_t result;
+
+#ifdef DB_CACHE
+ if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
+#else
+ if (yp_access(NULL, (struct svc_req *)rqstp))
+#endif
+ return (NULL);
+
+ if (argp == NULL || yp_validdomain(*argp))
+ return (NULL);
+ else
+ result = TRUE;
+
+ return (&result);
+}
+
+ypresp_val *
+ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp)
+{
+ static ypresp_val result;
+
+ result.val.valdat_val = "";
+ result.val.valdat_len = 0;
+
+#ifdef DB_CACHE
+ if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(argp->map, (struct svc_req *)rqstp)) {
+#endif
+ result.stat = YP_YPERR;
+ return (&result);
+ }
+
+ if (argp->domain == NULL || argp->map == NULL) {
+ result.stat = YP_BADARGS;
+ return (&result);
+ }
+
+ if (yp_select_map(argp->map, argp->domain, NULL, 1) != YP_TRUE) {
+ result.stat = yp_errno;
+ return(&result);
+ }
+
+ result.stat = yp_getbykey(&argp->key, &result.val);
+
+ /*
+ * Do DNS lookups for hosts maps if database lookup failed.
+ */
+
+#ifdef DB_CACHE
+ if (do_dns && result.stat != YP_TRUE &&
+ (yp_testflag(argp->map, argp->domain, YP_INTERDOMAIN) ||
+ (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes")))) {
+#else
+ if (do_dns && result.stat != YP_TRUE &&
+ (strstr(argp->map, "hosts") || strstr(argp->map, "ipnodes"))) {
+#endif
+ char *nbuf;
+
+ nbuf = alloca(argp->key.keydat_len + 1);
+ /* NUL terminate! NUL terminate!! NUL TERMINATE!!! */
+ bcopy(argp->key.keydat_val, nbuf, argp->key.keydat_len);
+ nbuf[argp->key.keydat_len] = '\0';
+
+ if (debug)
+ yp_error("doing DNS lookup of %s", nbuf);
+
+ if (!strcmp(argp->map, "hosts.byname"))
+ result.stat = yp_async_lookup_name(rqstp, nbuf,
+ AF_INET);
+ else if (!strcmp(argp->map, "hosts.byaddr"))
+ result.stat = yp_async_lookup_addr(rqstp, nbuf,
+ AF_INET);
+ else if (!strcmp(argp->map, "ipnodes.byname"))
+ result.stat = yp_async_lookup_name(rqstp, nbuf,
+ AF_INET6);
+ else if (!strcmp(argp->map, "ipnodes.byaddr"))
+ result.stat = yp_async_lookup_addr(rqstp, nbuf,
+ AF_INET6);
+
+ if (result.stat == YP_TRUE)
+ return(NULL);
+ }
+
+ return (&result);
+}
+
+ypresp_key_val *
+ypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
+{
+ static ypresp_key_val result;
+
+ result.val.valdat_val = result.key.keydat_val = "";
+ result.val.valdat_len = result.key.keydat_len = 0;
+
+#ifdef DB_CACHE
+ if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(argp->map, (struct svc_req *)rqstp)) {
+#endif
+ result.stat = YP_YPERR;
+ return (&result);
+ }
+
+ if (argp->domain == NULL) {
+ result.stat = YP_BADARGS;
+ return (&result);
+ }
+
+ if (yp_select_map(argp->map, argp->domain, NULL, 0) != YP_TRUE) {
+ result.stat = yp_errno;
+ return(&result);
+ }
+
+ result.stat = yp_firstbykey(&result.key, &result.val);
+
+ return (&result);
+}
+
+ypresp_key_val *
+ypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp)
+{
+ static ypresp_key_val result;
+
+ result.val.valdat_val = result.key.keydat_val = "";
+ result.val.valdat_len = result.key.keydat_len = 0;
+
+#ifdef DB_CACHE
+ if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(argp->map, (struct svc_req *)rqstp)) {
+#endif
+ result.stat = YP_YPERR;
+ return (&result);
+ }
+
+ if (argp->domain == NULL || argp->map == NULL) {
+ result.stat = YP_BADARGS;
+ return (&result);
+ }
+
+ if (yp_select_map(argp->map, argp->domain, &argp->key, 0) != YP_TRUE) {
+ result.stat = yp_errno;
+ return(&result);
+ }
+
+ result.key.keydat_len = argp->key.keydat_len;
+ result.key.keydat_val = argp->key.keydat_val;
+
+ result.stat = yp_nextbykey(&result.key, &result.val);
+
+ return (&result);
+}
+
+static void
+ypxfr_callback(ypxfrstat rval, struct sockaddr_in *addr, unsigned int transid,
+ unsigned int prognum, unsigned long port)
+{
+ CLIENT *clnt;
+ int sock = RPC_ANYSOCK;
+ struct timeval timeout;
+ yppushresp_xfr ypxfr_resp;
+ struct rpc_err err;
+
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ addr->sin_port = htons(port);
+
+ if ((clnt = clntudp_create(addr,prognum,1,timeout,&sock)) == NULL) {
+ yp_error("%s: %s", inet_ntoa(addr->sin_addr),
+ clnt_spcreateerror("failed to establish callback handle"));
+ return;
+ }
+
+ ypxfr_resp.status = rval;
+ ypxfr_resp.transid = transid;
+
+ /* Turn the timeout off -- we don't want to block. */
+ timeout.tv_sec = 0;
+ if (clnt_control(clnt, CLSET_TIMEOUT, &timeout) == FALSE)
+ yp_error("failed to set timeout on ypproc_xfr callback");
+
+ if (yppushproc_xfrresp_1(&ypxfr_resp, clnt) == NULL) {
+ clnt_geterr(clnt, &err);
+ if (err.re_status != RPC_SUCCESS &&
+ err.re_status != RPC_TIMEDOUT)
+ yp_error("%s", clnt_sperror(clnt,
+ "ypxfr callback failed"));
+ }
+
+ clnt_destroy(clnt);
+}
+
+#define YPXFR_RETURN(CODE) \
+ /* Order is important: send regular RPC reply, then callback */ \
+ result.xfrstat = CODE; \
+ svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_ypresp_xfr, &result); \
+ ypxfr_callback(CODE,rqhost,argp->transid, \
+ argp->prog,argp->port); \
+ return(NULL);
+
+ypresp_xfr *
+ypproc_xfr_2_svc(ypreq_xfr *argp, struct svc_req *rqstp)
+{
+ static ypresp_xfr result;
+ struct sockaddr_in *rqhost;
+ ypresp_master *mres;
+ ypreq_nokey mreq;
+
+ result.transid = argp->transid;
+ rqhost = svc_getcaller(rqstp->rq_xprt);
+
+#ifdef DB_CACHE
+ if (yp_access(argp->map_parms.map,
+ argp->map_parms.domain, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(argp->map_parms.map, (struct svc_req *)rqstp)) {
+#endif
+ YPXFR_RETURN(YPXFR_REFUSED)
+ }
+
+
+ if (argp->map_parms.domain == NULL) {
+ YPXFR_RETURN(YPXFR_BADARGS)
+ }
+
+ if (yp_validdomain(argp->map_parms.domain)) {
+ YPXFR_RETURN(YPXFR_NODOM)
+ }
+
+ /*
+ * Determine the master host ourselves. The caller may
+ * be up to no good. This has the side effect of verifying
+ * that the requested map and domain actually exist.
+ */
+
+ mreq.domain = argp->map_parms.domain;
+ mreq.map = argp->map_parms.map;
+
+ mres = ypproc_master_2_svc(&mreq, rqstp);
+
+ if (mres->stat != YP_TRUE) {
+ yp_error("couldn't find master for map %s@%s",
+ argp->map_parms.map,
+ argp->map_parms.domain);
+ yp_error("host at %s (%s) may be pulling my leg",
+ argp->map_parms.peer,
+ inet_ntoa(rqhost->sin_addr));
+ YPXFR_RETURN(YPXFR_REFUSED)
+ }
+
+ switch (yp_fork()) {
+ case 0:
+ {
+ char g[11], t[11], p[11];
+ char ypxfr_command[MAXPATHLEN + 2];
+
+ snprintf (ypxfr_command, sizeof(ypxfr_command), "%sypxfr", _PATH_LIBEXEC);
+ snprintf (t, sizeof(t), "%u", argp->transid);
+ snprintf (g, sizeof(g), "%u", argp->prog);
+ snprintf (p, sizeof(p), "%u", argp->port);
+ if (debug) {
+ close(0); close(1); close(2);
+ }
+ if (strcmp(yp_dir, _PATH_YP)) {
+ execl(ypxfr_command, "ypxfr",
+ "-d", argp->map_parms.domain,
+ "-h", mres->peer,
+ "-p", yp_dir, "-C", t,
+ g, inet_ntoa(rqhost->sin_addr),
+ p, argp->map_parms.map,
+ NULL);
+ } else {
+ execl(ypxfr_command, "ypxfr",
+ "-d", argp->map_parms.domain,
+ "-h", mres->peer,
+ "-C", t,
+ g, inet_ntoa(rqhost->sin_addr),
+ p, argp->map_parms.map,
+ NULL);
+ }
+ yp_error("ypxfr execl(%s): %s", ypxfr_command, strerror(errno));
+ YPXFR_RETURN(YPXFR_XFRERR)
+ /*
+ * Just to safe, prevent PR #10970 from biting us in
+ * the unlikely case that execing ypxfr fails. We don't
+ * want to have any child processes spawned from this
+ * child process.
+ */
+ _exit(0);
+ break;
+ }
+ case -1:
+ yp_error("ypxfr fork(): %s", strerror(errno));
+ YPXFR_RETURN(YPXFR_XFRERR)
+ break;
+ default:
+ result.xfrstat = YPXFR_SUCC;
+ children++;
+ break;
+ }
+
+ return (&result);
+}
+#undef YPXFR_RETURN
+
+void *
+ypproc_clear_2_svc(void *argp, struct svc_req *rqstp)
+{
+ static char * result;
+ static char rval = 0;
+
+#ifdef DB_CACHE
+ if (yp_access(NULL, NULL, (struct svc_req *)rqstp))
+#else
+ if (yp_access(NULL, (struct svc_req *)rqstp))
+#endif
+ return (NULL);
+#ifdef DB_CACHE
+ /* clear out the database cache */
+ yp_flush_all();
+#endif
+ /* Re-read the securenets database for the hell of it. */
+ load_securenets();
+
+ result = &rval;
+ return((void *) &result);
+}
+
+/*
+ * For ypproc_all, we have to send a stream of ypresp_all structures
+ * via TCP, but the XDR filter generated from the yp.x protocol
+ * definition file only serializes one such structure. This means that
+ * to send the whole stream, you need a wrapper which feeds all the
+ * records into the underlying XDR routine until it hits an 'EOF.'
+ * But to use the wrapper, you have to violate the boundaries between
+ * RPC layers by calling svc_sendreply() directly from the ypproc_all
+ * service routine instead of letting the RPC dispatcher do it.
+ *
+ * Bleah.
+ */
+
+/*
+ * Custom XDR routine for serialzing results of ypproc_all: keep
+ * reading from the database and spew until we run out of records
+ * or encounter an error.
+ */
+static bool_t
+xdr_my_ypresp_all(register XDR *xdrs, ypresp_all *objp)
+{
+ while (1) {
+ /* Get a record. */
+ if ((objp->ypresp_all_u.val.stat =
+ yp_nextbykey(&objp->ypresp_all_u.val.key,
+ &objp->ypresp_all_u.val.val)) == YP_TRUE) {
+ objp->more = TRUE;
+ } else {
+ objp->more = FALSE;
+ }
+
+ /* Serialize. */
+ if (!xdr_ypresp_all(xdrs, objp))
+ return(FALSE);
+ if (objp->more == FALSE)
+ return(TRUE);
+ }
+}
+
+ypresp_all *
+ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
+{
+ static ypresp_all result;
+
+ /*
+ * Set this here so that the client will be forced to make
+ * at least one attempt to read from us even if all we're
+ * doing is returning an error.
+ */
+ result.more = TRUE;
+ result.ypresp_all_u.val.key.keydat_len = 0;
+ result.ypresp_all_u.val.key.keydat_val = "";
+
+#ifdef DB_CACHE
+ if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(argp->map, (struct svc_req *)rqstp)) {
+#endif
+ result.ypresp_all_u.val.stat = YP_YPERR;
+ return (&result);
+ }
+
+ if (argp->domain == NULL || argp->map == NULL) {
+ result.ypresp_all_u.val.stat = YP_BADARGS;
+ return (&result);
+ }
+
+ /*
+ * XXX If we hit the child limit, fail the request.
+ * If we don't, and the map is large, we could block for
+ * a long time in the parent.
+ */
+ if (children >= MAX_CHILDREN) {
+ result.ypresp_all_u.val.stat = YP_YPERR;
+ return(&result);
+ }
+
+ /*
+ * The ypproc_all procedure can take a while to complete.
+ * Best to handle it in a subprocess so the parent doesn't
+ * block. (Is there a better way to do this? Maybe with
+ * async socket I/O?)
+ */
+ if (!debug) {
+ switch (yp_fork()) {
+ case 0:
+ break;
+ case -1:
+ yp_error("ypall fork(): %s", strerror(errno));
+ result.ypresp_all_u.val.stat = YP_YPERR;
+ return(&result);
+ break;
+ default:
+ children++;
+ return (NULL);
+ break;
+ }
+ }
+
+ /*
+ * Fix for PR #10971: don't let the child ypserv share
+ * DB handles with the parent process.
+ */
+#ifdef DB_CACHE
+ yp_flush_all();
+#endif
+
+ if (yp_select_map(argp->map, argp->domain,
+ &result.ypresp_all_u.val.key, 0) != YP_TRUE) {
+ result.ypresp_all_u.val.stat = yp_errno;
+ return(&result);
+ }
+
+ /* Kick off the actual data transfer. */
+ svc_sendreply(rqstp->rq_xprt, (xdrproc_t)xdr_my_ypresp_all, &result);
+
+ /*
+ * Proper fix for PR #10970: exit here so that we don't risk
+ * having a child spawned from this sub-process.
+ */
+ if (!debug)
+ _exit(0);
+
+ return &result;
+}
+
+ypresp_master *
+ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
+{
+ static ypresp_master result;
+ static char ypvalbuf[YPMAXRECORD];
+ keydat key = { MASTER_SZ, MASTER_STRING };
+ valdat val;
+
+ result.peer = "";
+
+#ifdef DB_CACHE
+ if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(argp->map, (struct svc_req *)rqstp)) {
+#endif
+ result.stat = YP_YPERR;
+ return(&result);
+ }
+
+ if (argp->domain == NULL) {
+ result.stat = YP_BADARGS;
+ return (&result);
+ }
+
+ if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
+ result.stat = yp_errno;
+ return(&result);
+ }
+
+ /*
+ * Note that we copy the data retrieved from the database to
+ * a private buffer and NUL terminate the buffer rather than
+ * terminating the data in place. We do this because by stuffing
+ * a '\0' into data.data, we will actually be corrupting memory
+ * allocated by the DB package. This is a bad thing now that we
+ * cache DB handles rather than closing the database immediately.
+ */
+ result.stat = yp_getbykey(&key, &val);
+ if (result.stat == YP_TRUE) {
+ bcopy(val.valdat_val, &ypvalbuf, val.valdat_len);
+ ypvalbuf[val.valdat_len] = '\0';
+ result.peer = ypvalbuf;
+ } else
+ result.peer = "";
+
+ return (&result);
+}
+
+ypresp_order *
+ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp)
+{
+ static ypresp_order result;
+ keydat key = { ORDER_SZ, ORDER_STRING };
+ valdat val;
+
+ result.ordernum = 0;
+
+#ifdef DB_CACHE
+ if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(argp->map, (struct svc_req *)rqstp)) {
+#endif
+ result.stat = YP_YPERR;
+ return(&result);
+ }
+
+ if (argp->domain == NULL) {
+ result.stat = YP_BADARGS;
+ return (&result);
+ }
+
+ /*
+ * We could just check the timestamp on the map file,
+ * but that's a hack: we'll only know the last time the file
+ * was touched, not the last time the database contents were
+ * updated.
+ */
+
+ if (yp_select_map(argp->map, argp->domain, &key, 1) != YP_TRUE) {
+ result.stat = yp_errno;
+ return(&result);
+ }
+
+ result.stat = yp_getbykey(&key, &val);
+
+ if (result.stat == YP_TRUE)
+ result.ordernum = atoi(val.valdat_val);
+ else
+ result.ordernum = 0;
+
+ return (&result);
+}
+
+static void yp_maplist_free(struct ypmaplist *yp_maplist)
+{
+ register struct ypmaplist *next;
+
+ while (yp_maplist) {
+ next = yp_maplist->next;
+ free(yp_maplist->map);
+ free(yp_maplist);
+ yp_maplist = next;
+ }
+}
+
+static struct ypmaplist *
+yp_maplist_create(const char *domain)
+{
+ char yp_mapdir[MAXPATHLEN + 2];
+ char yp_mapname[MAXPATHLEN + 2];
+ struct ypmaplist *cur = NULL;
+ struct ypmaplist *yp_maplist = NULL;
+ DIR *dird;
+ struct dirent *dirp;
+ struct stat statbuf;
+
+ snprintf(yp_mapdir, sizeof(yp_mapdir), "%s/%s", yp_dir, domain);
+
+ if ((dird = opendir(yp_mapdir)) == NULL) {
+ yp_error("opendir(%s) failed: %s", yp_mapdir, strerror(errno));
+ return(NULL);
+ }
+
+ while ((dirp = readdir(dird)) != NULL) {
+ if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, "..")) {
+ snprintf(yp_mapname, sizeof(yp_mapname), "%s/%s",
+ yp_mapdir,dirp->d_name);
+ if (stat(yp_mapname, &statbuf) < 0 ||
+ !S_ISREG(statbuf.st_mode))
+ continue;
+ if ((cur = (struct ypmaplist *)
+ malloc(sizeof(struct ypmaplist))) == NULL) {
+ yp_error("malloc() failed");
+ closedir(dird);
+ yp_maplist_free(yp_maplist);
+ return(NULL);
+ }
+ if ((cur->map = strdup(dirp->d_name)) == NULL) {
+ yp_error("strdup() failed: %s",strerror(errno));
+ closedir(dird);
+ yp_maplist_free(yp_maplist);
+ free(cur);
+ return(NULL);
+ }
+ cur->next = yp_maplist;
+ yp_maplist = cur;
+ if (debug)
+ yp_error("map: %s", yp_maplist->map);
+ }
+
+ }
+ closedir(dird);
+ return(yp_maplist);
+}
+
+ypresp_maplist *
+ypproc_maplist_2_svc(domainname *argp, struct svc_req *rqstp)
+{
+ static ypresp_maplist result = { 0, NULL };
+
+#ifdef DB_CACHE
+ if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) {
+#else
+ if (yp_access(NULL, (struct svc_req *)rqstp)) {
+#endif
+ result.stat = YP_YPERR;
+ return(&result);
+ }
+
+ if (argp == NULL) {
+ result.stat = YP_BADARGS;
+ return (&result);
+ }
+
+ if (yp_validdomain(*argp)) {
+ result.stat = YP_NODOM;
+ return (&result);
+ }
+
+ /*
+ * We have to construct a linked list for the ypproc_maplist
+ * procedure using dynamically allocated memory. Since the XDR
+ * layer won't free this list for us, we have to deal with it
+ * ourselves. We call yp_maplist_free() first to free any
+ * previously allocated data we may have accumulated to insure
+ * that we have only one linked list in memory at any given
+ * time.
+ */
+
+ yp_maplist_free(result.maps);
+
+ if ((result.maps = yp_maplist_create(*argp)) == NULL) {
+ yp_error("yp_maplist_create failed");
+ result.stat = YP_YPERR;
+ return(&result);
+ } else
+ result.stat = YP_TRUE;
+
+ return (&result);
+}
+
+/*
+ * NIS v1 support. The nullproc, domain and domain_nonack
+ * functions from v1 are identical to those in v2, so all
+ * we have to do is hand off to them.
+ *
+ * The other functions are mostly just wrappers around their v2
+ * counterparts. For example, for the v1 'match' procedure, we
+ * crack open the argument structure, make a request to the v2
+ * 'match' function, repackage the data into a v1 response and
+ * then send it on its way.
+ *
+ * Note that we don't support the pull, push and get procedures.
+ * There's little documentation available to show what they
+ * do, and I suspect they're meant largely for map transfers
+ * between master and slave servers.
+ */
+
+void *
+ypoldproc_null_1_svc(void *argp, struct svc_req *rqstp)
+{
+ return(ypproc_null_2_svc(argp, rqstp));
+}
+
+bool_t *
+ypoldproc_domain_1_svc(domainname *argp, struct svc_req *rqstp)
+{
+ return(ypproc_domain_2_svc(argp, rqstp));
+}
+
+bool_t *
+ypoldproc_domain_nonack_1_svc(domainname *argp, struct svc_req *rqstp)
+{
+ return (ypproc_domain_nonack_2_svc(argp, rqstp));
+}
+
+/*
+ * the 'match' procedure sends a response of type YPRESP_VAL
+ */
+ypresponse *
+ypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp)
+{
+ static ypresponse result;
+ ypresp_val *v2_result;
+
+ result.yp_resptype = YPRESP_VAL;
+ result.ypresponse_u.yp_resp_valtype.val.valdat_val = "";
+ result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0;
+
+ if (argp->yp_reqtype != YPREQ_KEY) {
+ result.ypresponse_u.yp_resp_valtype.stat = YP_BADARGS;
+ return(&result);
+ }
+
+ v2_result = ypproc_match_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
+ if (v2_result == NULL)
+ return(NULL);
+
+ bcopy(v2_result, &result.ypresponse_u.yp_resp_valtype,
+ sizeof(ypresp_val));
+
+ return (&result);
+}
+
+/*
+ * the 'first' procedure sends a response of type YPRESP_KEY_VAL
+ */
+ypresponse *
+ypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp)
+{
+ static ypresponse result;
+ ypresp_key_val *v2_result;
+
+ result.yp_resptype = YPRESP_KEY_VAL;
+ result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
+ result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
+ result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
+ result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
+
+ if (argp->yp_reqtype != YPREQ_NOKEY) {
+ result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
+ return(&result);
+ }
+
+ v2_result = ypproc_first_2_svc(&argp->yprequest_u.yp_req_nokeytype,
+ rqstp);
+ if (v2_result == NULL)
+ return(NULL);
+
+ bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype,
+ sizeof(ypresp_key_val));
+
+ return (&result);
+}
+
+/*
+ * the 'next' procedure sends a response of type YPRESP_KEY_VAL
+ */
+ypresponse *
+ypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp)
+{
+ static ypresponse result;
+ ypresp_key_val *v2_result;
+
+ result.yp_resptype = YPRESP_KEY_VAL;
+ result.ypresponse_u.yp_resp_key_valtype.val.valdat_val =
+ result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = "";
+ result.ypresponse_u.yp_resp_key_valtype.val.valdat_len =
+ result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0;
+
+ if (argp->yp_reqtype != YPREQ_KEY) {
+ result.ypresponse_u.yp_resp_key_valtype.stat = YP_BADARGS;
+ return(&result);
+ }
+
+ v2_result = ypproc_next_2_svc(&argp->yprequest_u.yp_req_keytype,rqstp);
+ if (v2_result == NULL)
+ return(NULL);
+
+ bcopy(v2_result, &result.ypresponse_u.yp_resp_key_valtype,
+ sizeof(ypresp_key_val));
+
+ return (&result);
+}
+
+/*
+ * the 'poll' procedure sends a response of type YPRESP_MAP_PARMS
+ */
+ypresponse *
+ypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp)
+{
+ static ypresponse result;
+ ypresp_master *v2_result1;
+ ypresp_order *v2_result2;
+
+ result.yp_resptype = YPRESP_MAP_PARMS;
+ result.ypresponse_u.yp_resp_map_parmstype.domain =
+ argp->yprequest_u.yp_req_nokeytype.domain;
+ result.ypresponse_u.yp_resp_map_parmstype.map =
+ argp->yprequest_u.yp_req_nokeytype.map;
+ /*
+ * Hmm... there is no 'status' value in the
+ * yp_resp_map_parmstype structure, so I have to
+ * guess at what to do to indicate a failure.
+ * I hope this is right.
+ */
+ result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0;
+ result.ypresponse_u.yp_resp_map_parmstype.peer = "";
+
+ if (argp->yp_reqtype != YPREQ_MAP_PARMS) {
+ return(&result);
+ }
+
+ v2_result1 = ypproc_master_2_svc(&argp->yprequest_u.yp_req_nokeytype,
+ rqstp);
+ if (v2_result1 == NULL)
+ return(NULL);
+
+ if (v2_result1->stat != YP_TRUE) {
+ return(&result);
+ }
+
+ v2_result2 = ypproc_order_2_svc(&argp->yprequest_u.yp_req_nokeytype,
+ rqstp);
+ if (v2_result2 == NULL)
+ return(NULL);
+
+ if (v2_result2->stat != YP_TRUE) {
+ return(&result);
+ }
+
+ result.ypresponse_u.yp_resp_map_parmstype.peer =
+ v2_result1->peer;
+ result.ypresponse_u.yp_resp_map_parmstype.ordernum =
+ v2_result2->ordernum;
+
+ return (&result);
+}
+
+ypresponse *
+ypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp)
+{
+ static ypresponse result;
+
+ /*
+ * Not implemented.
+ */
+
+ return (&result);
+}
+
+ypresponse *
+ypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp)
+{
+ static ypresponse result;
+
+ /*
+ * Not implemented.
+ */
+
+ return (&result);
+}
+
+ypresponse *
+ypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp)
+{
+ static ypresponse result;
+
+ /*
+ * Not implemented.
+ */
+
+ return (&result);
+}
diff --git a/usr.sbin/ypserv/yp_svc_udp.c b/usr.sbin/ypserv/yp_svc_udp.c
new file mode 100644
index 000000000000..9cb904db01b1
--- /dev/null
+++ b/usr.sbin/ypserv/yp_svc_udp.c
@@ -0,0 +1,71 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1996
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <rpc/rpc.h>
+#include <rpc/svc_dg.h>
+#include "yp_extern.h"
+
+#define su_data(xprt) ((struct svc_dg_data *)((xprt)->xp_p2))
+
+/*
+ * We need to be able to manually set the transaction ID in the
+ * UDP transport handle, but the standard library offers us no way
+ * to do that. Hence we need this garbage.
+ */
+
+unsigned long
+svcudp_get_xid(SVCXPRT *xprt)
+{
+ struct svc_dg_data *su;
+
+ if (xprt == NULL)
+ return(0);
+ su = su_data(xprt);
+ return(su->su_xid);
+}
+
+unsigned long
+svcudp_set_xid(SVCXPRT *xprt, unsigned long xid)
+{
+ struct svc_dg_data *su;
+ unsigned long old_xid;
+
+ if (xprt == NULL)
+ return(0);
+ su = su_data(xprt);
+ old_xid = su->su_xid;
+ su->su_xid = xid;
+ return(old_xid);
+}
diff --git a/usr.sbin/ypserv/ypinit.8 b/usr.sbin/ypserv/ypinit.8
new file mode 100644
index 000000000000..6e09a64aa86e
--- /dev/null
+++ b/usr.sbin/ypserv/ypinit.8
@@ -0,0 +1,198 @@
+.\" Copyright (c) 1997
+.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+.\" 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.
+.\"
+.Dd August 18, 2015
+.Dt YPINIT 8
+.Os
+.Sh NAME
+.Nm ypinit
+.Nd build and install NIS databases
+.Sh SYNOPSIS
+.Nm
+.Fl m
+.Op Ar domainname
+.Nm
+.Fl s
+.Ar master_server
+.Op Ar domainname
+.Nm
+.Fl u
+.Op Ar domainname
+.Sh DESCRIPTION
+The
+.Nm
+utility is a script which sets up databases on a Network Information Service
+(NIS)
+master or slave server.
+.Pp
+On a master server,
+.Nm
+creates the
+.Pa /var/yp/$DOMAINNAME
+directory, the
+.Pa /var/yp/ypservers
+file, and calls
+.Pa /var/yp/Makefile
+to create and populate an initial set of NIS maps.
+The maps are
+created from local source files using the
+.Xr yp_mkdb 8
+utility.
+The utility will prompt the user for a list of servers
+that support the specified domain; this list is used to populate
+the ypservers map.
+.Pp
+On a slave server,
+.Nm
+creates the
+.Pa /var/yp/$DOMAINNAME ,
+populates it with copies of the NIS maps from the master.
+The maps
+are obtained from the master using the
+.Xr ypxfr 8
+utility.
+The
+.Nm
+utility obtains the list of maps to transfer in one of two ways: if
+the system is configured as an NIS client and is bound to the master
+server,
+.Nm
+is able to use the
+.Xr ypwhich 1
+utility to obtain a list of maps exported by the master server.
+If the system is not configured as a client of the NIS master,
+.Nm
+uses a hardcoded list of maps, some of which may or may not actually
+exist on the master.
+The system administrator can edit the
+.Nm
+script and
+modify the map list if necessary.
+Otherwise, individual maps can
+be transferred manually from the master using
+.Xr ypxfr 8 .
+.Sh OPTIONS
+The
+.Nm
+utility supports the following options:
+.Bl -tag -width indent
+.It Fl m Op Ar domainname
+Set up a master server.
+By default,
+.Nm
+sets up a server for
+the system default domain.
+The user can override this default by specifying
+.Ar domainname
+explicitly.
+Maps are constructed from scratch using local files as templates using
+the
+.Xr yp_mkdb 8
+utility.
+.It Fl s Ar master_server Op Ar domainname
+Set up a slave server using
+.Ar master_name
+as the master.
+Maps are copied from
+.Ar master_server
+to the slave using
+.Xr ypxfr 8 .
+By default,
+.Nm
+sets up a server for
+the system default domain.
+The user can override this default by specifying
+.Ar domainname
+explicitly.
+.It Fl u Op Ar domainname
+Update the ypservers map on the master server.
+When a new slave
+server is added to a domain, its hostname must be added to the
+ypservers map so that
+.Xr yppush 8
+can propagate updates on the master to all of the slaves.
+.El
+.Sh FILES
+.Bl -tag -width /var/yp/master.passwd -compact
+.It Pa /etc/bootparams
+Bootparams source file
+.It Pa /etc/ethers
+Ethers data source file
+.It Pa /etc/eui64
+EUI64 data source file
+.It Pa /etc/group
+Group source file
+.It Pa /etc/hosts
+Hostname/IP address source file
+.It Pa /etc/netid
+RPC netid source file
+.It Pa /etc/networks
+Networks source file
+.It Pa /etc/protocols
+Protocols source file
+.It Pa /etc/publickey
+RPC public key/secret key source file
+.It Pa /etc/services
+Services data source file
+.It Pa /etc/shells
+Shells source file
+.It Pa /var/yp/master.passwd
+Passwd database source file
+.It Pa /var/yp/netgroup
+Netgroup data source file
+.It Pa /var/yp/ypservers
+Ypservers source file (generated by
+.Nm )
+.El
+.Sh SEE ALSO
+.Xr mknetid 8 ,
+.Xr revnetgroup 8 ,
+.Xr yp 8 ,
+.Xr yp_mkdb 8 ,
+.Xr yppush 8 ,
+.Xr ypserv 8 ,
+.Xr ypxfr 8
+.Sh HISTORY
+This version of
+.Nm
+is based on the
+.Nm
+script in
+.Ox .
+It first appeared in
+.Fx 3.0 .
+.Sh AUTHORS
+.An -nosplit
+The original script was written by
+.An Mats O Jansson Aq Mt moj@stacken.kth.se .
+It was modified for
+.Fx
+by
+.An Bill Paul Aq Mt wpaul@ctr.columbia.edu .
diff --git a/usr.sbin/ypserv/ypinit.sh b/usr.sbin/ypserv/ypinit.sh
new file mode 100644
index 000000000000..63f4e0706b92
--- /dev/null
+++ b/usr.sbin/ypserv/ypinit.sh
@@ -0,0 +1,386 @@
+#!/bin/sh
+#
+# ypinit.sh - setup a master or slave server.
+# (Taken from OpenBSD and modified for FreeBSD.)
+#
+DOMAINNAME=/bin/domainname
+HOSTNAME=/bin/hostname
+YPWHICH=/usr/bin/ypwhich
+YPXFR=/usr/libexec/ypxfr
+YP_DIR=/var/yp
+MAKEDBM=/usr/sbin/yp_mkdb
+MAPLIST="master.passwd.byname master.passwd.byuid passwd.byname passwd.byuid \
+ group.byname group.bygid hosts.byname hosts.byaddr services.byname \
+ rpc.byname rpc.bynumber networks.byname networks.byaddr netgroup \
+ netgroup.byuser netgroup.byhost netid.byname publickey.byname \
+ bootparams ethers.byname ethers.byaddr eui64.byname eui64.byid \
+ amd.host mail.aliases ypservers protocols.byname protocols.bynumber \
+ netmasks.byaddr"
+
+ERROR_EXISTS="NO"
+umask 077
+
+#set -xv
+
+ERROR=USAGE # assume usage error
+
+if [ $# -eq 1 ]
+then
+ if [ $1 = "-m" ] # ypinit -m
+ then
+ DOMAIN=`${DOMAINNAME}`
+ SERVERTYPE=MASTER
+ ERROR=
+ fi
+
+ if [ $1 = "-u" ] # ypinit -u
+ then
+ DOMAIN=`${DOMAINNAME}`
+ SERVERTYPE=UPDATE
+ ERROR=
+ fi
+fi
+
+if [ $# -eq 2 ]
+then
+ if [ $1 = "-m" ] # ypinit -m domainname
+ then
+ DOMAIN=${2}
+ SERVERTYPE=MASTER
+ ERROR=
+ fi
+
+ if [ $1 = "-s" ] # ypinit -s master_server
+ then
+ DOMAIN=`${DOMAINNAME}`
+ SERVERTYPE=SLAVE
+ MASTER=${2}
+ ERROR=
+ fi
+
+ if [ $1 = "-u" ] # ypinit -u domainname
+ then
+ DOMAIN=${2}
+ SERVERTYPE=UPDATE
+ ERROR=
+ fi
+fi
+
+if [ $# -eq 3 ]
+then
+ if [ $1 = "-s" ] # ypinit -s master_server domainname
+ then
+ DOMAIN=${3}
+ SERVERTYPE=SLAVE
+ MASTER=${2}
+ ERROR=
+ fi
+fi
+
+if [ "${ERROR}" = "USAGE" ]; then
+ cat << \__usage 1>&2
+usage: ypinit -m [domainname]
+ ypinit -s master_server [domainname]
+ ypinit -u [domainname]
+
+The `-m' flag builds a master YP server, and the `-s' flag builds
+a slave YP server. When building a slave YP server, `master_server'
+must be an existing, reachable YP server.
+The `-u' is for updating the ypservers map on a master server.
+__usage
+
+ exit 1
+fi
+
+# Check if domainname is set, don't accept an empty domainname
+if [ -z "${DOMAIN}" ]; then
+ cat << \__no_domain 1>&2
+The local host's YP domain name has not been set. Please set it with
+the domainname(1) command or pass the domain as an argument to ypinit(8).
+__no_domain
+
+ exit 1
+fi
+
+# Check if hostname is set, don't accept an empty hostname
+HOST=`${HOSTNAME}`
+if [ -z "${HOST}" ]; then
+ cat << \__no_hostname 1>&2
+The local host's hostname has not been set. Please set it with the
+hostname(1) command.
+__no_hostname
+
+ exit 1
+fi
+
+# Check if we have contact with master.
+# If we can't list the maps on the master, then we fake it with a
+# hard-coded list of maps. The FreeBSD ypxfr command will work even
+# if ypbind isn't running or if we are bound to ourselves instead of
+# the master (the slave should be bound to itself, but since it has
+# no maps yet, we can't get a maplist from it).
+if [ "${SERVERTYPE}" = "SLAVE" ];
+then
+ COUNT=`${YPWHICH} -d ${DOMAIN} -m 2>/dev/null | grep -i ${MASTER} | wc -l | tr -d " "`
+ if [ "$COUNT" = "0" ]
+ then
+ echo "Can't enumerate maps from ${MASTER}. Please check that it is running." 1>&2
+ echo "Note: using hardcoded maplist for map transfers." 1>&2
+ YPMAPLIST=${MAPLIST}
+ else
+ YPMAPLIST=`${YPWHICH} -d ${DOMAIN} -m | cut -d\ -f1`
+ fi
+ echo "" 1>&2
+fi
+
+# Check if user is root
+ID=`id -u`
+if [ "${ID}" != "0" ]; then
+ echo "You have to be the superuser to run this. Please login as root." 1>&2
+ exit 1
+fi
+
+# Check if the YP directory exists.
+
+if [ ! -d ${YP_DIR} -o -f ${YP_DIR} ]
+then
+ echo "The directory ${YP_DIR} doesn't exist. Restore it from the distribution." 1>&2
+ exit 1
+
+fi
+
+echo -n "Server Type: ${SERVERTYPE} Domain: ${DOMAIN}"
+if [ "${SERVERTYPE}" = "SLAVE" ]; then
+ echo -n " Master: ${MASTER}"
+fi
+echo ""
+
+if [ "${SERVERTYPE}" != "UPDATE" ];
+then
+ cat << \__notice1
+
+Creating an YP server will require that you answer a few questions.
+Questions will all be asked at the beginning of the procedure.
+
+__notice1
+
+ echo -n "Do you want this procedure to quit on non-fatal errors? [y/n: n] "
+ read DOEXIT
+
+ case ${DOEXIT} in
+ y*|Y*)
+ ERROR_EXIT="YES"
+ ;;
+
+ *) ERROR_EXIT="NO"
+ echo ""
+ echo "Ok, please remember to go back and redo manually whatever fails."
+ echo "If you don't, something might not work. "
+ ;;
+ esac
+
+ if [ -d "${YP_DIR}/${DOMAIN}" ]; then
+ echo ""
+ echo -n "Can we destroy the existing ${YP_DIR}/${DOMAIN} and its contents? [y/n: n] "
+ read KILL
+
+ ERROR=
+ case ${KILL} in
+ y*|Y*)
+ ERROR="DELETE"
+ ;;
+
+ *) ERROR=
+ ;;
+ esac
+
+ if [ "${ERROR}" = "DELETE" ]; then
+ if ! rm -rf ${YP_DIR}/${DOMAIN}; then
+ echo "Can't clean up old directory ${YP_DIR}/${DOMAIN}." 1>&2
+ exit 1
+ fi
+ else
+ echo "OK, please clean it up by hand and start again. Bye"
+ exit 0
+ fi
+ fi
+
+ if ! mkdir "${YP_DIR}/${DOMAIN}"; then
+ echo "Can't make new directory ${YP_DIR}/${DOMAIN}." 1>&2
+ exit 1
+ fi
+fi
+
+if [ "${SERVERTYPE}" = "MASTER" ];
+then
+
+ if [ ! -f ${YP_DIR}/Makefile ]
+ then
+ if [ ! -f ${YP_DIR}/Makefile.dist ]
+ then
+ echo "Can't find ${YP_DIR}/Makefile.dist. " 1>&2
+ exit 1
+ fi
+ cp ${YP_DIR}/Makefile.dist ${YP_DIR}/Makefile
+ fi
+
+fi
+
+if [ "${SERVERTYPE}" = "SLAVE" ];
+then
+
+ echo "There will be no further questions. The remainder of the procedure"
+ echo "should take a few minutes, to copy the databases from ${MASTER}."
+
+ for MAP in ${YPMAPLIST}
+ do
+ echo "Transferring ${MAP}..."
+ if ! ${YPXFR} -p ${YP_DIR} -h ${MASTER} -c -d ${DOMAIN} ${MAP}; then
+ echo "Can't transfer map ${MAP}." 1>&2
+ ERROR_EXISTS="YES"
+ if [ "${ERROR_EXIT}" = "YES" ]; then
+ exit 1
+ fi
+ fi
+ done
+
+ echo ""
+ if [ "${ERROR_EXISTS}" = "YES" ]; then
+ echo "${HOST} has been setup as an YP slave server with errors. " 1>&2
+ echo "Please remember fix any problem that occurred." 1>&2
+ else
+ echo "${HOST} has been setup as an YP slave server without any errors. "
+ fi
+
+ echo "Don't forget to update map ypservers on ${MASTER}."
+ exit 0
+fi
+
+LIST_OK="NO"
+
+while [ "${LIST_OK}" = "NO" ];
+do
+ if [ "${SERVERTYPE}" = "MASTER" ];
+ then
+ HOST_LIST="${HOST}"
+ echo ""
+ echo "At this point, we have to construct a list of this domains YP servers."
+ echo "${HOST} is already known as master server."
+ echo "Please continue to add any slave servers, one per line. When you are"
+ echo "done with the list, type a <control D>."
+ echo " master server : ${HOST}"
+ fi
+
+ if [ "${SERVERTYPE}" = "UPDATE" ];
+ then
+ HOST_LIST="${HOST}"
+ NEW_LIST=""
+ MASTER_NAME=""
+ SHORT_HOST=`echo ${HOST} | cut -d. -f1`
+ if [ -f ${YP_DIR}/${DOMAIN}/ypservers ];
+ then
+ for srv in `${MAKEDBM} -u ${YP_DIR}/${DOMAIN}/ypservers | grep -v "^YP" | tr "\t" " " | cut -d\ -f1`;
+ do
+ short_srv=`echo ${srv} | cut -d. -f1`
+ if [ "${SHORT_HOST}" != "${short_srv}" ]
+ then
+ if [ "${NEW_LIST}" = "" ];
+ then
+ NEW_LIST="${srv}"
+ else
+ NEW_LIST="${NEW_LIST} ${srv}"
+ fi
+ fi
+ done;
+ MASTER_NAME=`${MAKEDBM} -u ${YP_DIR}/${DOMAIN}/ypservers | grep "^YP_MASTER_NAME" | tr "\t" " " | cut -d\ -f2`
+ fi
+ echo ""
+ echo "Update the list of hosts running YP servers in domain ${DOMAIN}."
+ echo "Master for this domain is ${MASTER_NAME}."
+ echo ""
+ echo "First verify old servers, type \\\\ to remove a server."
+ echo "Then add new servers, one per line. When done type a <control D>."
+ echo ""
+ echo " master server : ${HOST}"
+ if [ "${NEW_LIST}" != "" ]; then
+ for node in $NEW_LIST; do
+ echo -n " verify host : [${node}] "
+ read verify
+ if [ "${verify}" != "\\" ]; then
+ HOST_LIST="${HOST_LIST} ${node}"
+ fi
+ done;
+ fi
+ fi
+
+ echo -n " next host to add: "
+
+ while read h
+ do
+ echo -n " next host to add: "
+ HOST_LIST="${HOST_LIST} ${h}"
+ done
+
+ echo ""
+ echo "The current list of NIS servers looks like this:"
+ echo ""
+
+ for h in `echo ${HOST_LIST}`;
+ do
+ echo ${h}
+ done
+
+ echo ""
+ echo -n "Is this correct? [y/n: y] "
+ read hlist_ok
+
+ case $hlist_ok in
+ n*) echo "Let's try the whole thing again...";;
+ N*) echo "Let's try the whole thing again...";;
+ *) LIST_OK="YES";;
+ esac
+
+done
+
+echo "Building ${YP_DIR}/${DOMAIN}/ypservers..."
+rm -f ${YP_DIR}/ypservers
+touch -f ${YP_DIR}/ypservers
+rm -f ${YP_DIR}/${DOMAIN}/ypservers
+for host in ${HOST_LIST};
+do
+ echo "${host} ${host}" >> ${YP_DIR}/ypservers
+ echo "${host} ${host}"
+done | ${MAKEDBM} - ${YP_DIR}/${DOMAIN}/ypservers
+
+if [ $? -ne 0 ]; then
+ echo "" 1>&2
+ echo "Couldn't build yp data base ${YP_DIR}/${DOMAIN}/ypservers." 1>&2
+ ERROR_EXISTS="YES"
+ if [ "${ERROR_EXIT}" = "YES" ]; then
+ exit 1
+ fi
+fi
+
+if [ "${SERVERTYPE}" = "MASTER" ]; then
+ CUR_PWD=`pwd`
+ cd ${YP_DIR}
+ echo "Running ${YP_DIR}/Makefile..."
+ if ! make NOPUSH=True UPDATE_DOMAIN=${DOMAIN} YP_DIR=${YP_DIR}; then
+ echo "" 1>&2
+ echo "Error running Makefile." 1>&2
+ ERROR_EXISTS="YES"
+ if [ "${ERROR_EXIT}" = "YES" ]; then
+ exit 1
+ fi
+ fi
+
+ cd ${CUR_PWD}
+
+ echo ""
+ if [ "${ERROR_EXISTS}" = "YES" ]; then
+ echo "${HOST} has been setup as an YP master server with errors. " 1>&2
+ echo "Please remember fix any problem that occurred." 1>&2
+ else
+ echo "${HOST} has been setup as an YP master server without any errors. "
+ fi
+fi
diff --git a/usr.sbin/ypserv/ypserv.8 b/usr.sbin/ypserv/ypserv.8
new file mode 100644
index 000000000000..9c33b4b95ddc
--- /dev/null
+++ b/usr.sbin/ypserv/ypserv.8
@@ -0,0 +1,461 @@
+.\" Copyright (c) 1995
+.\" Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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.
+.\"
+.Dd December 13, 2009
+.Dt YPSERV 8
+.Os
+.Sh NAME
+.Nm ypserv
+.Nd NIS database server
+.Sh SYNOPSIS
+.Nm
+.Op Fl n
+.Op Fl d
+.Op Fl P Ar port
+.Op Fl p Ar path
+.Sh DESCRIPTION
+.Tn NIS
+is an RPC-based service designed to allow a number of UNIX-based
+machines to share a common set of configuration files.
+Rather than
+requiring a system administrator to update several copies of files
+such as
+.Pa /etc/hosts ,
+.Pa /etc/passwd
+and
+.Pa /etc/group ,
+which tend to require frequent changes in most environments,
+.Tn NIS
+allows groups of computers to share one set of data which can be
+updated from a single location.
+.Pp
+The
+.Nm
+utility is the server that distributes
+.Tn NIS
+databases to client systems within an
+.Tn NIS
+.Em domain .
+Each client in an
+.Tn NIS
+domain must have its domainname set to
+one of the domains served by
+.Nm
+using the
+.Xr domainname 1
+command.
+The clients must also run
+.Xr ypbind 8
+in order to attach to a particular server, since it is possible to
+have several servers within a single
+.Tn NIS
+domain.
+.Pp
+The databases distributed by
+.Nm
+are stored in
+.Pa /var/yp/[domainname]
+where
+.Pa domainname
+is the name of the domain being served.
+There can be several
+such directories with different domainnames, and you need only one
+.Nm
+daemon to handle them all.
+.Pp
+The databases, or
+.Pa maps
+as they are often called,
+are created by
+.Pa /var/yp/Makefile
+using several system files as source.
+The database files are in
+.Xr db 3
+format to help speed retrieval when there are many records involved.
+In
+.Fx ,
+the maps are always readable and writable only by root for security
+reasons.
+Technically this is only necessary for the password
+maps, but since the data in the other maps can be found in
+other world-readable files anyway, it does not hurt and it is considered
+good general practice.
+.Pp
+The
+.Nm
+utility is started by
+.Pa /etc/rc.d/ypserv
+if it has been enabled in
+.Pa /etc/rc.conf .
+.Sh SPECIAL FEATURES
+There are some problems associated with distributing a
+.Fx
+password
+database via
+.Tn NIS :
+.Fx
+normally only stores encrypted passwords
+in
+.Pa /etc/master.passwd ,
+which is readable and writable only by root.
+By turning this file
+into an
+.Tn NIS
+map, this security feature would be completely defeated.
+.Pp
+To make up for this, the
+.Fx
+version of
+.Nm
+handles the
+.Pa master.passwd.byname
+and
+.Pa master.passwd.byuid
+maps in a special way.
+When the server receives a request to access
+either of these two maps (or in fact either of the
+.Pa shadow.byname
+or
+.Pa shadow.byuid
+maps), it will check the TCP port from which the
+request originated and return an error if the port number is greater
+than 1023.
+Since only the superuser is allowed to bind to TCP ports
+with values less than 1024, the server can use this test to determine
+whether or not the access request came from a privileged user.
+Any requests made by non-privileged users are therefore rejected.
+.Pp
+Furthermore, the
+.Xr getpwent 3
+routines in the
+.Fx
+standard C library will only attempt to retrieve
+data from the
+.Pa master.passwd.byname
+and
+.Pa master.passwd.byuid
+maps for the superuser: if a normal user calls any of these functions,
+the standard
+.Pa passwd.byname
+and
+.Pa passwd.byuid
+maps will be accessed instead.
+The latter two maps are constructed by
+.Pa /var/yp/Makefile
+by parsing the
+.Pa master.passwd
+file and stripping out the password fields, and are therefore
+safe to pass on to unprivileged users.
+In this way, the shadow password
+aspect of the protected
+.Pa master.passwd
+database is maintained through
+.Tn NIS .
+.Sh NOTES
+.Ss Setting Up Master and Slave Servers
+.Xr ypinit 8
+is a convenient script that will help setup master and slave
+.Tn NIS
+servers.
+.Ss Limitations
+There are two problems inherent with password shadowing in
+.Tn NIS
+that users should
+be aware of:
+.Bl -enum -offset indent
+.It
+The
+.Sq TCP port less than 1024
+test is trivial to defeat for users with
+unrestricted access to machines on your network (even those machines
+which do not run UNIX-based operating systems).
+.It
+If you plan to use a
+.Fx
+system to serve
+.No non- Ns Fx
+clients that
+have no support for password shadowing (which is most of them), you
+will have to disable the password shadowing entirely by uncommenting the
+.Em UNSECURE=True
+entry in
+.Pa /var/yp/Makefile .
+This will cause the standard
+.Pa passwd.byname
+and
+.Pa passwd.byuid
+maps to be generated with valid encrypted password fields, which is
+necessary in order for
+.No non- Ns Fx
+clients to perform user
+authentication through
+.Tn NIS .
+.El
+.Ss Security
+In general, any remote user can issue an RPC to
+.Nm
+and retrieve the contents of your
+.Tn NIS
+maps, provided the remote user
+knows your domain name.
+To prevent such unauthorized transactions,
+.Nm
+supports a feature called
+.Pa securenets
+which can be used to restrict access to a given set of hosts.
+At startup,
+.Nm
+will attempt to load the securenets information from a file
+called
+.Pa /var/yp/securenets .
+(Note that this path varies depending on the path specified with
+the
+.Fl p
+option, which is explained below.)
+This file contains entries
+that consist of a network specification and a network mask separated
+by white space.
+Lines starting with
+.Dq \&#
+are considered to be comments.
+A
+sample securenets file might look like this:
+.Bd -unfilled -offset indent
+# allow connections from local host -- mandatory
+127.0.0.1 255.255.255.255
+# allow connections from any host
+# on the 192.168.128.0 network
+192.168.128.0 255.255.255.0
+# allow connections from any host
+# between 10.0.0.0 to 10.0.15.255
+10.0.0.0 255.255.240.0
+.Ed
+.Pp
+If
+.Nm
+receives a request from an address that matches one of these rules,
+it will process the request normally.
+If the address fails to match
+a rule, the request will be ignored and a warning message will be
+logged.
+If the
+.Pa /var/yp/securenets
+file does not exist,
+.Nm
+will allow connections from any host.
+.Pp
+The
+.Nm
+utility also has support for Wietse Venema's
+.Em tcpwrapper
+package.
+This allows the administrator to use the tcpwrapper
+configuration files
+.Pa ( /etc/hosts.allow
+and
+.Pa /etc/hosts.deny )
+for access control instead of
+.Pa /var/yp/securenets .
+.Pp
+Note: while both of these access control mechanisms provide some
+security, they, like the privileged port test, are both vulnerable
+to
+.Dq IP spoofing
+attacks.
+.Ss NIS v1 compatibility
+This version of
+.Nm
+has some support for serving
+.Tn NIS
+v1 clients.
+The
+.Fx
+.Tn NIS
+implementation only uses the
+.Tn NIS
+v2 protocol, however other implementations
+include support for the v1 protocol for backwards compatibility
+with older systems.
+The
+.Xr ypbind 8
+daemons supplied with these systems will try to establish a binding
+to an
+.Tn NIS
+v1 server even though they may never actually need it (and they may
+persist in broadcasting in search of one even after they receive a
+response from a v2 server).
+Note that while
+support for normal client calls is provided, this version of
+.Nm
+does not handle v1 map transfer requests; consequently, it cannot
+be used as a master or slave in conjunction with older
+.Tn NIS
+servers that
+only support the v1 protocol.
+Fortunately, there probably are not any
+such servers still in use today.
+.Ss NIS servers that are also NIS clients
+Care must be taken when running
+.Nm
+in a multi-server domain where the server machines are also
+.Tn NIS
+clients.
+It is generally a good idea to force the servers to
+bind to themselves rather than allowing them to broadcast bind
+requests and possibly become bound to each other: strange failure
+modes can result if one server goes down and
+others are dependent upon on it.
+(Eventually all the clients will
+time out and attempt to bind to other servers, but the delay
+involved can be considerable and the failure mode is still present
+since the servers might bind to each other all over again).
+.Pp
+Refer to the
+.Xr ypbind 8
+man page for details on how to force it to bind to a particular
+server.
+.Sh OPTIONS
+The following options are supported by
+.Nm :
+.Bl -tag -width flag
+.It Fl n
+This option affects the way
+.Nm
+handles yp_match requests for the
+.Pa hosts.byname
+and
+.Pa hosts.byaddress
+maps.
+By default, if
+.Nm
+cannot find an entry for a given host in its hosts maps, it will
+return an error and perform no further processing.
+With the
+.Fl n
+flag,
+.Nm
+will go one step further: rather than giving up immediately, it
+will try to resolve the hostname or address using a DNS nameserver
+query.
+If the query is successful,
+.Nm
+will construct a fake database record and return it to the client,
+thereby making it seem as though the client's yp_match request
+succeeded.
+.Pp
+This feature is provided for compatibility with SunOS 4.1.x,
+which has brain-damaged resolver functions in its standard C
+library that depend on
+.Tn NIS
+for hostname and address resolution.
+The
+.Fx
+resolver can be configured to do DNS
+queries directly, therefore it is not necessary to enable this
+option when serving only
+.Fx
+.Tn NIS
+clients.
+.It Fl d
+Cause the server to run in debugging mode.
+Normally,
+.Nm
+reports only unusual errors (access violations, file access failures)
+using the
+.Xr syslog 3
+facility.
+In debug mode, the server does not background
+itself and prints extra status messages to stderr for each
+request that it receives.
+Also, while running in debug mode,
+.Nm
+will not spawn any additional subprocesses as it normally does
+when handling yp_all requests or doing DNS lookups.
+(These actions
+often take a fair amount of time to complete and are therefore handled
+in subprocesses, allowing the parent server process to go on handling
+other requests.)
+This makes it easier to trace the server with
+a debugging tool.
+.It Fl h Ar addr
+Specify a specific address to bind to for requests. This option may be
+specified multiple times. If no
+.Fl h
+option is specified,
+.Nm
+will bind to default passive address
+.Pq e.g. INADDR_ANY for IPv4
+for each transport.
+.It Fl P Ar port
+Force ypserv to bind to a specific TCP/UDP port, rather than selecting
+its own.
+.It Fl p Ar path
+Normally,
+.Nm
+assumes that all
+.Tn NIS
+maps are stored under
+.Pa /var/yp .
+The
+.Fl p
+flag may be used to specify an alternate
+.Tn NIS
+root path, allowing
+the system administrator to move the map files to a different place
+within the file system.
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /var/yp/[domainname]/[maps]
+the
+.Tn NIS
+maps
+.It Pa /etc/nsswitch.conf
+name switch configuration file
+.It Pa /var/yp/securenets
+host access control file
+.El
+.Sh SEE ALSO
+.Xr ypcat 1 ,
+.Xr db 3 ,
+.Xr hosts_access 5 ,
+.Xr rpc.yppasswdd 8 ,
+.Xr yp 8 ,
+.Xr ypbind 8 ,
+.Xr ypinit 8 ,
+.Xr yppush 8 ,
+.Xr ypxfr 8
+.Sh HISTORY
+This version of
+.Nm
+first appeared in
+.Fx 2.2 .
+.Sh AUTHORS
+.An Bill Paul Aq Mt wpaul@ctr.columbia.edu