diff -ur --unidirectional-new-file /usr/src/usr.sbin/inetd/Makefile /usr/src-new/usr.sbin/inetd/Makefile
--- /usr/src/usr.sbin/inetd/Makefile	2004-01-31 00:56:44.000000000 -0600
+++ /usr/src-new/usr.sbin/inetd/Makefile	2006-06-20 11:04:28.000000000 -0500
@@ -1,20 +1,26 @@
-#	@(#)Makefile	8.1 (Berkeley) 6/6/93
-# $FreeBSD: src/usr.sbin/inetd/Makefile,v 1.18.2.4 2001/12/19 04:49:11 dd Exp $
-# $DragonFly: src/usr.sbin/inetd/Makefile,v 1.3 2004/01/31 06:56:44 dillon Exp $
-
-PROG=	inetd
-SRCS=	inetd.c builtins.c
-MAN=	inetd.8
-MLINKS=	inetd.8 inetd.conf.5
+#	from: @(#)Makefile	8.1 (Berkeley) 6/6/93
+#	$NetBSD: Makefile,v 1.20 2005/01/10 02:58:59 lukem Exp $
+
+.include <bsd.own.mk>
+
+WARNS?=	2
+PROG=   inetd
+SRCS=   inetd.c
+MAN=    inetd.8
+MLINKS= inetd.8 inetd.conf.5
 
 CFLAGS+= -DLOGIN_CAP
 #CFLAGS+= -DSANITY_CHECK
 
-DPADD+=	${LIBUTIL} ${LIBWRAP}
-LDADD+=	-lutil -lwrap
+DPADD+= ${LIBUTIL} ${LIBWRAP}
+LDADD+= -lutil -lwrap
 .if !defined(RELEASE_CRUNCH)
 CFLAGS+=-DINET6 -DIPSEC
-DPADD+=	${LIBIPSEC}
-LDADD+=	-lipsec
+DPADD+= ${LIBIPSEC}
+SRCS+=ipsec.c
+LDADD+= -lipsec
 .endif
+
 .include <bsd.prog.mk>
+
+
Only in /usr/src/usr.sbin/inetd/: builtins.c
diff -ur --unidirectional-new-file /usr/src/usr.sbin/inetd/inetd.8 /usr/src-new/usr.sbin/inetd/inetd.8
--- /usr/src/usr.sbin/inetd/inetd.8	2003-06-16 23:29:55.000000000 -0500
+++ /usr/src-new/usr.sbin/inetd/inetd.8	2006-06-20 08:50:33.000000000 -0500
@@ -1,5 +1,11 @@
-.\" Copyright (c) 1985, 1991, 1993, 1994
-.\"	The Regents of the University of California.  All rights reserved.
+.\"	$NetBSD: inetd.8,v 1.45 2005/09/11 23:38:35 wiz Exp $
+.\"
+.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+.\" NASA Ames Research Center.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
@@ -11,9 +17,36 @@
 .\"    documentation and/or other materials provided with the distribution.
 .\" 3. All advertising materials mentioning features or use of this software
 .\"    must display the following acknowledgement:
-.\"	This product includes software developed by the University of
-.\"	California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 	This product includes software developed by the NetBSD
+.\" 	Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Copyright (c) 1985, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. 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.
 .\"
@@ -29,121 +62,45 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"     from: @(#)inetd.8	8.3 (Berkeley) 4/13/94
-.\" $FreeBSD: src/usr.sbin/inetd/inetd.8,v 1.46.2.13 2003/03/12 22:08:14 trhodes Exp $
-.\" $DragonFly: src/usr.sbin/inetd/inetd.8,v 1.2 2003/06/17 04:29:55 dillon Exp $
+.\"     from: @(#)inetd.8       8.4 (Berkeley) 6/1/94
 .\"
-.Dd February 7, 1996
+.Dd March 24, 2004
 .Dt INETD 8
 .Os
 .Sh NAME
-.Nm inetd
+.Nm inetd ,
+.Nm inetd.conf
 .Nd internet
 .Dq super-server
 .Sh SYNOPSIS
 .Nm
 .Op Fl d
 .Op Fl l
-.Op Fl w
-.Op Fl W
-.Op Fl c Ar maximum
-.Op Fl C Ar rate
-.Op Fl a Ar address | hostname
-.Op Fl p Ar filename
-.Op Fl R Ar rate
-.Op Fl s Ar maximum
 .Op Ar configuration file
 .Sh DESCRIPTION
-The
 .Nm
-utility should be run at boot time by
+should be run at boot time by
 .Pa /etc/rc
 (see
 .Xr rc 8 ) .
-It then listens for connections on certain
-internet sockets.  When a connection is found on one
-of its sockets, it decides what service the socket
-corresponds to, and invokes a program to service the request.
-The server program is invoked with the service socket
-as its standard input, output and error descriptors.
-After the program is
-finished,
-.Nm
-continues to listen on the socket (except in some cases which
-will be described below).  Essentially,
+It then listens for connections on certain internet sockets.
+When a connection is found on one of its sockets, it decides what
+service the socket corresponds to, and invokes a program to service
+the request.
+After the program is finished, it continues to listen on the socket
+(except in some cases which will be described below).
+Essentially,
 .Nm
 allows running one daemon to invoke several others,
 reducing load on the system.
 .Pp
-The following options are available:
-.Bl -tag -width indent
+The options available for
+.Nm :
+.Bl -tag -width Ds
 .It Fl d
-Turn on debugging.
+Turns on debugging.
 .It Fl l
-Turn on logging of successful connections.
-.It Fl w
-Turn on TCP Wrapping for external services.
-See the
-.Sx "IMPLEMENTATION NOTES"
-section for more information on TCP Wrappers support.
-.It Fl W
-Turn on TCP Wrapping for internal services which are built in to
-.Nm .
-.It Fl c Ar maximum
-Specify the default maximum number of
-simultaneous invocations of each service;
-the default is unlimited.
-May be overridden on a per-service basis with the "max-child"
-parameter.
-.It Fl C Ar rate
-Specify the default maximum number of times a service can be invoked
-from a single IP address in one minute; the default is unlimited.
-May be overridden on a per-service basis with the
-"max-connections-per-ip-per-minute" parameter.
-.It Fl R Ar rate
-Specify the maximum number of times a service can be invoked
-in one minute; the default is 256.
-A rate of 0 allows an unlimited number of invocations.
-.It Fl s Ar maximum
-Specify the default maximum number of
-simultaneous invocations of each service from a single IP address;
-the default is unlimited.
-May be overridden on a per-service basis with the "max-child-per-ip"
-parameter.
-.It Fl a
-Specify one specific IP address to bind to.
-Alternatively, a hostname can be specified,
-in which case the IPv4 or IPv6 address
-which corresponds to that hostname is used.
-Usually a hostname is specified when
-.Nm
-is run inside a
-.Xr jail 8 ,
-in which case the hostname corresponds to the
-.Xr jail 8
-environment.
-.Pp
-When hostname specification is used
-and both IPv4 and IPv6 bindings are desired,
-one entry with the appropriate
-.Em protocol
-type for each binding
-is required for each service in
-.Pa /etc/inetd.conf .
-For example,
-a TCP-based service would need two entries,
-one using
-.Dq tcp4
-for the
-.Em protocol
-and the other using
-.Dq tcp6 .
-See the explanation of the
-.Pa /etc/inetd.conf
-.Em protocol
-field below.
-.It Fl p
-Specify an alternate file in which to store the process ID.
+Turns on libwrap connection logging.
 .El
 .Pp
 Upon execution,
@@ -151,99 +108,88 @@
 reads its configuration information from a configuration
 file which, by default, is
 .Pa /etc/inetd.conf .
+The path given for this configuration file must be absolute, unless
+the
+.Fl d
+option is also given on the command line.
 There must be an entry for each field of the configuration
 file, with entries for each field separated by a tab or
-a space.  Comments are denoted by a
-.Dq #
-at the beginning
-of a line.  There must be an entry for each field.  The
-fields of the configuration file are as follows:
+a space.
+Comments are denoted by a ``#'' at the beginning of a line.
+There must be an entry for each field (except for one
+special case, described below).
+The fields of the configuration file are as follows:
 .Pp
 .Bd -unfilled -offset indent -compact
-service name
-socket type
-protocol
-{wait|nowait}[/max-child[/max-connections-per-ip-per-minute[/max-child-per-ip]]]
-user[:group][/login-class]
-server program
+[addr:]service-name
+socket-type
+protocol[,sndbuf=size][,rcvbuf=size]
+wait/nowait[:max]
+user[:group]
+server-program
 server program arguments
 .Ed
 .Pp
 To specify an
-.Tn "ONC RPC" Ns -based
-service, the entry would contain these fields:
+.Em Sun-RPC
+based service, the entry would contain these fields.
 .Pp
 .Bd -unfilled -offset indent -compact
-service name/version
-socket type
-rpc/protocol
-user[:group][/login-class]
-server program
+service-name/version
+socket-type
+rpc/protocol[,sndbuf=size][,rcvbuf=size]
+wait/nowait[:max]
+user[:group]
+server-program
 server program arguments
 .Ed
 .Pp
-There are two types of services that
-.Nm
-can start: standard and TCPMUX.
-A standard service has a well-known port assigned to it;
-it may be a service that implements an official Internet standard or is a
-.Bx Ns -specific
-service.
-As described in
-.Tn RFC 1078 ,
-TCPMUX services are nonstandard services that do not have a
-well-known port assigned to them.
-They are invoked from
-.Nm
-when a program connects to the
-.Dq tcpmux
-well-known port and specifies
-the service name.
-This feature is useful for adding locally-developed servers.
-TCPMUX requests are only accepted when the multiplexor service itself
-is enabled, above and beyond and specific TCPMUX-based servers; see the
-discussion of internal services below.
+For Internet services, the first field of the line may also have a host
+address specifier prefixed to it, separated from the service name by a colon.
+If this is done, the string before the colon in the first field
+indicates what local address
+.Nm
+should use when listening for that service, or the single character
+.Dq \&*
+to indicate
+.Dv INADDR_ANY ,
+meaning
+.Sq all local addresses .
+To avoid repeating an address that occurs frequently, a line with a
+host address specifier and colon, but no further fields, causes the
+host address specifier to be remembered and used for all further lines
+with no explicit host specifier (until another such line or the end of
+the file).
+A line
+.Dl *:
+is implicitly provided at the top of the file; thus, traditional
+configuration files (which have no host address specifiers) will be
+interpreted in the traditional manner, with all services listened for
+on all local addresses.
 .Pp
 The
 .Em service-name
 entry is the name of a valid service in
 the file
-.Pa /etc/services ,
-or the specification of a
-.Ux
-domain socket (see below).
+.Pa /etc/services .
 For
 .Dq internal
 services (discussed below), the service
 name
-should
+.Em must
 be the official name of the service (that is, the first entry in
 .Pa /etc/services ) .
-When used to specify an
-.Tn "ONC RPC" Ns -based
-service, this field is a valid RPC service name in
+When used to specify a
+.Em Sun-RPC
+based service, this field is a valid RPC service name in
 the file
 .Pa /etc/rpc .
 The part on the right of the
 .Dq /
 is the RPC version number.
-This
-can simply be a single numeric argument or a range of versions.
-A range is bounded by the low version to the high version -
+This can simply be a single numeric argument or a range of versions.
+A range is bounded by the low version to the high version \-
 .Dq rusers/1-3 .
-For TCPMUX services, the value of the
-.Em service-name
-field consists of the string
-.Dq tcpmux
-followed by a slash and the
-locally-chosen service name.
-The service names listed in
-.Pa /etc/services
-and the name
-.Dq help
-are reserved.
-Try to choose unique names for your TCPMUX services by prefixing them with
-your organization's name and suffixing them with a version number.
 .Pp
 The
 .Em socket-type
@@ -256,184 +202,152 @@
 .Dq seqpacket ,
 depending on whether the socket is a stream, datagram, raw,
 reliably delivered message, or sequenced packet socket.
-TCPMUX services must use
-.Dq stream .
 .Pp
 The
 .Em protocol
-must be a valid protocol or
-.Dq unix .
-Examples are
+must be a valid protocol as given in
+.Pa /etc/protocols .
+Examples might be
 .Dq tcp
-or
-.Dq udp ,
-both of which imply IPv4 for backward compatibility.
-The names
-.Dq tcp4
-and
-.Dq udp4
-specify IPv4 only.
-The names
-.Dq tcp6
 and
-.Dq udp6
-specify IPv6 only.
-The names
-.Dq tcp46
-and
-.Dq udp46
-specify that the entry accepts both IPv4 and IPv6 connections
-via a wildcard
-.Dv AF_INET6
-socket.
-If it is desired that the service is reachable via T/TCP, one should
-specify
-.Dq tcp/ttcp ,
-which implies IPv4 for backward compatibility.
-The name
-.Dq tcp4/ttcp
-specifies IPv4 only, while
-.Dq tcp6/ttcp
-specifies IPv6 only.
-The name
-.Dq tcp46/ttcp
-specify that the entry accepts both IPv6 and IPv6 connections
-via a wildcard
-.Dv AF_INET6
-socket.
-Rpc based services
-(for which only IPv4 is supported at this time)
-are specified with the
+.Dq udp .
+Rpc based services are specified with the
 .Dq rpc/tcp
 or
 .Dq rpc/udp
 service type.
-TCPMUX services must use
-.Dq tcp ,
-.Dq tcp4 ,
-.Dq tcp6
+.Dq tcp
+and
+.Dq udp
+will be recognized as
+.Dq TCP or UDP over default IP version .
+It is currently IPv4, but in the future it will be IPv6.
+If you need to specify IPv4 or IPv6 explicitly, use something like
+.Dq tcp4
 or
-.Dq tcp46 .
+.Dq udp6 .
+If you would like to enable special support for
+.Xr faithd 8 ,
+prepend a keyword
+.Dq faith
+into
+.Em protocol ,
+like
+.Dq faith/tcp6 .
+.Pp
+In addition to the protocol, the configuration file may specify the
+send and receive socket buffer sizes for the listening socket.
+This is especially useful for
+.Tn TCP
+as the window scale factor, which is based on the receive socket
+buffer size, is advertised when the connection handshake occurs,
+thus the socket buffer size for the server must be set on the listen socket.
+By increasing the socket buffer sizes, better
+.Tn TCP
+performance may be realized in some situations.
+The socket buffer sizes are specified by appending their values to
+the protocol specification as follows:
+.Bd -literal -offset indent
+tcp,rcvbuf=16384
+tcp,sndbuf=64k
+tcp,rcvbuf=64k,sndbuf=1m
+.Ed
+.Pp
+A literal value may be specified, or modified using
+.Sq k
+to indicate kilobytes or
+.Sq m
+to indicate megabytes.
+Socket buffer sizes may be specified for all
+services and protocols except for tcpmux services.
 .Pp
 The
 .Em wait/nowait
-entry specifies whether the server that is invoked by
-.Nm
-will take over
-the socket associated with the service access point, and thus whether
+entry is used to tell
 .Nm
-should wait for the server to exit before listening for new service
-requests.
-Datagram servers must use
-.Dq wait ,
-as they are always invoked with the original datagram socket bound
-to the specified service address.
-These servers must read at least one datagram from the socket
-before exiting.
+if it should wait for the server program to return,
+or continue processing connections on the socket.
 If a datagram server connects
 to its peer, freeing the socket so
 .Nm
 can receive further messages on the socket, it is said to be
 a
 .Dq multi-threaded
-server;
-it should read one datagram from the socket and create a new socket
-connected to the peer.
-It should fork, and the parent should then exit
-to allow
-.Nm
-to check for new service requests to spawn new servers.
-Datagram servers which process all incoming datagrams
-on a socket and eventually time out are said to be
-.Dq single-threaded .
-.Xr Comsat 8 ,
+server, and should use the
+.Dq nowait
+entry.
+For datagram servers which process all incoming datagrams
+on a socket and eventually time out, the server is said to be
+.Dq single-threaded
+and should use a
+.Dq wait
+entry.
+.Xr comsat 8
 .Pq Xr biff 1
 and
 .Xr talkd 8
 are both examples of the latter type of
 datagram server.
-.Xr Tftpd 8
-is an example of a multi-threaded datagram server.
-.Pp
-Servers using stream sockets generally are multi-threaded and
-use the
-.Dq nowait
-entry.
-Connection requests for these services are accepted by
-.Nm ,
-and the server is given only the newly-accepted socket connected
-to a client of the service.
-Most stream-based services operate in this manner.
-Stream-based servers that use
+.Xr tftpd 8
+is an exception; it is a datagram server that establishes pseudo-connections.
+It must be listed as
+.Dq wait
+in order to avoid a race;
+the server reads the first packet, creates a new socket,
+and then forks and exits to allow
+.Nm
+to check for new service requests to spawn new servers.
+The optional
+.Dq max
+suffix (separated from
 .Dq wait
-are started with the listening service socket, and must accept
-at least one connection request before exiting.
-Such a server would normally accept and process incoming connection
-requests until a timeout.
-TCPMUX services must use
-.Dq nowait .
-.Pp
-The maximum number of outstanding child processes (or
-.Dq threads )
-for a
+or
 .Dq nowait
-service may be explicitly specified by appending a
-.Dq /
-followed by the number to the
+by a dot or a colon) specifies the maximum number of server instances that may
+be spawned from
+.Nm
+within an interval of 60 seconds.
+When omitted,
+.Dq max
+defaults to 40.
+.Pp
+Stream servers are usually marked as
 .Dq nowait
-keyword.
-Normally
-(or if a value of zero is specified) there is no maximum.
-Otherwise,
-once the maximum is reached, further connection attempts will be
-queued up until an existing child process exits.
-This also works
-in the case of
-.Dq wait
-mode, although a value other than one (the
-default) might not make sense in some cases.
-You can also specify the maximum number of connections per minute
-for a given IP address by appending
-a
-.Dq /
-followed by the number to the maximum number of
-outstanding child processes.
-Once the maximum is reached, further
-connections from this IP address will be dropped until the end of the
-minute.
-In addition, you can specify the maximum number of simultaneous
-invocations of each service from a single IP address by appending a
-.Dq /
-followed by the number to the maximum number of outstanding child
-processes.  Once the maximum is reached, further connections from this
-IP address will be dropped.
+but if a single server process is to handle multiple connections, it may be
+marked as
+.Dq wait .
+The master socket will then be passed as fd 0 to the server, which will then
+need to accept the incoming connection.
+The server should eventually time
+out and exit when no more connections are active.
+.Nm
+will continue to
+listen on the master socket for connections, so the server should not close
+it when it exits.
+.Xr identd 8
+is usually the only stream server marked as wait.
 .Pp
 The
 .Em user
-entry should contain the user name of the user as whom the server
-should run.  This allows for servers to be given less permission
-than root.
-Optional
-.Em group
-part separated by
-.Dq \&:
-allows to specify group name different
-than default group for this user.
-Optional
-.Em login-class
-part separated by
-.Dq /
-allows to specify login class different
-than default
-.Dq daemon
-login class.
+entry should contain the user name of the user as whom the server should run.
+This allows for servers to be given less permission than root.
+Optionally, a group can be specified by appending a colon to the user name,
+followed by the group name (it is possible to use a dot (``.'') in lieu of a
+colon, however this feature is provided only for backward compatibility).
+This allows for servers to run with a different (primary) group id than
+specified in the password file.
+If a group is specified and
+.Em user
+is not root, the supplementary groups associated with that user will still be
+set.
 .Pp
 The
 .Em server-program
 entry should contain the pathname of the program which is to be
 executed by
 .Nm
-when a request is found on its socket.  If
+when a request is found on its socket.
+If
 .Nm
 provides this service internally, this entry should
 be
@@ -443,445 +357,180 @@
 .Em server program arguments
 should be just as arguments
 normally are, starting with argv[0], which is the name of
-the program.  If the service is provided internally, the
-.Em service-name
-of the service (and any arguments to it) or the word
+the program.
+If the service is provided internally, the
+word
 .Dq internal
 should take the place of this entry.
-.Pp
-Currently, the only internal service to take arguments is
-.Dq auth .
-Without options, the service will always return
-.Dq ERROR\ : HIDDEN-USER .
-The available arguments to this service that alter its behavior are:
-.Bl -tag -width indent
-.It Fl d Ar fallback
-Provide a
-.Ar fallback
-username.
-If the real
-.Dq auth
-service is enabled
-(with the
-.Fl r
-option discussed below),
-return this username instead of an error
-when lookups fail
-for either socket credentials or the username.
-If the real
-.Dq auth
-service is disabled,
-return this username for every request.
-This is primarily useful when running this service on a NAT machine.
-.It Fl g
-Instead of returning
-the user's name to the ident requester,
-report a
-username made up of random alphanumeric characters,
-e.g.\&
-.Dq c0c993 .
-The
-.Fl g
-flag overrides not only the user names,
-but also any fallback name,
-.Pa .fakeid
-or
-.Pa .noident
-files.
-.It Fl t Xo
-.Ar sec Ns Op . Ns Ar usec
-.Xc
-Specify a timeout for the service.
-The default timeout is 10.0 seconds.
-.It Fl r
-Offer a real
-.Dq auth
-service, as per RFC 1413.
-All the remaining flags apply only in this case.
-.It Fl i
-Return numeric user IDs instead of usernames.
-.It Fl f
-If the file
-.Pa .fakeid
-exists in the home directory of the identified user, report the username
-found in that file instead of the real username.
-If the username found in
-.Pa .fakeid
-is that of an existing user,
-then the real username is reported.
-If the
-.Fl i
-flag is also given then the username in
-.Pa .fakeid
-is checked against existing user IDs instead.
-.It Fl F
-same as
-.Fl f
-but without the restriction that the username in
-.Pa .fakeid
-must not match an existing user.
-.It Fl n
-If the file
-.Pa .noident
-exists in the home directory of the identified user, return
-.Dq ERROR\ : HIDDEN-USER .
-This overrides any
-.Pa fakeid
-file which might exist.
-.It Fl o Ar osname
-Use
-.Ar osname
-instead of the name of the system as reported by
-.Xr uname 3 .
-.El
-.Pp
-The
-.Nm
-utility also provides several other
-.Dq trivial
-services internally by use of
-routines within itself.  These services are
-.Dq echo ,
-.Dq discard ,
-.Dq chargen
+It is possible to quote an argument using either single or double quotes.
+This allows you to have, e.g., spaces in paths and parameters.
+.Ss Internal Services
+.Nm
+provides several
+.Qq trivial
+services internally by use of routines within itself.
+These services are
+.Qq echo ,
+.Qq discard ,
+.Qq chargen
 (character generator),
-.Dq daytime
+.Qq daytime
 (human readable time), and
-.Dq time
-(machine readable time, in the form of the number of seconds since
-midnight, January 1, 1900).  All of these services are available in
-both TCP and UDP versions; the UDP versions will refuse service if the
-request specifies a reply port corresponding to any internal service.
-(This is done as a defense against looping attacks; the remote IP address
-is logged.)
-For details of these services, consult the
-appropriate
-.Tn RFC
-document.
-.Pp
-The TCPMUX-demultiplexing service is also implemented as an internal service.
-For any TCPMUX-based service to function, the following line must be included
-in
-.Pa inetd.conf :
-.Bd -literal -offset indent
-tcpmux	stream	tcp	nowait	root	internal
-.Ed
-.Pp
-When given the
-.Fl l
-option
-.Nm
-will log an entry to syslog each time a connection is accepted, noting the
-service selected and the IP-number of the remote requester if available.
-Unless otherwise specified in the configuration file,
-and in the absence of the
-.Fl W
-and
-.Fl w
-options,
-.Nm
-will log to the
-.Dq daemon
-facility.
+.Qq time
+(machine readable time,
+in the form of the number of seconds since midnight, January 1, 1900 GMT).
+For details of these services, consult the appropriate
+.Tn RFC .
+.Pp
+TCP services without official port numbers can be handled with the
+RFC1078-based tcpmux internal service.
+TCPmux listens on port 1 for requests.
+When a connection is made from a foreign host, the service name
+requested is passed to TCPmux, which performs a lookup in the
+service name table provided by
+.Pa /etc/inetd.conf
+and returns the proper entry for the service.
+TCPmux returns a negative reply if the service doesn't exist,
+otherwise the invoked server is expected to return the positive
+reply if the service type in
+.Pa /etc/inetd.conf
+file has the prefix
+.Qq tcpmux/ .
+If the service type has the
+prefix
+.Qq tcpmux/+ ,
+TCPmux will return the positive reply for the
+process; this is for compatibility with older server code, and also
+allows you to invoke programs that use stdin/stdout without putting any
+special server code in them.
+Services that use TCPmux are
+.Qq nowait
+because they do not have a well-known port number and hence cannot listen
+for new requests.
 .Pp
-The
 .Nm
-utility rereads its configuration file when it receives a hangup signal,
+rereads its configuration file when it receives a hangup signal,
 .Dv SIGHUP .
 Services may be added, deleted or modified when the configuration file
 is reread.
-Except when started in debugging mode,
 .Nm
-records its process ID in the file
-.Pa /var/run/inetd.pid
-to assist in reconfiguration.
-.Sh IMPLEMENTATION NOTES
-.Ss TCP Wrappers
-When given the
-.Fl w
-option,
-.Nm
-will wrap all services specified as
-.Dq stream nowait
-or
-.Dq dgram
-except for
-.Dq internal
-services.
-If the
-.Fl W
-option is given, such
-.Dq internal
-services will be wrapped.
-If both options are given, wrapping for both
-internal and external services will be enabled.
-Either wrapping option
-will cause failed connections to be logged to the
-.Dq auth
-syslog facility.
-Adding the
-.Fl l
-flag to the wrapping options will include successful connections in the
-logging to the
-.Dq auth
-facility.
-.Pp
-Note that
+creates a file
+.Em /var/run/inetd.pid
+that contains its process identifier.
+.Ss libwrap
+Support for
+.Tn TCP
+wrappers is included with
 .Nm
-only wraps requests for a
-.Dq wait
-service while no servers are available to service requests.
-Once a
-connection to such a service has been allowed,
-.Nm
-has no control
-over subsequent connections to the service until no more servers
-are left listening for connection requests.
-.Pp
-When wrapping is enabled, the
-.Pa tcpd
-daemon is not required, as that functionality is builtin.
-For more information on TCP Wrappers, see the relevant documentation
-.Pq Xr hosts_access 5 .
-When reading that document, keep in mind that
-.Dq internal
-services have no associated daemon name.
-Therefore, the service name
-as specified in
-.Pa inetd.conf
-should be used as the daemon name for
-.Dq internal
-services.
-.Ss TCPMUX
-.Tn RFC 1078
-describes the TCPMUX protocol:
-``A TCP client connects to a foreign host on TCP port 1.  It sends the
-service name followed by a carriage-return line-feed <CRLF>.  The
-service name is never case sensitive.  The server replies with a
-single character indicating positive (+) or negative (\-)
-acknowledgment, immediately followed by an optional message of
-explanation, terminated with a <CRLF>.  If the reply was positive,
-the selected protocol begins; otherwise the connection is closed.''
-The program is passed the TCP connection as file descriptors 0 and 1.
-.Pp
-If the TCPMUX service name begins with a
-.Dq + ,
-.Nm
-returns the positive reply for the program.
-This allows you to invoke programs that use stdin/stdout
-without putting any special server code in them.
-.Pp
-The special service name
-.Dq help
-causes
+to provide internal tcpd-like access control functionality.
+An external tcpd program is not needed.
+You do not need to change the
+.Pa /etc/inetd.conf
+server-program entry to enable this capability.
 .Nm
-to list TCPMUX services in
-.Pa inetd.conf .
+uses
+.Pa /etc/hosts.allow
+and
+.Pa /etc/hosts.deny
+for access control facility configurations, as described in
+.Xr hosts_access 5 .
+.Pp
+.Em Nota Bene :
+.Tn TCP
+wrappers do not affect/restrict
+.Tn UDP
+or internal services.
 .Ss IPsec
-The implementation includes a tiny hack
-to support IPsec policy settings for each socket.
-A special form of comment line, starting with
-.Dq Li #@ ,
-is interpreted as a policy specifier.
-Everything after the
-.Dq Li #@
-will be used as an IPsec policy string,
+The implementation includes a tiny hack to support IPsec policy settings for
+each socket.
+A special form of the comment line, starting with
+.Dq Li "#@" ,
+is used as a policy specifier.
+The content of the above comment line will be treated as a IPsec policy string,
 as described in
 .Xr ipsec_set_policy 3 .
-Each
-policy specifier is applied to all the following lines in
-.Pa inetd.conf
-until the next policy specifier.
-An empty policy specifier resets the IPsec policy.
+Multiple IPsec policy strings may be specified by using a semicolon
+as a separator.
+If conflicting policy strings are found in a single line,
+the last string will take effect.
+A
+.Li "#@"
+line affects all of the following lines in
+.Pa /etc/inetd.conf ,
+so you may want to reset the IPsec policy by using a comment line containing
+only
+.Li "#@"
+.Pq with no policy string .
 .Pp
-If an invalid IPsec policy specifier appears in
-.Pa inetd.conf ,
+If an invalid IPsec policy string appears in
+.Pa /etc/inetd.conf ,
 .Nm
-will provide an error message via the
+logs an error message using
 .Xr syslog 3
-interface and abort execution.
-.Ss Ux Domain Sockets
-In addition to running services on IP sockets,
-.Nm
-can also manage
-.Ux
-domain sockets.
-To do this you specify a
-.Em protocol
-of
-.Dq unix
-and specify the
-.Ux
-domain socket as the
-.Em service-name .
-The
-.Em service-type
-may be
-.Dq stream
-or
-.Dq dgram .
-The specification of the socket must be
-an absolute path name,
-optionally prefixed by an owner and mode
-of the form
-.Em :user:group:mode: .
-The specification:
-.Pp
-.Dl ":news:daemon:220:/var/run/sock"
-.Pp
-creates a socket owned
-by user
-.Dq news
-in group
-.Dq daemon
-with permissions allowing only that user and group to connect.
-The default owner is the user that
-.Nm
-is running as.
-The default mode only allows the socket's owner to connect.
-.Pp
-.Sy WARNING :
-while creating
-.Ux
-domain socket,
-.Nm
-must change the ownership and permissions on the socket.
-This can only be done securely if
-the directory in which the socket is created
-is writable only by root.
-Do
-.Em NOT
-use
-.Nm
-to create sockets in world writable directories,
-such as
-.Pa /tmp ,
-instead use
-.Pa /var/run
-or a similar directory.
-.Pp
-Internal services may be run on
-.Ux
-domain sockets, in the usual way.
-In this case
-the name of the internal service
-is determined using
-the last component of the socket's pathname.
-.Sh "FILES"
-.Bl -tag -width /var/run/inetd.pid -compact
-.It Pa /etc/inetd.conf
-configuration file
-.It Pa /etc/rpc
-translation of service names to RPC program numbers
-.It Pa /etc/services
-translation of service names to port numbers
-.It Pa /var/run/inetd.pid
-the pid of the currently running
-.Nm
-.El
-.Sh "EXAMPLES"
-Here are several example service entries for the various types of services:
-.Bd -literal
-ftp          stream  tcp   nowait root  /usr/libexec/ftpd        ftpd -l
-ntalk        dgram   udp   wait   root  /usr/libexec/ntalkd      ntalkd
-telnet       stream  tcp6  nowait root  /usr/libexec/telnetd  telnetd
-shell        stream  tcp46  nowait root  /usr/libexec/rshd rshd
-tcpmux/+date stream  tcp   nowait guest /bin/date                date
-tcpmux/phonebook stream tcp nowait guest /usr/local/bin/phonebook phonebook
-rstatd/1-3   dgram   rpc/udp wait root  /usr/libexec/rpc.rstatd  rpc.rstatd
-/var/run/echo stream unix  nowait root	internal
-#@ ipsec ah/require
-chargen      stream  tcp   nowait root  internal
-#@
-.Ed
-.Sh "ERROR MESSAGES"
-The
+and terminates itself.
+.Ss IPv6 TCP/UDP behavior
+If you wish to run a server for IPv4 and IPv6 traffic,
+you'll need to run two separate process for the same server program,
+specified as two separate lines on
+.Pa /etc/inetd.conf ,
+for
+.Dq tcp4
+and
+.Dq tcp6 .
+.Dq tcp
+means TCP on top of currently-default IP version,
+which is, at this moment, IPv4.
+.Pp
+Under various combination of IPv4/v6 daemon settings,
 .Nm
-server
-logs error messages using
-.Xr syslog 3 .
-Important error messages and their explanations are:
-.Pp
-.Bl -ohang -compact
-.It Xo
-.Ar service Ns / Ns Ar protocol
-.No "server failing (looping), service terminated."
-.Xc
-The number of requests for the specified service in the past minute
-exceeded the limit.
-The limit exists to prevent a broken program
-or a malicious user from swamping the system.
-This message may occur for several reasons:
-.Bl -enum -offset indent
+will behave as follows:
+.Bl -bullet -compact
 .It
-There are many hosts requesting the service within a short time period.
-.It
-A broken client program is requesting the service too frequently.
+If you have only one server on
+.Dq tcp4 ,
+IPv4 traffic will be routed to the server.
+IPv6 traffic will not be accepted.
 .It
-A malicious user is running a program to invoke the service in
-a denial-of-service attack.
+If you have two servers on
+.Dq tcp4
+and
+.Dq tcp6 ,
+IPv4 traffic will be routed to the server on
+.Dq tcp4 ,
+and IPv6 traffic will go to server on
+.Dq tcp6 .
 .It
-The invoked service program has an error that causes clients
-to retry quickly.
+If you have only one server on
+.Dq tcp6 ,
+only IPv6 traffic will be routed to the server.
+The kernel may route to the server IPv4 traffic as well,
+under certain configuration.
+See
+.Xr ip6 4
+for details.
 .El
-.Pp
-Use the
-.Fl R Ar rate
-option,
-as described above, to change the rate limit.
-Once the limit is reached, the service will be
-reenabled automatically in 10 minutes.
-.Pp
-.It Xo
-.Ar service Ns / Ns Ar protocol :
-.No \&No such user
-.Ar user ,
-.No service ignored
-.Xc
-.It Xo
-.Ar service Ns / Ns Ar protocol :
-.No getpwnam :
-.Ar user :
-.No \&No such user
-.Xc
-No entry for
-.Ar user
-exists in the
-.Xr passwd 5
-database.
-The first message
-occurs when
-.Nm
-(re)reads the configuration file.
-The second message occurs when the
-service is invoked.
-.Pp
-.It Xo
-.Ar service :
-.No can't set uid
-.Ar uid
-.Xc
-.It Xo
-.Ar service :
-.No can't set gid
-.Ar gid
-.Xc
-The user or group ID for the entry's
-.Ar user
-field is invalid.
-.Pp
-.It "setsockopt(SO_PRIVSTATE): Operation not supported"
-The
+.Sh FILES
+.Bl -tag -width /etc/hosts.allow -compact
+.It Pa /etc/inetd.conf
+configuration file for all
 .Nm
-utility attempted to renounce the privileged state associated with a
-socket but was unable to.
+provided services
+.It Pa /etc/services
+service name to protocol and port number mappings.
+.It Pa /etc/protocols
+protocol name to protocol number mappings
+.It Pa /etc/rpc
+.Tn Sun-RPC
+service name to service number mappings.
+.It Pa /etc/hosts.allow
+explicit remote host access list.
+.It Pa /etc/hosts.deny
+explicit remote host denial of service list.
 .El
 .Sh SEE ALSO
-.Xr ipsec_set_policy 3 ,
 .Xr hosts_access 5 ,
 .Xr hosts_options 5 ,
-.Xr login.conf 5 ,
-.Xr passwd 5 ,
+.Xr protocols 5 ,
 .Xr rpc 5 ,
 .Xr services 5 ,
 .Xr comsat 8 ,
@@ -889,29 +538,87 @@
 .Xr ftpd 8 ,
 .Xr rexecd 8 ,
 .Xr rlogind 8 ,
-.Xr rpcbind 8 ,
 .Xr rshd 8 ,
 .Xr telnetd 8 ,
 .Xr tftpd 8
 .Rs
-.%A Michael C. St. Johns
-.%T Identification Protocol
-.%O RFC1413
+.%A J. Postel
+.%R RFC
+.%N 862
+.%D May 1983
+.%T "Echo Protocol"
+.Re
+.Rs
+.%A J. Postel
+.%R RFC
+.%N 863
+.%D May 1983
+.%T "Discard Protocol"
+.Re
+.Rs
+.%A J. Postel
+.%R RFC
+.%N 864
+.%D May 1983
+.%T "Character Generator Protocol"
+.Re
+.Rs
+.%A J. Postel
+.%R RFC
+.%N 867
+.%D May 1983
+.%T "Daytime Protocol"
+.Re
+.Rs
+.%A J. Postel
+.%A K. Harrenstien
+.%R RFC
+.%N 868
+.%D May 1983
+.%T "Time Protocol"
+.Re
+.Rs
+.%A M. Lottor
+.%R RFC
+.%N 1078
+.%D November 1988
+.%T "TCP port service Multiplexer (TCPMUX)"
 .Re
 .Sh HISTORY
 The
 .Nm
-utility appeared in
+command appeared in
 .Bx 4.3 .
-TCPMUX is based on code and documentation by Mark Lottor.
 Support for
-.Tn "ONC RPC"
+.Em Sun-RPC
 based services is modeled after that
-provided by
-.Tn SunOS
-4.1.
-The IPsec hack was contributed by the KAME project in 1999.
-The
-.Fx
-TCP Wrappers support first appeared in
-.Fx 3.2 .
+provided by SunOS 4.1.
+Support for specifying the socket buffer sizes was added in
+.Nx 1.4 .
+In November 1996, libwrap support was added to provide
+internal tcpd-like access control functionality;
+libwrap is based on Wietse Venema's tcp_wrappers.
+IPv6 support and IPsec hack was made by KAME project, in 1999.
+.Sh BUGS
+Host address specifiers, while they make conceptual sense for RPC
+services, do not work entirely correctly.
+This is largely because the portmapper interface does not provide
+a way to register different ports for the same service on different
+local addresses.
+Provided you never have more than one entry for a given RPC service,
+everything should work correctly (Note that default host address
+specifiers do apply to RPC lines with no explicit specifier.)
+.Pp
+.Dq tcpmux
+on IPv6 is not tested enough.
+.Sh SECURITY CONSIDERATIONS
+Enabling the
+.Dq echo ,
+.Dq discard ,
+and
+.Dq chargen
+built-in trivial services is not recommended because remote
+users may abuse these to cause a denial of network service to
+or from the local host.
+
+
diff -ur --unidirectional-new-file /usr/src/usr.sbin/inetd/inetd.c /usr/src-new/usr.sbin/inetd/inetd.c
--- /usr/src/usr.sbin/inetd/inetd.c	2006-01-13 14:26:46.000000000 -0600
+++ /usr/src-new/usr.sbin/inetd/inetd.c	2006-06-20 11:11:04.000000000 -0500
@@ -1,3 +1,40 @@
+/*-
+ * Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center and by Matthias Scheler.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 /*
  * Copyright (c) 1983, 1991, 1993, 1994
  *	The Regents of the University of California.  All rights reserved.
@@ -10,11 +47,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by the University of
- *	California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. 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.
  *
@@ -32,7 +65,7 @@
  *
  * @(#) Copyright (c) 1983, 1991, 1993, 1994 The Regents of the University of California.  All rights reserved.
  * @(#)from: inetd.c	8.4 (Berkeley) 4/13/94
- * $FreeBSD: src/usr.sbin/inetd/inetd.c,v 1.80.2.11 2003/04/05 13:39:18 dwmalone Exp $
+ * $NetBSD: inetd.c,v 1.101 2006/05/11 06:59:40 mrg Exp $
  * $DragonFly: src/usr.sbin/inetd/inetd.c,v 1.10 2006/01/13 20:26:46 swildner Exp $
  */
 
@@ -56,19 +89,51 @@
  * Inetd uses a configuration file which is read at startup
  * and, possibly, at some later time in response to a hangup signal.
  * The configuration file is ``free format'' with fields given in the
- * order shown below.  Continuation lines for an entry must begin with
+ * order shown below.  Continuation lines for an entry must being with
  * a space or tab.  All fields must be present in each entry.
  *
- *	service name			must be in /etc/services
- *					or name a tcpmux service 
- *					or specify a unix domain socket
+ *	service name			must be in /etc/services or must
+ *					name a tcpmux service
+ *	socket type			stream/dgram/raw/rdm/seqpacket
+ *	protocol			must be in /etc/protocols
+ *	wait/nowait[:max]		single-threaded/multi-threaded, max #
+ *	user[:group]			user/group to run daemon as
+ *	server program			full path name
+ *	server program arguments	maximum of MAXARGS (20)
+ *
+ * For RPC services
+ *      service name/version            must be in /etc/rpc
  *	socket type			stream/dgram/raw/rdm/seqpacket
- *	protocol			tcp[4][6][/faith,ttcp], udp[4][6], unix
- *	wait/nowait			single-threaded/multi-threaded
- *	user				user to run daemon as
+ *	protocol			must be in /etc/protocols
+ *	wait/nowait[:max]		single-threaded/multi-threaded
+ *	user[:group]			user to run daemon as
  *	server program			full path name
  *	server program arguments	maximum of MAXARGS (20)
  *
+ * For non-RPC services, the "service name" can be of the form
+ * hostaddress:servicename, in which case the hostaddress is used
+ * as the host portion of the address to listen on.  If hostaddress
+ * consists of a single `*' character, INADDR_ANY is used.
+ *
+ * A line can also consist of just
+ *	hostaddress:
+ * where hostaddress is as in the preceding paragraph.  Such a line must
+ * have no further fields; the specified hostaddress is remembered and
+ * used for all further lines that have no hostaddress specified,
+ * until the next such line (or EOF).  (This is why * is provided to
+ * allow explicit specification of INADDR_ANY.)  A line
+ *	*:
+ * is implicitly in effect at the beginning of the file.
+ *
+ * The hostaddress specifier may (and often will) contain dots;
+ * the service name must not.
+ *
+ * For RPC services, host-address specifiers are accepted and will
+ * work to some extent; however, because of limitations in the
+ * portmapper interface, it will not work to try to give more than
+ * one line for any given RPC service, even if the host-address
+ * specifiers are different.
+ *
  * TCP services without official port numbers are handled with the
  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
  * requests. When a connection is made from a foreign host, the service
@@ -84,15 +149,6 @@
  * because they do not have a well-known port and hence cannot listen
  * for new requests.
  *
- * For RPC services
- *	service name/version		must be in /etc/rpc
- *	socket type			stream/dgram/raw/rdm/seqpacket
- *	protocol			rpc/tcp, rpc/udp
- *	wait/nowait			single-threaded/multi-threaded
- *	user				user to run daemon as
- *	server program			full path name
- *	server program arguments	maximum of MAXARGS
- *
  * Comment lines are indicated by a `#' in column 1.
  *
  * #ifdef IPSEC
@@ -102,6 +158,30 @@
  * there's no IPsec policy.
  * #endif
  */
+
+/*
+ * Here's the scoop concerning the user:group feature:
+ *
+ * 1) set-group-option off.
+ *
+ * 	a) user = root:	NO setuid() or setgid() is done
+ *
+ * 	b) other:	setuid()
+ * 			setgid(primary group as found in passwd)
+ * 			initgroups(name, primary group)
+ *
+ * 2) set-group-option on.
+ *
+ * 	a) user = root:	NO setuid()
+ * 			setgid(specified group)
+ * 			NO initgroups()
+ *
+ * 	b) other:	setuid()
+ * 			setgid(specified group)
+ * 			initgroups(name, specified group)
+ *
+ */
+
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
@@ -109,13 +189,17 @@
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/un.h>
+#include <sys/event.h>
 
-#include <netinet/in.h>
+#include <netinet/in.h>  
 #include <netinet/tcp.h>
+
 #include <arpa/inet.h>
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
 
+#include <net/if.h>
+
 #include <errno.h>
 #include <err.h>
 #include <fcntl.h>
@@ -132,22 +216,23 @@
 #include <libutil.h>
 #include <sysexits.h>
 #include <ctype.h>
+#include <ifaddrs.h>
 
-#include "inetd.h"
 #include "pathnames.h"
 
 #ifdef IPSEC
 #include <netinet6/ipsec.h>
-#ifndef IPSEC_POLICY_IPSEC	/* no ipsec support on old ipsec */
+#ifndef IPSEC_POLICY_IPSEC      /* no ipsec support on old ipsec */
 #undef IPSEC
 #endif
 #endif
 
-/* wrapper for KAME-special getnameinfo() */
-#ifndef NI_WITHSCOPEID
-#define NI_WITHSCOPEID	0
+#ifndef RLIMIT_NOFILE
+#define RLIMIT_NOFILE	RLIMIT_OFILE
 #endif
 
+#ifdef LIBWRAP
+# include <tcpd.h>
 #ifndef LIBWRAP_ALLOW_FACILITY
 # define LIBWRAP_ALLOW_FACILITY LOG_AUTH
 #endif
@@ -160,971 +245,727 @@
 #ifndef LIBWRAP_DENY_SEVERITY
 # define LIBWRAP_DENY_SEVERITY LOG_WARNING
 #endif
-
-#define ISWRAP(sep)	\
-	   ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \
-	&& (sep->se_family == AF_INET || sep->se_family == AF_INET6) \
-	&& ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \
-	    || (sep)->se_socktype == SOCK_DGRAM))
-
-#ifdef LOGIN_CAP
-#include <login_cap.h>
-
-/* see init.c */
-#define RESOURCE_RC "daemon"
-
-#endif
-
-#ifndef	MAXCHILD
-#define	MAXCHILD	-1		/* maximum number of this service
-					   < 0 = no limit */
-#endif
-
-#ifndef	MAXCPM
-#define	MAXCPM		-1		/* rate limit invocations from a
-					   single remote address,
-					   < 0 = no limit */
-#endif
-
-#ifndef	MAXPERIP
-#define	MAXPERIP	-1		/* maximum number of this service
-					   from a single remote address,
-					   < 0 = no limit */
+int allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
+int deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
 #endif
 
-#ifndef TOOMANY
-#define	TOOMANY		256		/* don't start more than TOOMANY */
-#endif
+#define	TOOMANY		40		/* don't start more than TOOMANY */
 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
-#define MAX_MAXCHLD	32767		/* max allowable max children */
 
-#define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
+#define	A_CNT(a)	(sizeof (a) / sizeof (a[0]))
 
-void		close_sep(struct servtab *);
-void		flag_signal(int);
-void		flag_config(int);
-void		config(void);
-int		cpmip(const struct servtab *, int);
-void		endconfig(void);
-struct servtab *enter(struct servtab *);
-void		freeconfig(struct servtab *);
-struct servtab *getconfigent(void);
-int		matchservent(const char *, const char *, const char *);
-char	       *nextline(FILE *);
-void		addchild(struct servtab *, int);
-void		flag_reapchild(int);
-void		reapchild(void);
-void		enable(struct servtab *);
-void		disable(struct servtab *);
-void		flag_retry(int);
-void		retry(void);
-int		setconfig(void);
-void		setup(struct servtab *);
-#ifdef IPSEC
-void		ipsecsetup(struct servtab *);
+int	debug;
+#ifdef LIBWRAP
+int	lflag;
 #endif
-void		unregisterrpc(struct servtab *sep);
-static struct conninfo *search_conn(struct servtab *sep, int ctrl);
-static int	room_conn(struct servtab *sep, struct conninfo *conn);
-static void	addchild_conn(struct conninfo *conn, pid_t pid);
-static void	reapchild_conn(pid_t pid);
-static void	free_conn(struct conninfo *conn);
-static void	resize_conn(struct servtab *sep, int maxperip);
-static void	free_connlist(struct servtab *sep);
-static void	free_proc(struct procinfo *);
-static struct procinfo *search_proc(pid_t pid, int add);
-static int	hashval(char *p, int len);
-
-int	allow_severity;
-int	deny_severity;
-int	wrap_ex = 0;
-int	wrap_bi = 0;
-int	debug = 0;
-int	log = 0;
-int	maxsock;			/* highest-numbered descriptor */
-fd_set	allsock;
+int	maxsock;
+int	kq;
 int	options;
 int	timingout;
-int	toomany = TOOMANY;
-int	maxchild = MAXCHILD;
-int	maxcpm = MAXCPM;
-int	maxperip = MAXPERIP;
 struct	servent *sp;
-struct	rpcent *rpc;
-char	*hostname = NULL;
-struct	sockaddr_in *bind_sa4;
-int	no_v4bind = 1;
-#ifdef INET6
-struct	sockaddr_in6 *bind_sa6;
-int	no_v6bind = 1;
+char	*curdom;
+const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+
+#ifndef OPEN_MAX
+#define OPEN_MAX	64
 #endif
-int	signalpipe[2];
-#ifdef SANITY_CHECK
-int	nsock;
+
+/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
+#define FD_MARGIN	(8)
+rlim_t		rlim_ofile_cur = OPEN_MAX;
+
+#ifdef RLIMIT_NOFILE
+struct rlimit	rlim_ofile;
+#endif
+
+struct kevent	changebuf[64];
+size_t		changes;
+
+struct	servtab {
+	char	*se_hostaddr;		/* host address to listen on */
+	char	*se_service;		/* name of service */
+	int	se_socktype;		/* type of socket to use */
+	int	se_family;		/* address family */
+	char	*se_proto;		/* protocol used */
+	int	se_sndbuf;		/* sndbuf size */
+	int	se_rcvbuf;		/* rcvbuf size */
+	int	se_rpcprog;		/* rpc program number */
+	int	se_rpcversl;		/* rpc program lowest version */
+	int	se_rpcversh;		/* rpc program highest version */
+#define isrpcservice(sep)	((sep)->se_rpcversl != 0)
+	pid_t	se_wait;		/* single threaded server */
+	short	se_checked;		/* looked at during merge */
+	char	*se_user;		/* user name to run as */
+	char	*se_group;		/* group name to run as */
+	struct	biltin *se_bi;		/* if built-in, description */
+	char	*se_server;		/* server program */
+#define	MAXARGV 20
+	char	*se_argv[MAXARGV+1];	/* program arguments */
+#ifdef IPSEC
+	char	*se_policy;		/* IPsec poilcy string */
 #endif
-uid_t	euid;
-gid_t	egid;
-mode_t	mask;
+	int	se_fd;			/* open descriptor */
+	int	se_type;		/* type */
+	union {
+		struct	sockaddr se_un_ctrladdr;
+		struct	sockaddr_in se_un_ctrladdr_in;
+		struct	sockaddr_in6 se_un_ctrladdr_in6;
+		struct	sockaddr_un se_un_ctrladdr_un;
+	} se_un;			/* bound address */
+#define se_ctrladdr	se_un.se_un_ctrladdr
+#define se_ctrladdr_in	se_un.se_un_ctrladdr_in
+#define se_ctrladdr_un	se_un.se_un_ctrladdr_un
+	int	se_ctrladdr_size;
+	int	se_max;			/* max # of instances of this service */
+	int	se_count;		/* number started since se_time */
+	struct	timeval se_time;	/* start of se_count */
+#ifdef MULOG
+	int	se_log;
+#define MULOG_RFC931	0x40000000
+#endif
+	struct	servtab *se_next;
+} *servtab;
+
+#define NORM_TYPE	0
+#define MUX_TYPE	1
+#define MUXPLUS_TYPE	2
+#define FAITH_TYPE	3
+#define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
+			 ((sep)->se_type == MUXPLUS_TYPE))
+#define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
+
+
+static void	chargen_dg(int, struct servtab *);
+static void	chargen_stream(int, struct servtab *);
+static void	close_sep(struct servtab *);
+static void	config(void);
+static void	daytime_dg(int, struct servtab *);
+static void	daytime_stream(int, struct servtab *);
+static void	discard_dg(int, struct servtab *);
+static void	discard_stream(int, struct servtab *);
+static void	echo_dg(int, struct servtab *);
+static void	echo_stream(int, struct servtab *);
+static void	endconfig(void);
+static struct servtab *enter(struct servtab *);
+static void	freeconfig(struct servtab *);
+static struct servtab *getconfigent(void);
+static void	goaway(void);
+static void	machtime_dg(int, struct servtab *);
+static void	machtime_stream(int, struct servtab *);
+static char    *newstr(char *);
+static char    *nextline(FILE *);
+static void	print_service(char *, struct servtab *);
+static void	reapchild(void);
+static void	retry(void);
+static void	run_service(int, struct servtab *);
+static int	setconfig(void);
+static void	setup(struct servtab *);
+static char    *sskip(char **);
+static char    *skip(char **);
+static void	tcpmux(int, struct servtab *);
+static void	usage(void);
+static void	register_rpc(struct servtab *);
+static void	unregister_rpc(struct servtab *);
+static void	bump_nofile(void);
+static void	inetd_setproctitle(char *, int);
+static void	initring(void);
+static uint32_t	machtime(void);
+static int	port_good_dg(struct sockaddr *);
+static int 	dg_broadcast(struct in_addr *);
+static int	my_kevent(const struct kevent *, size_t, struct kevent *,
+		size_t);
+static struct kevent *	allocchange(void);
+static int	getline(int, char *, int);
+static void	spawn(struct servtab *, int);
+#ifdef MULOG
+static void	dolog(struct servtab *, int);
+static void	timeout(int);
+static char    *rfc931_name(struct sockaddr *, int);
+#endif
+
+struct biltin {
+	char	*bi_service;		/* internally provided service name */
+	int	bi_socktype;		/* type of socket supported */
+	short	bi_fork;		/* 1 if should fork before call */
+	short	bi_wait;		/* 1 if should wait for child */
+	void	(*bi_fn)(int, struct servtab *);
+					/* function which performs it */
+} biltins[] = {
+	/* Echo received data */
+	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
+	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
+
+	/* Internet /dev/null */
+	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
+	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
+
+	/* Return 32 bit time since 1970 */
+	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
+	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
+
+	/* Return human-readable time */
+	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
+	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
+
+	/* Familiar character generator */
+	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
+	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
+
+	{ "tcpmux",	SOCK_STREAM,	1, 0,	tcpmux },
+
+	{ NULL }
+};
+
+/* list of "bad" ports. I.e. ports that are most obviously used for
+ * "cycling packets" denial of service attacks. See /etc/services.
+ * List must end with port number "0".
+ */
 
-struct	servtab *servtab;
+u_int16_t bad_ports[] =  { 7, 9, 13, 19, 37, 0 };
 
-extern struct biltin biltins[];
 
 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
-const char	*CONFIG = _PATH_INETDCONF;
-const char	*pid_file = _PATH_INETDPID;
+char	*CONFIG = _PATH_INETDCONF;
 
-static LIST_HEAD(, procinfo) proctable[PERIPSIZE];
+static int my_signals[] =
+    { SIGALRM, SIGHUP, SIGCHLD, SIGTERM, SIGINT, SIGPIPE };
 
 int
-getvalue(const char *arg, int *value, const char *whine)
-{
-	int  tmp;
-	char *p;
-
-	tmp = strtol(arg, &p, 0);
-	if (tmp < 0 || *p) {
-		syslog(LOG_ERR, whine, arg);
-		return 1;			/* failure */
-	}
-	*value = tmp;
-	return 0;				/* success */
-}
-
-static sa_family_t
-whichaf(struct request_info *req)
+main(int argc, char *argv[])
 {
-	struct sockaddr *sa;
-
-	sa = (struct sockaddr *)req->client->sin;
-	if (sa == NULL)
-		return AF_UNSPEC;
-	if (sa->sa_family == AF_INET6 &&
-	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr))
-		return AF_INET;
-	return sa->sa_family;
-}
+	int		ch, n, reload = 1;
 
-int
-main(int argc, char **argv)
-{
-	struct servtab *sep;
-	struct passwd *pwd;
-	struct group *grp;
-	struct sigaction sa, saalrm, sachld, sahup, sapipe;
-	int ch, dofork;
-	pid_t pid;
-	char buf[50];
-#ifdef LOGIN_CAP
-	login_cap_t *lc = NULL;
+	while ((ch = getopt(argc, argv,
+#ifdef LIBWRAP
+					"dl"
+#else
+					"d"
 #endif
-	struct request_info req;
-	int denied;
-	char *service = NULL;
-	union {
-		struct sockaddr peer_un;
-		struct sockaddr_in peer_un4;
-		struct sockaddr_in6 peer_un6;
-		struct sockaddr_storage peer_max;
-	} p_un;
-#define peer	p_un.peer_un
-#define peer4	p_un.peer_un4
-#define peer6	p_un.peer_un6
-#define peermax	p_un.peer_max
-	int i;
-	struct addrinfo hints, *res;
-	const char *servname;
-	int error;
-	struct conninfo *conn;
-
-	openlog("inetd", LOG_PID | LOG_NOWAIT | LOG_PERROR, LOG_DAEMON);
-
-	while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:s:")) != -1)
+					   )) != -1)
 		switch(ch) {
 		case 'd':
 			debug = 1;
 			options |= SO_DEBUG;
 			break;
+#ifdef LIBWRAP
 		case 'l':
-			log = 1;
-			break;
-		case 'R':
-			getvalue(optarg, &toomany,
-				"-R %s: bad value for service invocation rate");
-			break;
-		case 'c':
-			getvalue(optarg, &maxchild,
-				"-c %s: bad value for maximum children");
-			break;
-		case 'C':
-			getvalue(optarg, &maxcpm,
-				"-C %s: bad value for maximum children/minute");
-			break;
-		case 'a':
-			hostname = optarg;
-			break;
-		case 'p':
-			pid_file = optarg;
-			break;
-		case 's':
-			getvalue(optarg, &maxperip,
-				"-s %s: bad value for maximum children per source address");
-			break;
-		case 'w':
-			wrap_ex++;
-			break;
-		case 'W':
-			wrap_bi++;
+			lflag = 1;
 			break;
+#endif
 		case '?':
 		default:
-			syslog(LOG_ERR,
-				"usage: inetd [-dlwW] [-a address] [-R rate]"
-				" [-c maximum] [-C rate]"
-				" [-p pidfile] [conf-file]");
-			exit(EX_USAGE);
+			usage();
 		}
-	/*
-	 * Initialize Bind Addrs.
-	 *   When hostname is NULL, wild card bind addrs are obtained from
-	 *   getaddrinfo(). But getaddrinfo() requires at least one of
-	 *   hostname or servname is non NULL.
-	 *   So when hostname is NULL, set dummy value to servname.
-	 */
-	servname = (hostname == NULL) ? "discard" /* dummy */ : NULL;
+	argc -= optind;
+	argv += optind;
+
+	if (argc > 0)
+		CONFIG = argv[0];
 
-	bzero(&hints, sizeof(struct addrinfo));
-	hints.ai_flags = AI_PASSIVE;
-	hints.ai_family = AF_UNSPEC;
-	error = getaddrinfo(hostname, servname, &hints, &res);
-	if (error != 0) {
-		syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error));
-		if (error == EAI_SYSTEM)
-			syslog(LOG_ERR, "%s", strerror(errno));
-		exit(EX_USAGE);
+	if (!debug)
+		daemon(0, 0);
+	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
+	pidfile(NULL);
+
+	kq = kqueue();
+	if (kq < 0) {
+		syslog(LOG_ERR, "kqueue: %m");
+		return (EXIT_FAILURE);
 	}
-	do {
-		if (res->ai_addr == NULL) {
-			syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
-			exit(EX_USAGE);
-		}
-		switch (res->ai_addr->sa_family) {
-		case AF_INET:
-			if (no_v4bind == 0)
-				continue;
-			bind_sa4 = (struct sockaddr_in *)res->ai_addr;
-			/* init port num in case servname is dummy */
-			bind_sa4->sin_port = 0;
-			no_v4bind = 0;
-			continue;
-#ifdef INET6
-		case AF_INET6:
-			if (no_v6bind == 0)
-				continue;
-			bind_sa6 = (struct sockaddr_in6 *)res->ai_addr;
-			/* init port num in case servname is dummy */
-			bind_sa6->sin6_port = 0;
-			no_v6bind = 0;
-			continue;
-#endif
-		}
-		if (no_v4bind == 0
-#ifdef INET6
-		    && no_v6bind == 0
-#endif
-		    )
-			break;
-	} while ((res = res->ai_next) != NULL);
-	if (no_v4bind != 0
-#ifdef INET6
-	    && no_v6bind != 0
-#endif
-	    ) {
-		syslog(LOG_ERR, "-a %s: unknown address family", hostname);
-		exit(EX_USAGE);
+
+#ifdef RLIMIT_NOFILE
+	if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
+		syslog(LOG_ERR, "getrlimit: %m");
+	} else {
+		rlim_ofile_cur = rlim_ofile.rlim_cur;
+		if (rlim_ofile_cur == RLIM_INFINITY)	/* ! */
+			rlim_ofile_cur = OPEN_MAX;
 	}
+#endif
 
-	euid = geteuid();
-	egid = getegid();
-	umask(mask = umask(0777));
+	for (n = 0; n < A_CNT(my_signals); n++) {
+		int	signum;
 
-	argc -= optind;
-	argv += optind;
+		signum = my_signals[n];
+		if (signum != SIGCHLD)
+			(void) signal(signum, SIG_IGN);
 
-	if (argc > 0)
-		CONFIG = argv[0];
-	if (debug == 0) {
-		FILE *fp;
-		if (daemon(0, 0) < 0) {
-			syslog(LOG_WARNING, "daemon(0,0) failed: %m");
-		}
-		/* From now on we don't want syslog messages going to stderr. */
-		closelog();
-		openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
-		/*
-		 * In case somebody has started inetd manually, we need to
-		 * clear the logname, so that old servers run as root do not
-		 * get the user's logname..
-		 */
-		if (setlogin("") < 0) {
-			syslog(LOG_WARNING, "cannot clear logname: %m");
-			/* no big deal if it fails.. */
-		}
-		pid = getpid();
-		fp = fopen(pid_file, "w");
-		if (fp) {
-			fprintf(fp, "%ld\n", (long)pid);
-			fclose(fp);
-		} else {
-			syslog(LOG_WARNING, "%s: %m", pid_file);
+		if (signum != SIGPIPE) {
+			struct kevent	*ev;
+
+			ev = allocchange();
+			EV_SET(ev, signum, EVFILT_SIGNAL, EV_ADD | EV_ENABLE,
+			    0, 0, 0);
 		}
 	}
-	for (i = 0; i < PERIPSIZE; ++i)
-		LIST_INIT(&proctable[i]);
-	sa.sa_flags = 0;
-	sigemptyset(&sa.sa_mask);
-	sigaddset(&sa.sa_mask, SIGALRM);
-	sigaddset(&sa.sa_mask, SIGCHLD);
-	sigaddset(&sa.sa_mask, SIGHUP);
-	sa.sa_handler = flag_retry;
-	sigaction(SIGALRM, &sa, &saalrm);
-	config();
-	sa.sa_handler = flag_config;
-	sigaction(SIGHUP, &sa, &sahup);
-	sa.sa_handler = flag_reapchild;
-	sigaction(SIGCHLD, &sa, &sachld);
-	sa.sa_handler = SIG_IGN;
-	sigaction(SIGPIPE, &sa, &sapipe);
-
-	{
-		/* space for daemons to overwrite environment for ps */
-#define	DUMMYSIZE	100
-		char dummy[DUMMYSIZE];
-
-		memset(dummy, 'x', DUMMYSIZE - 1);
-		dummy[DUMMYSIZE - 1] = '\0';
-		if (setenv("inetd_dummy", dummy, 1) == -1)
-			syslog(LOG_WARNING, "setenv: cannot set inetd_dummy=%s: %m", dummy);
-		
-	}
-
-	if (pipe(signalpipe) != 0) {
-		syslog(LOG_ERR, "pipe: %m");
-		exit(EX_OSERR);
-	}
-	if (fcntl(signalpipe[0], F_SETFD, FD_CLOEXEC) < 0 ||
-	    fcntl(signalpipe[1], F_SETFD, FD_CLOEXEC) < 0) {
-		syslog(LOG_ERR, "signalpipe: fcntl (F_SETFD, FD_CLOEXEC): %m");
-		exit(EX_OSERR);
-	}
-	FD_SET(signalpipe[0], &allsock);
-#ifdef SANITY_CHECK
-	nsock++;
-#endif
-	if (signalpipe[0] > maxsock)
-	    maxsock = signalpipe[0];
-	if (signalpipe[1] > maxsock)
-	    maxsock = signalpipe[1];
 
 	for (;;) {
-	    int n, ctrl;
-	    fd_set readable;
+		int		ctrl;
+		struct kevent	eventbuf[64], *ev;
+		struct servtab	*sep;
 
-#ifdef SANITY_CHECK
-	    if (nsock == 0) {
-		syslog(LOG_ERR, "%s: nsock=0", __func__);
-		exit(EX_SOFTWARE);
-	    }
-#endif
-	    readable = allsock;
-	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
-		(fd_set *)0, (struct timeval *)0)) <= 0) {
-		    if (n < 0 && errno != EINTR) {
-			syslog(LOG_WARNING, "select: %m");
-			sleep(1);
-		    }
-		    continue;
-	    }
-	    /* handle any queued signal flags */
-	    if (FD_ISSET(signalpipe[0], &readable)) {
-		int nsig;
-		if (ioctl(signalpipe[0], FIONREAD, &nsig) != 0) {
-		    syslog(LOG_ERR, "ioctl: %m");
-		    exit(EX_OSERR);
-		}
-		while (--nsig >= 0) {
-		    char c;
-		    if (read(signalpipe[0], &c, 1) != 1) {
-			syslog(LOG_ERR, "read: %m");
-			exit(EX_OSERR);
-		    }
-		    if (debug)
-			warnx("handling signal flag %c", c);
-		    switch(c) {
-		    case 'A': /* sigalrm */
-			retry();
-			break;
-		    case 'C': /* sigchld */
-			reapchild();
-			break;
-		    case 'H': /* sighup */
+		if (reload) {
+			reload = 0;
 			config();
-			break;
-		    }
 		}
-	    }
-	    for (sep = servtab; n && sep; sep = sep->se_next)
-	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
-		    n--;
-		    if (debug)
-			    warnx("someone wants %s", sep->se_service);
-		    dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep);
-		    conn = NULL;
-		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
-			    i = 1;
-			    if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
-				    syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m");
-			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
-				(socklen_t *)0);
-			    if (debug)
-				    warnx("accept, ctrl %d", ctrl);
-			    if (ctrl < 0) {
-				    if (errno != EINTR)
-					    syslog(LOG_WARNING,
-						"accept (for %s): %m",
-						sep->se_service);
-                                      if (sep->se_accept &&
-                                          sep->se_socktype == SOCK_STREAM)
-                                              close(ctrl);
-				    continue;
-			    }
-			    i = 0;
-			    if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
-				    syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m");
-			    if (ioctl(ctrl, FIONBIO, &i) < 0)
-				    syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m");
-			    if (cpmip(sep, ctrl) < 0) {
-				close(ctrl);
+
+		n = my_kevent(changebuf, changes, eventbuf, A_CNT(eventbuf));
+		changes = 0;
+
+		for (ev = eventbuf; n > 0; ev++, n--) {
+			if (ev->filter == EVFILT_SIGNAL) {
+				switch (ev->ident) {
+				case SIGALRM:
+					retry();
+					break;
+				case SIGCHLD:
+					reapchild();
+					break;
+				case SIGTERM:
+				case SIGINT:
+					goaway();
+					break;
+				case SIGHUP:
+					reload = 1;
+					break;
+				}
 				continue;
-			    }
-			    if (dofork &&
-				(conn = search_conn(sep, ctrl)) != NULL &&
-				!room_conn(sep, conn)) {
-				close(ctrl);
+			}
+			if (ev->filter != EVFILT_READ)
 				continue;
-			    }
-		    } else
-			    ctrl = sep->se_fd;
-		    if (log && !ISWRAP(sep)) {
-			    char pname[INET6_ADDRSTRLEN] = "unknown";
-			    socklen_t sl;
-			    sl = sizeof peermax;
-			    if (getpeername(ctrl, (struct sockaddr *)
-					    &peermax, &sl)) {
-				    sl = sizeof peermax;
-				    if (recvfrom(ctrl, buf, sizeof(buf),
-					MSG_PEEK,
-					(struct sockaddr *)&peermax,
-					&sl) >= 0) {
-				      getnameinfo((struct sockaddr *)&peermax,
-						  peer.sa_len,
-						  pname, sizeof(pname),
-						  NULL, 0, 
-						  NI_NUMERICHOST|
-						  NI_WITHSCOPEID);
-				    }
-			    } else {
-			            getnameinfo((struct sockaddr *)&peermax,
-						peer.sa_len,
-						pname, sizeof(pname),
-						NULL, 0, 
-						NI_NUMERICHOST|
-						NI_WITHSCOPEID);
-			    }
-			    syslog(LOG_INFO,"%s from %s", sep->se_service, pname);
-		    }
-		    sigblock(SIGBLOCK);
-		    pid = 0;
-		    /*
-		     * Fork for all external services, builtins which need to
-		     * fork and anything we're wrapping (as wrapping might
-		     * block or use hosts_options(5) twist).
-		     */
-		    if (dofork) {
-			    if (sep->se_count++ == 0)
-				gettimeofday(&sep->se_time, (struct timezone *)NULL);
-			    else if (toomany > 0 && sep->se_count >= toomany) {
-				struct timeval now;
-
-				gettimeofday(&now, (struct timezone *)NULL);
-				if (now.tv_sec - sep->se_time.tv_sec >
-				    CNT_INTVL) {
-					sep->se_time = now;
-					sep->se_count = 1;
-				} else {
-					syslog(LOG_ERR,
-			"%s/%s server failing (looping), service terminated",
-					    sep->se_service, sep->se_proto);
-					if (sep->se_accept &&
-					    sep->se_socktype == SOCK_STREAM)
-						close(ctrl);
-					close_sep(sep);
-					free_conn(conn);
-					sigsetmask(0L);
-					if (!timingout) {
-						timingout = 1;
-						alarm(RETRYTIME);
-					}
-					continue;
-				}
-			    }
-			    pid = fork();
-		    }
-		    if (pid < 0) {
-			    syslog(LOG_ERR, "fork: %m");
-			    if (sep->se_accept &&
-				sep->se_socktype == SOCK_STREAM)
-				    close(ctrl);
-			    free_conn(conn);
-			    sigsetmask(0L);
-			    sleep(1);
-			    continue;
-		    }
-		    if (pid) {
-			addchild_conn(conn, pid);
-			addchild(sep, pid);
-		    }
-		    sigsetmask(0L);
-		    if (pid == 0) {
-			    if (dofork) {
-				sigaction(SIGALRM, &saalrm, (struct sigaction *)0);
-				sigaction(SIGCHLD, &sachld, (struct sigaction *)0);
-				sigaction(SIGHUP, &sahup, (struct sigaction *)0);
-				/* SIGPIPE reset before exec */
-			    }
-			    /*
-			     * Call tcpmux to find the real service to exec.
-			     */
-			    if (sep->se_bi &&
-				sep->se_bi->bi_fn == (bi_fn_t *) tcpmux) {
-				    sep = tcpmux(ctrl);
-				    if (sep == NULL) {
-					    close(ctrl);
-					    _exit(0);
-				    }
-			    }
-			    if (ISWRAP(sep)) {
-				inetd_setproctitle("wrapping", ctrl);
-				service = sep->se_server_name ?
-				    sep->se_server_name : sep->se_service;
-				request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL);
-				fromhost(&req);
-				deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
-				allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
-				denied = !hosts_access(&req);
-				if (denied) {
-				    syslog(deny_severity,
-				        "refused connection from %.500s, service %s (%s%s)",
-				        eval_client(&req), service, sep->se_proto,
-					(whichaf(&req) == AF_INET6) ? "6" : "");
-				    if (sep->se_socktype != SOCK_STREAM)
-					recv(ctrl, buf, sizeof (buf), 0);
-				    if (dofork) {
-					sleep(1);
-					_exit(0);
-				    }
-				}
-				if (log) {
-				    syslog(allow_severity,
-				        "connection from %.500s, service %s (%s%s)",
-					eval_client(&req), service, sep->se_proto,
-					(whichaf(&req) == AF_INET6) ? "6" : "");
-				}
-			    }
-			    if (sep->se_bi) {
-				(*sep->se_bi->bi_fn)(ctrl, sep);
-			    } else {
+			sep = (struct servtab *)ev->udata;
+			/* Paranoia */
+			if (ev->ident != sep->se_fd)
+				continue;
+			if (debug)
+				fprintf(stderr, "someone wants %s\n",
+				    sep->se_service);
+			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
+				/* XXX here do the libwrap check-before-accept*/
+				ctrl = accept(sep->se_fd, NULL, NULL);
 				if (debug)
-					warnx("%d execl %s",
-						getpid(), sep->se_server);
-				/* Clear close-on-exec. */
-				if (fcntl(ctrl, F_SETFD, 0) < 0) {
-					syslog(LOG_ERR,
-					    "%s/%s: fcntl (F_SETFD, 0): %m",
-						sep->se_service, sep->se_proto);
-					_exit(EX_OSERR);
-				}
-				if (ctrl != 0) {
-					dup2(ctrl, 0);
-					close(ctrl);
-				}
-				dup2(0, 1);
-				dup2(0, 2);
-				if ((pwd = getpwnam(sep->se_user)) == NULL) {
-					syslog(LOG_ERR,
-					    "%s/%s: %s: no such user",
-						sep->se_service, sep->se_proto,
-						sep->se_user);
-					if (sep->se_socktype != SOCK_STREAM)
-						recv(0, buf, sizeof (buf), 0);
-					_exit(EX_NOUSER);
-				}
-				grp = NULL;
-				if (   sep->se_group != NULL
-				    && (grp = getgrnam(sep->se_group)) == NULL
-				   ) {
-					syslog(LOG_ERR,
-					    "%s/%s: %s: no such group",
-						sep->se_service, sep->se_proto,
-						sep->se_group);
-					if (sep->se_socktype != SOCK_STREAM)
-						recv(0, buf, sizeof (buf), 0);
-					_exit(EX_NOUSER);
-				}
-				if (grp != NULL)
-					pwd->pw_gid = grp->gr_gid;
-#ifdef LOGIN_CAP
-				if ((lc = login_getclass(sep->se_class)) == NULL) {
-					/* error syslogged by getclass */
-					syslog(LOG_ERR,
-					    "%s/%s: %s: login class error",
-						sep->se_service, sep->se_proto,
-						sep->se_class);
-					if (sep->se_socktype != SOCK_STREAM)
-						recv(0, buf, sizeof (buf), 0);
-					_exit(EX_NOUSER);
-				}
-#endif
-				if (setsid() < 0) {
-					syslog(LOG_ERR,
-						"%s: can't setsid(): %m",
-						 sep->se_service);
-					/* _exit(EX_OSERR); not fatal yet */
-				}
-#ifdef LOGIN_CAP
-				if (setusercontext(lc, pwd, pwd->pw_uid,
-				    LOGIN_SETALL) != 0) {
-					syslog(LOG_ERR,
-					 "%s: can't setusercontext(..%s..): %m",
-					 sep->se_service, sep->se_user);
-					_exit(EX_OSERR);
-				}
-				login_close(lc);
-#else
-				if (pwd->pw_uid) {
-					if (setlogin(sep->se_user) < 0) {
-						syslog(LOG_ERR,
-						 "%s: can't setlogin(%s): %m",
-						 sep->se_service, sep->se_user);
-						/* _exit(EX_OSERR); not yet */
-					}
-					if (setgid(pwd->pw_gid) < 0) {
-						syslog(LOG_ERR,
-						  "%s: can't set gid %d: %m",
-						  sep->se_service, pwd->pw_gid);
-						_exit(EX_OSERR);
-					}
-					initgroups(pwd->pw_name,
-							pwd->pw_gid);
-					if (setuid(pwd->pw_uid) < 0) {
-						syslog(LOG_ERR,
-						  "%s: can't set uid %d: %m",
-						  sep->se_service, pwd->pw_uid);
-						_exit(EX_OSERR);
-					}
+					fprintf(stderr, "accept, ctrl %d\n",
+					    ctrl);
+				if (ctrl < 0) {
+					if (errno != EINTR)
+						syslog(LOG_WARNING,
+						    "accept (for %s): %m",
+						    sep->se_service);
+					continue;
 				}
-#endif
-				sigaction(SIGPIPE, &sapipe,
-				    (struct sigaction *)0);
-				execv(sep->se_server, sep->se_argv);
-				syslog(LOG_ERR,
-				    "cannot execute %s: %m", sep->se_server);
-				if (sep->se_socktype != SOCK_STREAM)
-					recv(0, buf, sizeof (buf), 0);
-			    }
-			    if (dofork)
-				_exit(0);
-		    }
-		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
-			    close(ctrl);
+			} else
+				ctrl = sep->se_fd;
+			spawn(sep, ctrl);
 		}
 	}
 }
 
-/*
- * Add a signal flag to the signal flag queue for later handling
- */
-
-void
-flag_signal(int c)
+static void
+spawn(struct servtab *sep, int ctrl)
 {
-	char ch = c;
+	int dofork;
+	pid_t pid;
+
+	pid = 0;
+#ifdef LIBWRAP_INTERNAL
+	dofork = 1;
+#else
+	dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
+#endif
+	if (dofork) {
+		if (sep->se_count++ == 0)
+			(void)gettimeofday(&sep->se_time, NULL);
+		else if (sep->se_count >= sep->se_max) {
+			struct timeval now;
+
+			(void)gettimeofday(&now, NULL);
+			if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
+				sep->se_time = now;
+				sep->se_count = 1;
+			} else {
+				syslog(LOG_ERR,
+				    "%s/%s max spawn rate (%d in %d seconds) "
+				    "exceeded; service not started",
+				    sep->se_service, sep->se_proto,
+				    sep->se_max, CNT_INTVL);
+				if (!sep->se_wait && sep->se_socktype ==
+				    SOCK_STREAM)
+					close(ctrl);
+				close_sep(sep);
+				if (!timingout) {
+					timingout = 1;
+					alarm(RETRYTIME);
+				}
+				return;
+			}
+		}
+		pid = fork();
+		if (pid < 0) {
+			syslog(LOG_ERR, "fork: %m");
+			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
+				close(ctrl);
+			sleep(1);
+			return;
+		}
+		if (pid != 0 && sep->se_wait) {
+			struct kevent	*ev;
 
-	if (write(signalpipe[1], &ch, 1) != 1) {
-		syslog(LOG_ERR, "write: %m");
-		_exit(EX_OSERR);
+			sep->se_wait = pid;
+			ev = allocchange();
+			EV_SET(ev, sep->se_fd, EVFILT_READ,
+			    EV_DELETE, 0, 0, 0);
+		}
+		if (pid == 0) {
+			int	n;
+
+			for (n = 0; n < A_CNT(my_signals); n++)
+				(void) signal(my_signals[n], SIG_DFL);
+			if (debug)
+				setsid();
+		}
 	}
+	if (pid == 0) {
+		run_service(ctrl, sep);
+		if (dofork)
+			exit(0);
+	}
+	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
+		close(ctrl);
 }
 
-/*
- * Record a new child pid for this service. If we've reached the
- * limit on children, then stop accepting incoming requests.
- */
-
-void
-addchild(struct servtab *sep, pid_t pid)
+static void
+run_service(int ctrl, struct servtab *sep)
 {
-	if (sep->se_maxchild <= 0)
-		return;
-#ifdef SANITY_CHECK
-	if (sep->se_numchild >= sep->se_maxchild) {
-		syslog(LOG_ERR, "%s: %d >= %d",
-		    __func__, sep->se_numchild, sep->se_maxchild);
-		exit(EX_SOFTWARE);
-	}
+	struct passwd *pwd;
+	struct group *grp = NULL;	/* XXX gcc */
+	char buf[NI_MAXSERV];
+#ifdef LIBWRAP
+	struct request_info req;
+	int denied;
+	char *service = NULL;	/* XXX gcc */
 #endif
-	sep->se_pids[sep->se_numchild++] = pid;
-	if (sep->se_numchild == sep->se_maxchild)
-		disable(sep);
-}
 
-/*
- * Some child process has exited. See if it's on somebody's list.
- */
+#ifdef LIBWRAP
+#ifndef LIBWRAP_INTERNAL
+	if (sep->se_bi == 0)
+#endif
+	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
+		request_init(&req, RQ_DAEMON, sep->se_argv[0] ?
+		    sep->se_argv[0] : sep->se_service, RQ_FILE, ctrl, NULL);
+		fromhost(&req);
+		denied = !hosts_access(&req);
+		if (denied || lflag) {
+			if (getnameinfo(&sep->se_ctrladdr,
+					sep->se_ctrladdr.sa_len, NULL, 0,
+					buf, sizeof(buf), 0) != 0) {
+				/* shouldn't happen */
+				(void)snprintf(buf, sizeof buf, "%d",
+				    ntohs(sep->se_ctrladdr_in.sin_port));
+			}
+			service = buf;
+		}
+		if (denied) {
+			syslog(deny_severity,
+			    "refused connection from %.500s, service %s (%s)",
+			    eval_client(&req), service, sep->se_proto);
+			goto reject;
+		}
+		if (lflag) {
+			syslog(allow_severity,
+			    "connection from %.500s, service %s (%s)",
+			    eval_client(&req), service, sep->se_proto);
+		}
+	}
+#endif /* LIBWRAP */
 
-void
-flag_reapchild(int signo __unused)
-{
-	flag_signal('C');
+	if (sep->se_bi) {
+		(*sep->se_bi->bi_fn)(ctrl, sep);
+	} else {
+		if ((pwd = getpwnam(sep->se_user)) == NULL) {
+			syslog(LOG_ERR, "%s/%s: %s: No such user",
+			    sep->se_service, sep->se_proto, sep->se_user);
+			goto reject;
+		}
+		if (sep->se_group &&
+		    (grp = getgrnam(sep->se_group)) == NULL) {
+			syslog(LOG_ERR, "%s/%s: %s: No such group",
+			    sep->se_service, sep->se_proto, sep->se_group);
+			goto reject;
+		}
+		if (pwd->pw_uid) {
+			if (sep->se_group)
+				pwd->pw_gid = grp->gr_gid;
+			if (setgid(pwd->pw_gid) < 0) {
+				syslog(LOG_ERR,
+				 "%s/%s: can't set gid %d: %m", sep->se_service,
+				    sep->se_proto, pwd->pw_gid);
+				goto reject;
+			}
+			(void) initgroups(pwd->pw_name,
+			    pwd->pw_gid);
+			if (setuid(pwd->pw_uid) < 0) {
+				syslog(LOG_ERR,
+				 "%s/%s: can't set uid %d: %m", sep->se_service,
+				    sep->se_proto, pwd->pw_uid);
+				goto reject;
+			}
+		} else if (sep->se_group) {
+			(void) setgid((gid_t)grp->gr_gid);
+		}
+		if (debug)
+			fprintf(stderr, "%d execl %s\n",
+			    getpid(), sep->se_server);
+#ifdef MULOG
+		if (sep->se_log)
+			dolog(sep, ctrl);
+#endif
+		/* Set our control descriptor to not close-on-exec... */
+		if (fcntl(ctrl, F_SETFD, 0) < 0)
+			syslog(LOG_ERR, "fcntl (F_SETFD, 0): %m");
+		/* ...and dup it to stdin, stdout, and stderr. */
+		if (ctrl != 0) {
+			dup2(ctrl, 0);
+			close(ctrl);
+			ctrl = 0;
+		}
+		dup2(0, 1);
+		dup2(0, 2);
+#ifdef RLIMIT_NOFILE
+		if (rlim_ofile.rlim_cur != rlim_ofile_cur &&
+		    setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
+			syslog(LOG_ERR, "setrlimit: %m");
+#endif
+		execv(sep->se_server, sep->se_argv);
+		syslog(LOG_ERR, "cannot execute %s: %m", sep->se_server);
+	reject:
+		if (sep->se_socktype != SOCK_STREAM)
+			recv(ctrl, buf, sizeof (buf), 0);
+		_exit(1);
+	}
 }
 
-void
+static void
 reapchild(void)
 {
-	int k, status;
+	int status;
 	pid_t pid;
 	struct servtab *sep;
 
 	for (;;) {
-		pid = wait3(&status, WNOHANG, (struct rusage *)0);
+		pid = wait3(&status, WNOHANG, NULL);
 		if (pid <= 0)
 			break;
 		if (debug)
-			warnx("%d reaped, %s %u", pid,
-			    WIFEXITED(status) ? "status" : "signal",
-			    WIFEXITED(status) ? WEXITSTATUS(status)
-				: WTERMSIG(status));
-		for (sep = servtab; sep; sep = sep->se_next) {
-			for (k = 0; k < sep->se_numchild; k++)
-				if (sep->se_pids[k] == pid)
-					break;
-			if (k == sep->se_numchild)
-				continue;
-			if (sep->se_numchild == sep->se_maxchild)
-				enable(sep);
-			sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
-			if (WIFSIGNALED(status) || WEXITSTATUS(status))
-				syslog(LOG_WARNING,
-				    "%s[%d]: exited, %s %u",
-				    sep->se_server, pid,
-				    WIFEXITED(status) ? "status" : "signal",
-				    WIFEXITED(status) ? WEXITSTATUS(status)
-					: WTERMSIG(status));
-			break;
-		}
-		reapchild_conn(pid);
+			(void) fprintf(stderr, "%d reaped, status %#x\n", 
+			    pid, status);
+		for (sep = servtab; sep != NULL; sep = sep->se_next)
+			if (sep->se_wait == pid) {
+				struct kevent	*ev;
+
+				if (WIFEXITED(status) && WEXITSTATUS(status))
+					syslog(LOG_WARNING,
+					    "%s: exit status 0x%x",
+					    sep->se_server, WEXITSTATUS(status));
+				else if (WIFSIGNALED(status))
+					syslog(LOG_WARNING,
+					    "%s: exit signal 0x%x",
+					    sep->se_server, WTERMSIG(status));
+				sep->se_wait = 1;
+				ev = allocchange();
+				EV_SET(ev, sep->se_fd, EVFILT_READ,
+				    EV_ADD | EV_ENABLE, 0, 0, (intptr_t)sep);
+				if (debug)
+					fprintf(stderr, "restored %s, fd %d\n",
+					    sep->se_service, sep->se_fd);
+			}
 	}
 }
 
-void
-flag_config(int signo __unused)
-{
-	flag_signal('H');
-}
-
-void
+static void
 config(void)
 {
-	struct servtab *sep, *new, **sepp;
-	long omask;
-#ifdef LOGIN_CAP
-	login_cap_t *lc = NULL;
-#endif
-
+	struct servtab *sep, *cp, **sepp;
+	int n;
 
 	if (!setconfig()) {
 		syslog(LOG_ERR, "%s: %m", CONFIG);
 		return;
 	}
-	for (sep = servtab; sep; sep = sep->se_next)
+	for (sep = servtab; sep != NULL; sep = sep->se_next)
 		sep->se_checked = 0;
-	while ((new = getconfigent())) {
-		if (getpwnam(new->se_user) == NULL) {
-			syslog(LOG_ERR,
-				"%s/%s: no such user '%s', service ignored",
-				new->se_service, new->se_proto, new->se_user);
-			continue;
-		}
-		if (new->se_group && getgrnam(new->se_group) == NULL) {
-			syslog(LOG_ERR,
-				"%s/%s: no such group '%s', service ignored",
-				new->se_service, new->se_proto, new->se_group);
-			continue;
-		}
-#ifdef LOGIN_CAP
-		if ((lc = login_getclass(new->se_class)) == NULL) {
-			/* error syslogged by getclass */
-			syslog(LOG_ERR,
-				"%s/%s: %s: login class error, service ignored",
-				new->se_service, new->se_proto, new->se_class);
-			continue;
-		}
-		login_close(lc);
-#endif
-		for (sep = servtab; sep; sep = sep->se_next)
-			if (strcmp(sep->se_service, new->se_service) == 0 &&
-			    strcmp(sep->se_proto, new->se_proto) == 0 &&
-			    sep->se_socktype == new->se_socktype &&
-			    sep->se_family == new->se_family)
+	while ((cp = getconfigent())) {
+		for (sep = servtab; sep != NULL; sep = sep->se_next)
+			if (strcmp(sep->se_service, cp->se_service) == 0 &&
+			    strcmp(sep->se_hostaddr, cp->se_hostaddr) == 0 &&
+			    strcmp(sep->se_proto, cp->se_proto) == 0 &&
+			    ISMUX(sep) == ISMUX(cp))
 				break;
-		if (sep != 0) {
+		if (sep != NULL) {
 			int i;
 
-#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
-			omask = sigblock(SIGBLOCK);
-			if (sep->se_nomapped != new->se_nomapped) {
-				sep->se_nomapped = new->se_nomapped;
-				sep->se_reset = 1;
-			}
-			/* copy over outstanding child pids */
-			if (sep->se_maxchild > 0 && new->se_maxchild > 0) {
-				new->se_numchild = sep->se_numchild;
-				if (new->se_numchild > new->se_maxchild)
-					new->se_numchild = new->se_maxchild;
-				memcpy(new->se_pids, sep->se_pids,
-				    new->se_numchild * sizeof(*new->se_pids));
-			}
-			SWAP(sep->se_pids, new->se_pids);
-			sep->se_maxchild = new->se_maxchild;
-			sep->se_numchild = new->se_numchild;
-			sep->se_maxcpm = new->se_maxcpm;
-			resize_conn(sep, new->se_maxperip);
-			sep->se_maxperip = new->se_maxperip;
-			sep->se_bi = new->se_bi;
-			/* might need to turn on or off service now */
-			if (sep->se_fd >= 0) {
-			      if (sep->se_maxchild > 0
-				  && sep->se_numchild == sep->se_maxchild) {
-				      if (FD_ISSET(sep->se_fd, &allsock))
-					  disable(sep);
-			      } else {
-				      if (!FD_ISSET(sep->se_fd, &allsock))
-					  enable(sep);
-			      }
-			}
-			sep->se_accept = new->se_accept;
-			SWAP(sep->se_user, new->se_user);
-			SWAP(sep->se_group, new->se_group);
-#ifdef LOGIN_CAP
-			SWAP(sep->se_class, new->se_class);
-#endif
-			SWAP(sep->se_server, new->se_server);
-			SWAP(sep->se_server_name, new->se_server_name);
+#define SWAP(type, a, b) {type c = a; a = b; b = c;}
+
+			/*
+			 * sep->se_wait may be holding the pid of a daemon
+			 * that we're waiting for.  If so, don't overwrite
+			 * it unless the config file explicitly says don't
+			 * wait.
+			 */
+			if (cp->se_bi == 0 &&
+			    (sep->se_wait == 1 || cp->se_wait == 0))
+				sep->se_wait = cp->se_wait;
+			SWAP(char *, sep->se_user, cp->se_user);
+			SWAP(char *, sep->se_group, cp->se_group);
+			SWAP(char *, sep->se_server, cp->se_server);
 			for (i = 0; i < MAXARGV; i++)
-				SWAP(sep->se_argv[i], new->se_argv[i]);
+				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
 #ifdef IPSEC
-			SWAP(sep->se_policy, new->se_policy);
-			ipsecsetup(sep);
+			SWAP(char *, sep->se_policy, cp->se_policy);
 #endif
-			sigsetmask(omask);
-			freeconfig(new);
+			SWAP(int, cp->se_type, sep->se_type);
+			SWAP(int, cp->se_max, sep->se_max);
+#undef SWAP
+			if (isrpcservice(sep))
+				unregister_rpc(sep);
+			sep->se_rpcversl = cp->se_rpcversl;
+			sep->se_rpcversh = cp->se_rpcversh;
+			freeconfig(cp);
 			if (debug)
 				print_service("REDO", sep);
 		} else {
-			sep = enter(new);
+			sep = enter(cp);
 			if (debug)
 				print_service("ADD ", sep);
 		}
 		sep->se_checked = 1;
-		if (ISMUX(sep)) {
-			sep->se_fd = -1;
-			continue;
-		}
+
 		switch (sep->se_family) {
-		case AF_INET:
-			if (no_v4bind != 0) {
-				sep->se_fd = -1;
+		case AF_LOCAL:
+			if (sep->se_fd != -1)
+				break;
+			n = strlen(sep->se_service);
+			if (n > sizeof(sep->se_ctrladdr_un.sun_path)) {
+				syslog(LOG_ERR, "%s: address too long",
+				    sep->se_service);
+				sep->se_checked = 0;
 				continue;
 			}
+			(void)unlink(sep->se_service);
+			strncpy(sep->se_ctrladdr_un.sun_path,
+			    sep->se_service, n);
+			sep->se_ctrladdr_un.sun_family = AF_LOCAL;
+			sep->se_ctrladdr_size = n +
+			    sizeof(sep->se_ctrladdr_un) -
+			    sizeof(sep->se_ctrladdr_un.sun_path);
+			if (!ISMUX(sep))
+				setup(sep);
 			break;
+		case AF_INET:
 #ifdef INET6
 		case AF_INET6:
-			if (no_v6bind != 0) {
-				sep->se_fd = -1;
+#endif
+		    {
+			struct addrinfo hints, *res;
+			char *host, *port;
+			int error;
+			int s;
+
+			/* check if the family is supported */
+			s = socket(sep->se_family, SOCK_DGRAM, 0);
+			if (s < 0) {
+				syslog(LOG_WARNING,
+				    "%s/%s: %s: the address family is not "
+				    "supported by the kernel",
+				    sep->se_service, sep->se_proto,
+				    sep->se_hostaddr);
+				sep->se_checked = 0;
 				continue;
 			}
-			break;
-#endif
-		}
-		if (!sep->se_rpc) {
-			if (sep->se_family != AF_UNIX) {
-				sp = getservbyname(sep->se_service, sep->se_proto);
-				if (sp == 0) {
-					syslog(LOG_ERR, "%s/%s: unknown service",
-					sep->se_service, sep->se_proto);
-					sep->se_checked = 0;
-					continue;
+			close(s);
+
+			memset(&hints, 0, sizeof(hints));
+			hints.ai_family = sep->se_family;
+			hints.ai_socktype = sep->se_socktype;
+			hints.ai_flags = AI_PASSIVE;
+			if (!strcmp(sep->se_hostaddr, "*"))
+				host = NULL;
+			else
+				host = sep->se_hostaddr;
+			if (isrpcservice(sep) || ISMUX(sep))
+				port = "0";
+			else
+				port = sep->se_service;
+			error = getaddrinfo(host, port, &hints, &res);
+			if (error) {
+				if (error == EAI_SERVICE) {
+					/* gai_strerror not friendly enough */
+					syslog(LOG_WARNING, "%s/%s: "
+					    "unknown service",
+					    sep->se_service, sep->se_proto);
+				} else {
+					syslog(LOG_ERR, "%s/%s: %s: %s",
+					    sep->se_service, sep->se_proto,
+					    sep->se_hostaddr,
+					    gai_strerror(error));
 				}
+				sep->se_checked = 0;
+				continue;
 			}
-			switch (sep->se_family) {
-			case AF_INET:
-				if (sp->s_port != sep->se_ctrladdr4.sin_port) {
-					sep->se_ctrladdr4.sin_port =
-						sp->s_port;
-					sep->se_reset = 1;
-				}
-				break;
-#ifdef INET6
-			case AF_INET6:
-				if (sp->s_port !=
-				    sep->se_ctrladdr6.sin6_port) {
-					sep->se_ctrladdr6.sin6_port =
-						sp->s_port;
-					sep->se_reset = 1;
-				}
-				break;
-#endif
+			if (res->ai_next) {
+				syslog(LOG_ERR,
+					"%s/%s: %s: resolved to multiple addr",
+				    sep->se_service, sep->se_proto,
+				    sep->se_hostaddr);
+				sep->se_checked = 0;
+				freeaddrinfo(res);
+				continue;
 			}
-			if (sep->se_reset != 0 && sep->se_fd >= 0)
-				close_sep(sep);
-		} else {
-			rpc = getrpcbyname(sep->se_service);
-			if (rpc == 0) {
-				syslog(LOG_ERR, "%s/%s unknown RPC service",
-					sep->se_service, sep->se_proto);
-				if (sep->se_fd != -1)
-					close(sep->se_fd);
+			memcpy(&sep->se_ctrladdr, res->ai_addr,
+				res->ai_addrlen);
+			if (ISMUX(sep)) {
 				sep->se_fd = -1;
-					continue;
+				freeaddrinfo(res);
+				continue;
 			}
-			if (rpc->r_number != sep->se_rpc_prog) {
-				if (sep->se_rpc_prog)
-					unregisterrpc(sep);
-				sep->se_rpc_prog = rpc->r_number;
+			sep->se_ctrladdr_size = res->ai_addrlen;
+			freeaddrinfo(res);
+#ifdef RPC
+			if (isrpcservice(sep)) {
+				struct rpcent *rp;
+
+				sep->se_rpcprog = atoi(sep->se_service);
+				if (sep->se_rpcprog == 0) {
+					rp = getrpcbyname(sep->se_service);
+					if (rp == 0) {
+						syslog(LOG_ERR,
+						    "%s/%s: unknown service",
+						    sep->se_service,
+						    sep->se_proto);
+						sep->se_checked = 0;
+						continue;
+					}
+					sep->se_rpcprog = rp->r_number;
+				}
+				if (sep->se_fd == -1 && !ISMUX(sep))
+					setup(sep);
 				if (sep->se_fd != -1)
-					close(sep->se_fd);
-				sep->se_fd = -1;
+					register_rpc(sep);
+			} else
+#endif
+			{
+				if (sep->se_fd >= 0)
+					close_sep(sep);
+				if (sep->se_fd == -1 && !ISMUX(sep))
+					setup(sep);
 			}
+		    }
 		}
-		if (sep->se_fd == -1)
-			setup(sep);
 	}
 	endconfig();
 	/*
 	 * Purge anything not looked at above.
 	 */
-	omask = sigblock(SIGBLOCK);
 	sepp = &servtab;
 	while ((sep = *sepp)) {
 		if (sep->se_checked) {
@@ -1134,80 +975,92 @@
 		*sepp = sep->se_next;
 		if (sep->se_fd >= 0)
 			close_sep(sep);
+		if (isrpcservice(sep))
+			unregister_rpc(sep);
+		if (sep->se_family == AF_LOCAL)
+			(void)unlink(sep->se_service);
 		if (debug)
 			print_service("FREE", sep);
-		if (sep->se_rpc && sep->se_rpc_prog > 0)
-			unregisterrpc(sep);
 		freeconfig(sep);
 		free(sep);
 	}
-	sigsetmask(omask);
 }
 
-void
-unregisterrpc(struct servtab *sep)
+static void
+retry(void)
 {
-        u_int i;
-        struct servtab *sepp;
-	long omask;
-
-	omask = sigblock(SIGBLOCK);
-        for (sepp = servtab; sepp; sepp = sepp->se_next) {
-                if (sepp == sep)
-                        continue;
-		if (sep->se_checked == 0 ||
-                    !sepp->se_rpc ||
-                    sep->se_rpc_prog != sepp->se_rpc_prog)
-			continue;
-                return;
-        }
-        if (debug)
-                print_service("UNREG", sep);
-        for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
-                pmap_unset(sep->se_rpc_prog, i);
-        if (sep->se_fd != -1)
-                close(sep->se_fd);
-        sep->se_fd = -1;
-	sigsetmask(omask);
-}
+	struct servtab *sep;
 
-void
-flag_retry(int signo __unused)
-{
-	flag_signal('A');
+	timingout = 0;
+	for (sep = servtab; sep != NULL; sep = sep->se_next) {
+		if (sep->se_fd == -1 && !ISMUX(sep)) {
+			switch (sep->se_family) {
+			case AF_LOCAL:
+			case AF_INET:
+#ifdef INET6
+			case AF_INET6:
+#endif
+				setup(sep);
+				if (sep->se_fd != -1 && isrpcservice(sep))
+					register_rpc(sep);
+				break;
+			}
+		}
+	}
 }
 
-void
-retry(void)
+static void
+goaway(void)
 {
 	struct servtab *sep;
 
-	timingout = 0;
-	for (sep = servtab; sep; sep = sep->se_next)
-		if (sep->se_fd == -1 && !ISMUX(sep))
-			setup(sep);
+	for (sep = servtab; sep != NULL; sep = sep->se_next) {
+		if (sep->se_fd == -1)
+			continue;
+
+		switch (sep->se_family) {
+		case AF_LOCAL:
+			(void)unlink(sep->se_service);
+			break;
+		case AF_INET:
+#ifdef INET6
+		case AF_INET6:
+#endif
+			if (sep->se_wait == 1 && isrpcservice(sep))
+				unregister_rpc(sep);
+			break;
+		}
+		(void)close(sep->se_fd);
+	}
+	exit(0);
 }
 
-void
+
+static void
 setup(struct servtab *sep)
 {
-	int on = 1;
+	int		on = 1;
+#ifdef INET6
+	int		off = 0;
+#endif
+	struct kevent	*ev;
 
 	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
 		if (debug)
-			warn("socket failed on %s/%s",
-				sep->se_service, sep->se_proto);
+			fprintf(stderr, "socket failed on %s/%s: %s\n", 
+			    sep->se_service, sep->se_proto, strerror(errno));
 		syslog(LOG_ERR, "%s/%s: socket: %m",
 		    sep->se_service, sep->se_proto);
 		return;
 	}
 	/* Set all listening sockets to close-on-exec. */
 	if (fcntl(sep->se_fd, F_SETFD, FD_CLOEXEC) < 0) {
-		syslog(LOG_ERR, "%s/%s: fcntl (F_SETFD, FD_CLOEXEC): %m",
+		syslog(LOG_ERR, "%s/%s: fcntl(F_SETFD, FD_CLOEXEC): %m",
 		    sep->se_service, sep->se_proto);
 		close(sep->se_fd);
 		return;
 	}
+
 #define	turnon(fd, opt) \
 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
@@ -1215,309 +1068,180 @@
 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
-#ifdef SO_PRIVSTATE
-	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
-		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
-#endif
-	/* tftpd opens a new connection then needs more infos */
-	if ((sep->se_family == AF_INET6) &&
-	    (strcmp(sep->se_proto, "udp") == 0) &&
-	    (sep->se_accept == 0) &&
-	    (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_PKTINFO,
-			(char *)&on, sizeof (on)) < 0))
-		syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m");
-	if (sep->se_family == AF_INET6) {
-		int flag = sep->se_nomapped ? 1 : 0;
-		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY,
-			       (char *)&flag, sizeof (flag)) < 0)
-			syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m");
-	}
 #undef turnon
-	if (sep->se_type == TTCP_TYPE)
-		if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH,
-		    (char *)&on, sizeof (on)) < 0)
-			syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m");
-#ifdef IPV6_FAITH
-	if (sep->se_type == FAITH_TYPE) {
-		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on,
-				sizeof(on)) < 0) {
+
+	/* Set the socket buffer sizes, if specified. */
+	if (sep->se_sndbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
+	    SO_SNDBUF, (char *)&sep->se_sndbuf, sizeof(sep->se_sndbuf)) < 0)
+		syslog(LOG_ERR, "setsockopt (SO_SNDBUF %d): %m",
+		    sep->se_sndbuf);
+	if (sep->se_rcvbuf != 0 && setsockopt(sep->se_fd, SOL_SOCKET,
+	    SO_RCVBUF, (char *)&sep->se_rcvbuf, sizeof(sep->se_rcvbuf)) < 0)
+		syslog(LOG_ERR, "setsockopt (SO_RCVBUF %d): %m",
+		    sep->se_rcvbuf);
+#ifdef INET6
+	if (sep->se_family == AF_INET6) {
+		int *v;
+		v = (sep->se_type == FAITH_TYPE) ? &on : &off;
+		if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH,
+		    (char *)v, sizeof(*v)) < 0)
 			syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
-		}
 	}
 #endif
 #ifdef IPSEC
-	ipsecsetup(sep);
-#endif
-	if (sep->se_family == AF_UNIX) {
-		unlink(sep->se_ctrladdr_un.sun_path);
-		umask(0777); /* Make socket with conservative permissions */
+	if (ipsecsetup(sep->se_family, sep->se_fd, sep->se_policy) < 0 &&
+	    sep->se_policy) {
+		syslog(LOG_ERR, "%s/%s: ipsec setup failed",
+		    sep->se_service, sep->se_proto);
+		(void)close(sep->se_fd);
+		sep->se_fd = -1;
+		return;
 	}
-	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
-	    sep->se_ctrladdr_size) < 0) {
+#endif
+
+	if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
 		if (debug)
-			warn("bind failed on %s/%s",
-				sep->se_service, sep->se_proto);
+			fprintf(stderr, "bind failed on %s/%s: %s\n",
+			    sep->se_service, sep->se_proto, strerror(errno));
 		syslog(LOG_ERR, "%s/%s: bind: %m",
 		    sep->se_service, sep->se_proto);
-		close(sep->se_fd);
+		(void) close(sep->se_fd);
 		sep->se_fd = -1;
 		if (!timingout) {
 			timingout = 1;
 			alarm(RETRYTIME);
 		}
-		if (sep->se_family == AF_UNIX)
-			umask(mask);
 		return;
 	}
-	if (sep->se_family == AF_UNIX) {
-		/* Ick - fch{own,mod} don't work on Unix domain sockets */
-		if (chown(sep->se_service, sep->se_sockuid, sep->se_sockgid) < 0)
-			syslog(LOG_ERR, "chown socket: %m");
-		if (chmod(sep->se_service, sep->se_sockmode) < 0)
-			syslog(LOG_ERR, "chmod socket: %m");
-		umask(mask);
-	}
-        if (sep->se_rpc) {
-		u_int i;
-		socklen_t len = sep->se_ctrladdr_size;
-
-		if (sep->se_family != AF_INET) {
-                        syslog(LOG_ERR,
-			       "%s/%s: unsupported address family for rpc",
-                               sep->se_service, sep->se_proto);
-                        close(sep->se_fd);
-                        sep->se_fd = -1;
-                        return;
-		}
-                if (getsockname(sep->se_fd,
-				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
-                        syslog(LOG_ERR, "%s/%s: getsockname: %m",
-                               sep->se_service, sep->se_proto);
-                        close(sep->se_fd);
-                        sep->se_fd = -1;
-                        return;
-                }
-                if (debug)
-                        print_service("REG ", sep);
-                for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
-                        pmap_unset(sep->se_rpc_prog, i);
-                        pmap_set(sep->se_rpc_prog, i,
-                                 (sep->se_socktype == SOCK_DGRAM)
-                                 ? IPPROTO_UDP : IPPROTO_TCP,
-				 ntohs(sep->se_ctrladdr4.sin_port));
-                }
-        }
 	if (sep->se_socktype == SOCK_STREAM)
-		listen(sep->se_fd, 64);
-	enable(sep);
-	if (debug) {
-		warnx("registered %s on %d",
-			sep->se_server, sep->se_fd);
-	}
-}
-
-#ifdef IPSEC
-void
-ipsecsetup(struct servtab *sep)
-{
-	char *buf;
-	char *policy_in = NULL;
-	char *policy_out = NULL;
-	int level;
-	int opt;
-
-	switch (sep->se_family) {
-	case AF_INET:
-		level = IPPROTO_IP;
-		opt = IP_IPSEC_POLICY;
-		break;
-#ifdef INET6
-	case AF_INET6:
-		level = IPPROTO_IPV6;
-		opt = IPV6_IPSEC_POLICY;
-		break;
-#endif
-	default:
-		return;
-	}
+		listen(sep->se_fd, 10);
 
-	if (!sep->se_policy || sep->se_policy[0] == '\0') {
-		static char def_in[] = "in entrust", def_out[] = "out entrust";
-		policy_in = def_in;
-		policy_out = def_out;
-	} else {
-		if (!strncmp("in", sep->se_policy, 2))
-			policy_in = sep->se_policy;
-		else if (!strncmp("out", sep->se_policy, 3))
-			policy_out = sep->se_policy;
-		else {
-			syslog(LOG_ERR, "invalid security policy \"%s\"",
-				sep->se_policy);
-			return;
-		}
-	}
-
-	if (policy_in != NULL) {
-		buf = ipsec_set_policy(policy_in, strlen(policy_in));
-		if (buf != NULL) {
-			if (setsockopt(sep->se_fd, level, opt,
-					buf, ipsec_get_policylen(buf)) < 0 &&
-			    debug != 0)
-				warnx("%s/%s: ipsec initialization failed; %s",
-				      sep->se_service, sep->se_proto,
-				      policy_in);
-			free(buf);
-		} else
-			syslog(LOG_ERR, "invalid security policy \"%s\"",
-				policy_in);
-	}
-	if (policy_out != NULL) {
-		buf = ipsec_set_policy(policy_out, strlen(policy_out));
-		if (buf != NULL) {
-			if (setsockopt(sep->se_fd, level, opt,
-					buf, ipsec_get_policylen(buf)) < 0 &&
-			    debug != 0)
-				warnx("%s/%s: ipsec initialization failed; %s",
-				      sep->se_service, sep->se_proto,
-				      policy_out);
-			free(buf);
-		} else
-			syslog(LOG_ERR, "invalid security policy \"%s\"",
-				policy_out);
+	ev = allocchange();
+	EV_SET(ev, sep->se_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0,
+	    (intptr_t)sep);
+	if (sep->se_fd > maxsock) {
+		maxsock = sep->se_fd;
+		if (maxsock > rlim_ofile_cur - FD_MARGIN)
+			bump_nofile();
 	}
+	if (debug)
+		fprintf(stderr, "registered %s on %d\n",
+		    sep->se_server, sep->se_fd);
 }
-#endif
 
 /*
  * Finish with a service and its socket.
  */
-void
+static void
 close_sep(struct servtab *sep)
 {
 	if (sep->se_fd >= 0) {
-		if (FD_ISSET(sep->se_fd, &allsock))
-			disable(sep);
-		close(sep->se_fd);
+		(void) close(sep->se_fd);
 		sep->se_fd = -1;
 	}
 	sep->se_count = 0;
-	sep->se_numchild = 0;	/* forget about any existing children */
 }
 
-int
-matchservent(const char *name1, const char *name2, const char *proto)
+static void
+register_rpc(struct servtab *sep)
+{
+#ifdef RPC
+	socklen_t n;
+	struct netbuf nbuf;
+	struct sockaddr_storage ss;
+	struct netconfig *nconf;
+
+	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
+		syslog(LOG_ERR, "%s: getnetconfigent failed",
+		    sep->se_proto);
+		return;
+	}
+	n = sizeof ss;
+	if (getsockname(sep->se_fd, (struct sockaddr *)&ss, &n) < 0) {
+		syslog(LOG_ERR, "%s/%s: getsockname: %m",
+		    sep->se_service, sep->se_proto);
+		return;
+	}
+
+	nbuf.buf = &ss;
+	nbuf.len = ss.ss_len;
+	nbuf.maxlen = sizeof (struct sockaddr_storage);
+	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
+		if (debug)
+			fprintf(stderr, "rpcb_set: %u %d %s %s\n",
+			    sep->se_rpcprog, n, nconf->nc_netid,
+			    taddr2uaddr(nconf, &nbuf));
+		(void)rpcb_unset(sep->se_rpcprog, n, nconf);
+		if (!rpcb_set(sep->se_rpcprog, n, nconf, &nbuf))
+			syslog(LOG_ERR, "rpcb_set: %u %d %s %s%s",
+			    sep->se_rpcprog, n, nconf->nc_netid,
+			    taddr2uaddr(nconf, &nbuf), clnt_spcreateerror(""));
+	}
+#endif /* RPC */
+}
+
+static void
+unregister_rpc(struct servtab *sep)
 {
-	char **alias, *p;
-	struct servent *se;
+#ifdef RPC
+	int n;
+	struct netconfig *nconf;
+
+	if ((nconf = getnetconfigent(sep->se_proto+4)) == NULL) {
+		syslog(LOG_ERR, "%s: getnetconfigent failed",
+		    sep->se_proto);
+		return;
+	}
 
-	if (strcmp(proto, "unix") == 0) {
-		if ((p = strrchr(name1, '/')) != NULL)
-			name1 = p + 1;
-		if ((p = strrchr(name2, '/')) != NULL)
-			name2 = p + 1;
-	}
-	if (strcmp(name1, name2) == 0)
-		return(1);
-	if ((se = getservbyname(name1, proto)) != NULL) {
-		if (strcmp(name2, se->s_name) == 0)
-			return(1);
-		for (alias = se->s_aliases; *alias; alias++)
-			if (strcmp(name2, *alias) == 0)
-				return(1);
+	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
+		if (debug)
+			fprintf(stderr, "rpcb_unset(%u, %d, %s)\n",
+			    sep->se_rpcprog, n, nconf->nc_netid);
+		if (!rpcb_unset(sep->se_rpcprog, n, nconf))
+			syslog(LOG_ERR, "rpcb_unset(%u, %d, %s) failed\n",
+			    sep->se_rpcprog, n, nconf->nc_netid);
 	}
-	return(0);
+#endif /* RPC */
 }
 
-struct servtab *
+
+static struct servtab *
 enter(struct servtab *cp)
 {
 	struct servtab *sep;
-	long omask;
 
 	sep = (struct servtab *)malloc(sizeof (*sep));
-	if (sep == (struct servtab *)0) {
-		syslog(LOG_ERR, "malloc: %m");
-		exit(EX_OSERR);
+	if (sep == NULL) {
+		syslog(LOG_ERR, "Out of memory.");
+		exit(1);
 	}
 	*sep = *cp;
 	sep->se_fd = -1;
-	omask = sigblock(SIGBLOCK);
+	sep->se_rpcprog = -1;
 	sep->se_next = servtab;
 	servtab = sep;
-	sigsetmask(omask);
 	return (sep);
 }
 
-void
-enable(struct servtab *sep)
-{
-	if (debug)
-		warnx(
-		    "enabling %s, fd %d", sep->se_service, sep->se_fd);
-#ifdef SANITY_CHECK
-	if (sep->se_fd < 0) {
-		syslog(LOG_ERR,
-		    "%s: %s: bad fd", __func__, sep->se_service);
-		exit(EX_SOFTWARE);
-	}
-	if (ISMUX(sep)) {
-		syslog(LOG_ERR,
-		    "%s: %s: is mux", __func__, sep->se_service);
-		exit(EX_SOFTWARE);
-	}
-	if (FD_ISSET(sep->se_fd, &allsock)) {
-		syslog(LOG_ERR,
-		    "%s: %s: not off", __func__, sep->se_service);
-		exit(EX_SOFTWARE);
-	}
-	nsock++;
-#endif
-	FD_SET(sep->se_fd, &allsock);
-	if (sep->se_fd > maxsock)
-		maxsock = sep->se_fd;
-}
-
-void
-disable(struct servtab *sep)
-{
-	if (debug)
-		warnx(
-		    "disabling %s, fd %d", sep->se_service, sep->se_fd);
-#ifdef SANITY_CHECK
-	if (sep->se_fd < 0) {
-		syslog(LOG_ERR,
-		    "%s: %s: bad fd", __func__, sep->se_service);
-		exit(EX_SOFTWARE);
-	}
-	if (ISMUX(sep)) {
-		syslog(LOG_ERR,
-		    "%s: %s: is mux", __func__, sep->se_service);
-		exit(EX_SOFTWARE);
-	}
-	if (!FD_ISSET(sep->se_fd, &allsock)) {
-		syslog(LOG_ERR,
-		    "%s: %s: not on", __func__, sep->se_service);
-		exit(EX_SOFTWARE);
-	}
-	if (nsock == 0) {
-		syslog(LOG_ERR, "%s: nsock=0", __func__);
-		exit(EX_SOFTWARE);
-	}
-	nsock--;
-#endif
-	FD_CLR(sep->se_fd, &allsock);
-	if (sep->se_fd == maxsock)
-		maxsock--;
-}
-
 FILE	*fconfig = NULL;
 struct	servtab serv;
 char	line[LINE_MAX];
+char    *defhost;
+#ifdef IPSEC
+static char *policy = NULL;
+#endif
 
-int
+static int
 setconfig(void)
 {
-
+	if (defhost)
+		free(defhost);
+	defhost = newstr("*");
+#ifdef IPSEC
+	if (policy)
+		free(policy);
+	policy = NULL;
+#endif
 	if (fconfig != NULL) {
 		fseek(fconfig, 0L, SEEK_SET);
 		return (1);
@@ -1526,109 +1250,122 @@
 	return (fconfig != NULL);
 }
 
-void
+static void
 endconfig(void)
 {
-	if (fconfig) {
-		fclose(fconfig);
+	if (fconfig != NULL) {
+		(void) fclose(fconfig);
 		fconfig = NULL;
 	}
+	if (defhost != NULL) {
+		free(defhost);
+		defhost = NULL;
+	}
 }
 
-struct servtab *
+static struct servtab *
 getconfigent(void)
 {
 	struct servtab *sep = &serv;
-	int argc;
-	char *cp, *arg, *s;
-	char *versp;
+	int argc, val;
+	char *cp, *cp0, *arg, *buf0, *buf1, *sz0, *sz1;
 	static char TCPMUX_TOKEN[] = "tcpmux/";
 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
-#ifdef IPSEC
-	char *policy = NULL;
-#endif
-	int v4bind = 0;
-#ifdef INET6
-	int v6bind = 0;
-#endif
-	int i;
+	char *hostdelim;
 
 more:
-	while ((cp = nextline(fconfig)) != NULL) {
+	while ((cp = nextline(fconfig))) {
 #ifdef IPSEC
 		/* lines starting with #@ is not a comment, but the policy */
 		if (cp[0] == '#' && cp[1] == '@') {
 			char *p;
-			for (p = cp + 2; p && *p && isspace(*p); p++)
+			for (p = cp + 2; p && *p && isspace((unsigned char)*p); p++)
 				;
 			if (*p == '\0') {
 				if (policy)
 					free(policy);
 				policy = NULL;
-			} else if (ipsec_get_policylen(p) >= 0) {
-				if (policy)
-					free(policy);
-				policy = newstr(p);
 			} else {
-				syslog(LOG_ERR,
-					"%s: invalid ipsec policy \"%s\"",
-					CONFIG, p);
-				exit(EX_CONFIG);
+				if (ipsecsetup_test(p) < 0) {
+					syslog(LOG_ERR,
+						"%s: invalid ipsec policy \"%s\"",
+						CONFIG, p);
+					exit(1);
+				} else {
+					if (policy)
+						free(policy);
+					policy = newstr(p);
+				}
 			}
 		}
 #endif
 		if (*cp == '#' || *cp == '\0')
 			continue;
+#ifdef MULOG
+		/* Avoid use of `skip' if there is a danger of it looking
+		 * at continuation lines.
+		 */
+		do {
+			cp++;
+		} while (*cp == ' ' || *cp == '\t');
+		if (*cp == '\0')
+			continue;
+		if ((arg = skip(&cp)) == NULL)
+			continue;
+		if (strcmp(arg, "DOMAIN"))
+			continue;
+		if (curdom)
+			free(curdom);
+		curdom = NULL;
+		while (*cp == ' ' || *cp == '\t')
+			cp++;
+		if (*cp == '\0')
+			continue;
+		arg = cp;
+		while (*cp && *cp != ' ' && *cp != '\t')
+			cp++;
+		if (*cp != '\0')
+			*cp++ = '\0';
+		curdom = newstr(arg);
+#endif
 		break;
 	}
 	if (cp == NULL)
-		return ((struct servtab *)0);
+		return (NULL);
 	/*
 	 * clear the static buffer, since some fields (se_ctrladdr,
 	 * for example) don't get initialized here.
 	 */
-	memset(sep, 0, sizeof *sep);
+	memset((caddr_t)sep, 0, sizeof *sep);
 	arg = skip(&cp);
 	if (cp == NULL) {
 		/* got an empty line containing just blanks/tabs. */
 		goto more;
 	}
-	if (arg[0] == ':') { /* :user:group:perm: */
-		char *user, *group, *perm;
-		struct passwd *pw;
-		struct group *gr;
-		user = arg+1;
-		if ((group = strchr(user, ':')) == NULL) {
-			syslog(LOG_ERR, "no group after user '%s'", user);
-			goto more;
-		}
-		*group++ = '\0';
-		if ((perm = strchr(group, ':')) == NULL) {
-			syslog(LOG_ERR, "no mode after group '%s'", group);
-			goto more;
-		}
-		*perm++ = '\0';
-		if ((pw = getpwnam(user)) == NULL) {
-			syslog(LOG_ERR, "no such user '%s'", user);
-			goto more;
-		}
-		sep->se_sockuid = pw->pw_uid;
-		if ((gr = getgrnam(group)) == NULL) {
-			syslog(LOG_ERR, "no such user '%s'", group);
-			goto more;
-		}
-		sep->se_sockgid = gr->gr_gid;
-		sep->se_sockmode = strtol(perm, &arg, 8);
-		if (*arg != ':') {
-			syslog(LOG_ERR, "bad mode '%s'", perm);
-			goto more;
+	/* Check for a host name. */
+	hostdelim = strrchr(arg, ':');
+	if (hostdelim) {
+		*hostdelim = '\0';
+		if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
+			hostdelim[-1] = '\0';
+			sep->se_hostaddr = newstr(arg + 1);
+		} else
+			sep->se_hostaddr = newstr(arg);
+		arg = hostdelim + 1;
+		/*
+		 * If the line is of the form `host:', then just change the
+		 * default host for the following lines.
+		 */
+		if (*arg == '\0') {
+			arg = skip(&cp);
+			if (cp == NULL) {
+				free(defhost);
+				defhost = sep->se_hostaddr;
+				goto more;
+			}
 		}
-		*arg++ = '\0';
-	} else {
-		sep->se_sockuid = euid;
-		sep->se_sockgid = egid;
-		sep->se_sockmode = 0200;
-	}
+	} else
+		sep->se_hostaddr = newstr(defhost);
 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
 		char *c = arg + MUX_LEN;
 		if (*c == '+') {
@@ -1641,6 +1378,7 @@
 		sep->se_service = newstr(arg);
 		sep->se_type = NORM_TYPE;
 	}
+
 	arg = sskip(&cp);
 	if (strcmp(arg, "stream") == 0)
 		sep->se_socktype = SOCK_STREAM;
@@ -1656,286 +1394,278 @@
 		sep->se_socktype = -1;
 
 	arg = sskip(&cp);
-	if (strncmp(arg, "tcp", 3) == 0) {
-		sep->se_proto = newstr(strsep(&arg, "/"));
-		if (arg != NULL) {
-			if (strcmp(arg, "ttcp") == 0)
-				sep->se_type = TTCP_TYPE;
-			else if (strcmp(arg, "faith") == 0)
-				sep->se_type = FAITH_TYPE;
-		}
-	} else {
-		if (sep->se_type == NORM_TYPE &&
-		    strncmp(arg, "faith/", 6) == 0) {
-			arg += 6;
-			sep->se_type = FAITH_TYPE;
-		}
-		sep->se_proto = newstr(arg);
-	}
-        if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
-		if (no_v4bind != 0) {
-			syslog(LOG_NOTICE, "IPv4 bind is ignored for %s",
-			       sep->se_service);
-			freeconfig(sep);
+	if (sep->se_type == NORM_TYPE &&
+	    strncmp(arg, "faith/", strlen("faith/")) == 0) {
+		arg += strlen("faith/");
+		sep->se_type = FAITH_TYPE;
+	}
+	sep->se_proto = newstr(arg);
+
+#define	MALFORMED(arg) \
+do { \
+	syslog(LOG_ERR, "%s: malformed buffer size option `%s'", \
+	    sep->se_service, (arg)); \
+	goto more; \
+} while (0)
+
+#define	GETVAL(arg) \
+do { \
+	if (!isdigit((unsigned char)*(arg))) \
+		MALFORMED(arg); \
+	val = strtol((arg), &cp0, 10); \
+	if (cp0 != NULL) { \
+		if (cp0[1] != '\0') \
+			MALFORMED((arg)); \
+		if (cp0[0] == 'k') \
+			val *= 1024; \
+		if (cp0[0] == 'm') \
+			val *= 1024 * 1024; \
+	} \
+	if (val < 1) { \
+		syslog(LOG_ERR, "%s: invalid buffer size `%s'", \
+		    sep->se_service, (arg)); \
+		goto more; \
+	} \
+} while (0)
+
+#define	ASSIGN(arg) \
+do { \
+	if (strcmp((arg), "sndbuf") == 0) \
+		sep->se_sndbuf = val; \
+	else if (strcmp((arg), "rcvbuf") == 0) \
+		sep->se_rcvbuf = val; \
+	else \
+		MALFORMED((arg)); \
+} while (0)
+
+	/*
+	 * Extract the send and receive buffer sizes before parsing
+	 * the protocol.
+	 */
+	sep->se_sndbuf = sep->se_rcvbuf = 0;
+	buf0 = buf1 = sz0 = sz1 = NULL;
+	if ((buf0 = strchr(sep->se_proto, ',')) != NULL) {
+		/* Not meaningful for Tcpmux services. */
+		if (ISMUX(sep)) {
+			syslog(LOG_ERR, "%s: can't specify buffer sizes for "
+			    "tcpmux services", sep->se_service);
 			goto more;
 		}
-                memmove(sep->se_proto, sep->se_proto + 4,
-                    strlen(sep->se_proto) + 1 - 4);
-                sep->se_rpc = 1;
-                sep->se_rpc_prog = sep->se_rpc_lowvers =
-			sep->se_rpc_lowvers = 0;
-		memcpy(&sep->se_ctrladdr4, bind_sa4,
-		       sizeof(sep->se_ctrladdr4));
-                if ((versp = strrchr(sep->se_service, '/'))) {
-                        *versp++ = '\0';
-                        switch (sscanf(versp, "%u-%u",
-                                       &sep->se_rpc_lowvers,
-                                       &sep->se_rpc_highvers)) {
-                        case 2:
-                                break;
-                        case 1:
-                                sep->se_rpc_highvers =
-                                        sep->se_rpc_lowvers;
-                                break;
-                        default:
-                                syslog(LOG_ERR,
-					"bad RPC version specifier; %s",
-					sep->se_service);
-                                freeconfig(sep);
-                                goto more;
-                        }
-                }
-                else {
-                        sep->se_rpc_lowvers =
-                                sep->se_rpc_highvers = 1;
-                }
-        }
-	sep->se_nomapped = 0;
-	while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) {
-#ifdef INET6
-		if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') {
-			if (no_v6bind != 0) {
-				syslog(LOG_NOTICE, "IPv6 bind is ignored for %s",
-				       sep->se_service);
-				freeconfig(sep);
+
+		/* Skip the , */
+		*buf0++ = '\0';
+
+		/* Check to see if another socket buffer size was specified. */
+		if ((buf1 = strchr(buf0, ',')) != NULL) {
+			/* Skip the , */
+			*buf1++ = '\0';
+
+			/* Make sure a 3rd one wasn't specified. */
+			if (strchr(buf1, ',') != NULL) {
+				syslog(LOG_ERR, "%s: too many buffer sizes",
+				    sep->se_service);
 				goto more;
 			}
-			sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
-			v6bind = 1;
-			continue;
+
+			/* Locate the size. */
+			if ((sz1 = strchr(buf1, '=')) == NULL)
+				MALFORMED(buf1);
+
+			/* Skip the = */
+			*sz1++ = '\0';
 		}
-#endif
-		if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') {
-			sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
-			v4bind = 1;
-			continue;
+
+		/* Locate the size. */
+		if ((sz0 = strchr(buf0, '=')) == NULL)
+			MALFORMED(buf0);
+
+		/* Skip the = */
+		*sz0++ = '\0';
+
+		GETVAL(sz0);
+		ASSIGN(buf0);
+
+		if (buf1 != NULL) {
+			GETVAL(sz1);
+			ASSIGN(buf1);
 		}
-		/* illegal version num */
-		syslog(LOG_ERR,	"bad IP version for %s", sep->se_proto);
-		freeconfig(sep);
-		goto more;
 	}
+
+#undef ASSIGN
+#undef GETVAL
+#undef MALFORMED
+
 	if (strcmp(sep->se_proto, "unix") == 0) {
-	        sep->se_family = AF_UNIX;
-	} else
-#ifdef INET6
-	if (v6bind != 0) {
-		sep->se_family = AF_INET6;
-		if (v4bind == 0 || no_v4bind != 0)
-			sep->se_nomapped = 1;
-	} else
-#endif
-	{ /* default to v4 bind if not v6 bind */
-		if (no_v4bind != 0) {
-			syslog(LOG_NOTICE, "IPv4 bind is ignored for %s",
-			       sep->se_service);
-			freeconfig(sep);
+		sep->se_family = AF_LOCAL;
+	} else {
+		val = strlen(sep->se_proto);
+		if (!val) {
+			syslog(LOG_ERR, "%s: invalid protocol specified",
+			    sep->se_service);
 			goto more;
 		}
-		sep->se_family = AF_INET;
-	}
-	/* init ctladdr */
-	switch(sep->se_family) {
-	case AF_INET:
-		memcpy(&sep->se_ctrladdr4, bind_sa4,
-		       sizeof(sep->se_ctrladdr4));
-		sep->se_ctrladdr_size =	sizeof(sep->se_ctrladdr4);
-		break;
+		val = sep->se_proto[val - 1];
+		switch (val) {
+		case '4':	/*tcp4 or udp4*/
+			sep->se_family = AF_INET;
+			break;
 #ifdef INET6
-	case AF_INET6:
-		memcpy(&sep->se_ctrladdr6, bind_sa6,
-		       sizeof(sep->se_ctrladdr6));
-		sep->se_ctrladdr_size =	sizeof(sep->se_ctrladdr6);
-		break;
+		case '6':	/*tcp6 or udp6*/
+			sep->se_family = AF_INET6;
+			break;
 #endif
-	case AF_UNIX:
-		if (strlen(sep->se_service) >= sizeof(sep->se_ctrladdr_un.sun_path)) {
-			syslog(LOG_ERR, 
-			    "domain socket pathname too long for service %s",
+		default:
+			sep->se_family = AF_INET;	/*will become AF_INET6*/
+			break;
+		}
+		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
+#ifdef RPC
+			char *cp, *ccp;
+			cp = strchr(sep->se_service, '/');
+			if (cp == 0) {
+				syslog(LOG_ERR, "%s: no rpc version",
+				    sep->se_service);
+				goto more;
+			}
+			*cp++ = '\0';
+			sep->se_rpcversl = sep->se_rpcversh =
+			    strtol(cp, &ccp, 0);
+			if (ccp == cp) {
+		badafterall:
+				syslog(LOG_ERR, "%s/%s: bad rpc version",
+				    sep->se_service, cp);
+				goto more;
+			}
+			if (*ccp == '-') {
+				cp = ccp + 1;
+				sep->se_rpcversh = strtol(cp, &ccp, 0);
+				if (ccp == cp)
+					goto badafterall;
+			}
+#else
+			syslog(LOG_ERR, "%s: rpc services not suported",
 			    sep->se_service);
 			goto more;
+#endif /* RPC */
 		}
-		memset(&sep->se_ctrladdr, 0, sizeof(sep->se_ctrladdr));
-		sep->se_ctrladdr_un.sun_family = sep->se_family;
-		sep->se_ctrladdr_un.sun_len = strlen(sep->se_service);
-		strcpy(sep->se_ctrladdr_un.sun_path, sep->se_service);
-		sep->se_ctrladdr_size = SUN_LEN(&sep->se_ctrladdr_un);
 	}
 	arg = sskip(&cp);
-	if (!strncmp(arg, "wait", 4))
-		sep->se_accept = 0;
-	else if (!strncmp(arg, "nowait", 6))
-		sep->se_accept = 1;
-	else {
-		syslog(LOG_ERR,
-			"%s: bad wait/nowait for service %s",
-			CONFIG, sep->se_service);
-		goto more;
-	}
-	sep->se_maxchild = -1;
-	sep->se_maxcpm = -1;
-	sep->se_maxperip = -1;
-	if ((s = strchr(arg, '/')) != NULL) {
-		char *eptr;
-		u_long val;
-
-		val = strtoul(s + 1, &eptr, 10);
-		if (eptr == s + 1 || val > MAX_MAXCHLD) {
-			syslog(LOG_ERR,
-				"%s: bad max-child for service %s",
-				CONFIG, sep->se_service);
-			goto more;
-		}
-		if (debug)
-			if (!sep->se_accept && val != 1)
-				warnx("maxchild=%lu for wait service %s"
-				    " not recommended", val, sep->se_service);
-		sep->se_maxchild = val;
-		if (*eptr == '/')
-			sep->se_maxcpm = strtol(eptr + 1, &eptr, 10);
-		if (*eptr == '/')
-			sep->se_maxperip = strtol(eptr + 1, &eptr, 10);
-		/*
-		 * explicitly do not check for \0 for future expansion /
-		 * backwards compatibility
-		 */
+	{
+		char *cp;
+		if ((cp = strchr(arg, ':')) == NULL)
+			cp = strchr(arg, '.');
+		if (cp != NULL) {
+			*cp++ = '\0';
+			sep->se_max = atoi(cp);
+		} else
+			sep->se_max = TOOMANY;
 	}
+	sep->se_wait = strcmp(arg, "wait") == 0;
 	if (ISMUX(sep)) {
 		/*
-		 * Silently enforce "nowait" mode for TCPMUX services
-		 * since they don't have an assigned port to listen on.
+		 * Silently enforce "nowait" for TCPMUX services since
+		 * they don't have an assigned port to listen on.
 		 */
-		sep->se_accept = 1;
-		if (strcmp(sep->se_proto, "tcp")) {
-			syslog(LOG_ERR,
-				"%s: bad protocol for tcpmux service %s",
-				CONFIG, sep->se_service);
+		sep->se_wait = 0;
+
+		if (strncmp(sep->se_proto, "tcp", 3)) {
+			syslog(LOG_ERR, 
+			    "%s: bad protocol for tcpmux service %s",
+			    CONFIG, sep->se_service);
 			goto more;
 		}
 		if (sep->se_socktype != SOCK_STREAM) {
-			syslog(LOG_ERR,
-				"%s: bad socket type for tcpmux service %s",
-				CONFIG, sep->se_service);
+			syslog(LOG_ERR, 
+			    "%s: bad socket type for tcpmux service %s",
+			    CONFIG, sep->se_service);
 			goto more;
 		}
 	}
 	sep->se_user = newstr(sskip(&cp));
-#ifdef LOGIN_CAP
-	if ((s = strrchr(sep->se_user, '/')) != NULL) {
-		*s = '\0';
-		sep->se_class = newstr(s + 1);
-	} else
-		sep->se_class = newstr(RESOURCE_RC);
-#endif
-	if ((s = strrchr(sep->se_user, ':')) != NULL) {
-		*s = '\0';
-		sep->se_group = newstr(s + 1);
-	} else
-		sep->se_group = NULL;
+	if ((sep->se_group = strchr(sep->se_user, ':')) != NULL)
+		*sep->se_group++ = '\0';
+	else if ((sep->se_group = strchr(sep->se_user, '.')) != NULL)
+		*sep->se_group++ = '\0';
+
 	sep->se_server = newstr(sskip(&cp));
-	if ((sep->se_server_name = strrchr(sep->se_server, '/')))
-		sep->se_server_name++;
 	if (strcmp(sep->se_server, "internal") == 0) {
 		struct biltin *bi;
 
 		for (bi = biltins; bi->bi_service; bi++)
 			if (bi->bi_socktype == sep->se_socktype &&
-			    matchservent(bi->bi_service, sep->se_service,
-			    sep->se_proto))
+			    strcmp(bi->bi_service, sep->se_service) == 0)
 				break;
 		if (bi->bi_service == 0) {
 			syslog(LOG_ERR, "internal service %s unknown",
-				sep->se_service);
+			    sep->se_service);
 			goto more;
 		}
-		sep->se_accept = 1;	/* force accept mode for built-ins */
 		sep->se_bi = bi;
+		sep->se_wait = bi->bi_wait;
 	} else
 		sep->se_bi = NULL;
-	if (sep->se_maxperip < 0)
-		sep->se_maxperip = maxperip;
-	if (sep->se_maxcpm < 0)
-		sep->se_maxcpm = maxcpm;
-	if (sep->se_maxchild < 0) {	/* apply default max-children */
-		if (sep->se_bi && sep->se_bi->bi_maxchild >= 0)
-			sep->se_maxchild = sep->se_bi->bi_maxchild;
-		else if (sep->se_accept) 
-			sep->se_maxchild = maxchild > 0 ? maxchild : 0;
-		else
-			sep->se_maxchild = 1;
-	}
-	if (sep->se_maxchild > 0) {
-		sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
-		if (sep->se_pids == NULL) {
-			syslog(LOG_ERR, "malloc: %m");
-			exit(EX_OSERR);
-		}
-	}
 	argc = 0;
-	for (arg = skip(&cp); cp; arg = skip(&cp))
-		if (argc < MAXARGV) {
-			sep->se_argv[argc++] = newstr(arg);
-		} else {
-			syslog(LOG_ERR,
-				"%s: too many arguments for service %s",
-				CONFIG, sep->se_service);
-			goto more;
+	for (arg = skip(&cp); cp; arg = skip(&cp)) {
+#if MULOG
+		char *colon;
+
+		if (argc == 0 && (colon = strrchr(arg, ':'))) {
+			while (arg < colon) {
+				int	x;
+				char	*ccp;
+
+				switch (*arg++) {
+				case 'l':
+					x = 1;
+					if (isdigit(*arg)) {
+						x = strtol(arg, &ccp, 0);
+						if (ccp == arg)
+							break;
+						arg = ccp;
+					}
+					sep->se_log &= ~MULOG_RFC931;
+					sep->se_log |= x;
+					break;
+				case 'a':
+					sep->se_log |= MULOG_RFC931;
+					break;
+				default:
+					break;
+				}
+			}
+			arg = colon + 1;
 		}
+#endif
+		if (argc < MAXARGV)
+			sep->se_argv[argc++] = newstr(arg);
+	}
 	while (argc <= MAXARGV)
 		sep->se_argv[argc++] = NULL;
-	for (i = 0; i < PERIPSIZE; ++i)
-		LIST_INIT(&sep->se_conn[i]);
 #ifdef IPSEC
 	sep->se_policy = policy ? newstr(policy) : NULL;
 #endif
 	return (sep);
 }
 
-void
+static void
 freeconfig(struct servtab *cp)
 {
 	int i;
 
+	if (cp->se_hostaddr)
+		free(cp->se_hostaddr);
 	if (cp->se_service)
 		free(cp->se_service);
 	if (cp->se_proto)
 		free(cp->se_proto);
 	if (cp->se_user)
 		free(cp->se_user);
-	if (cp->se_group)
-		free(cp->se_group);
-#ifdef LOGIN_CAP
-	if (cp->se_class)
-		free(cp->se_class);
-#endif
+	/* Note: se_group is part of the newstr'ed se_user */
 	if (cp->se_server)
 		free(cp->se_server);
-	if (cp->se_pids)
-		free(cp->se_pids);
 	for (i = 0; i < MAXARGV; i++)
 		if (cp->se_argv[i])
 			free(cp->se_argv[i]);
-	free_connlist(cp);
 #ifdef IPSEC
 	if (cp->se_policy)
 		free(cp->se_policy);
@@ -1947,7 +1677,7 @@
  * Safe skip - if skip returns null, log a syntax error in the
  * configuration file and exit.
  */
-char *
+static char *
 sskip(char **cpp)
 {
 	char *cp;
@@ -1955,17 +1685,20 @@
 	cp = skip(cpp);
 	if (cp == NULL) {
 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
-		exit(EX_DATAERR);
+		exit(1);
 	}
 	return (cp);
 }
 
-char *
+static char *
 skip(char **cpp)
 {
 	char *cp = *cpp;
 	char *start;
-	char quote = '\0';
+	char quote;
+
+	if (*cpp == NULL)
+		return (NULL);
 
 again:
 	while (*cp == ' ' || *cp == '\t')
@@ -1974,527 +1707,827 @@
 		int c;
 
 		c = getc(fconfig);
-		ungetc(c, fconfig);
+		(void) ungetc(c, fconfig);
 		if (c == ' ' || c == '\t')
 			if ((cp = nextline(fconfig)))
 				goto again;
-		*cpp = (char *)0;
-		return ((char *)0);
+		*cpp = NULL;
+		return (NULL);
 	}
-	if (*cp == '"' || *cp == '\'')
-		quote = *cp++;
 	start = cp;
-	if (quote)
-		while (*cp && *cp != quote)
-			cp++;
-	else
-		while (*cp && *cp != ' ' && *cp != '\t')
+	quote = '\0';
+	while (*cp && (quote || (*cp != ' ' && *cp != '\t'))) {
+		if (*cp == '\'' || *cp == '"') {
+			if (quote && *cp != quote)
+				cp++;
+			else {
+				if (quote)
+					quote = '\0';
+				else
+					quote = *cp;
+				memmove(cp, cp+1, strlen(cp));
+			}
+		} else
 			cp++;
+	}
 	if (*cp != '\0')
 		*cp++ = '\0';
 	*cpp = cp;
 	return (start);
 }
 
-char *
+static char *
 nextline(FILE *fd)
 {
 	char *cp;
 
 	if (fgets(line, sizeof (line), fd) == NULL)
-		return ((char *)0);
+		return (NULL);
 	cp = strchr(line, '\n');
 	if (cp)
 		*cp = '\0';
 	return (line);
 }
 
-char *
-newstr(const char *cp)
+static char *
+newstr(char *cp)
 {
-	char *cr;
-
-	if ((cr = strdup(cp != NULL ? cp : "")))
-		return (cr);
+	if ((cp = strdup((cp != NULL) ? cp : "")) != NULL)
+		return (cp);
 	syslog(LOG_ERR, "strdup: %m");
-	exit(EX_OSERR);
+	exit(1);
 }
 
-void
-inetd_setproctitle(const char *a, int s)
+static void
+inetd_setproctitle(char *a, int s)
 {
 	socklen_t size;
 	struct sockaddr_storage ss;
-	char buf[80], pbuf[INET6_ADDRSTRLEN];
+	char hbuf[NI_MAXHOST], *hp;
 
 	size = sizeof(ss);
 	if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
-		getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf),
-			    NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID);
-		sprintf(buf, "%s [%s]", a, pbuf);
+		if (getnameinfo((struct sockaddr *)&ss, size, hp = hbuf,
+		    sizeof(hbuf), NULL, 0, niflags) != 0)
+			hp = "?";
+		setproctitle("-%s [%s]", a, hp);
 	} else
-		sprintf(buf, "%s", a);
-	setproctitle("%s", buf);
+		setproctitle("-%s", a);
 }
 
-int
-check_loop(const struct sockaddr *sa, const struct servtab *sep)
+static void
+bump_nofile(void)
 {
-	struct servtab *se2;
-	char pname[INET6_ADDRSTRLEN];
+#ifdef RLIMIT_NOFILE
 
-	for (se2 = servtab; se2; se2 = se2->se_next) {
-		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
-			continue;
+#define FD_CHUNK	32
 
-		switch (se2->se_family) {
-		case AF_INET:
-			if (((const struct sockaddr_in *)sa)->sin_port ==
-			    se2->se_ctrladdr4.sin_port)
-				goto isloop;
-			continue;
-#ifdef INET6
-		case AF_INET6:
-			if (((const struct sockaddr_in *)sa)->sin_port ==
-			    se2->se_ctrladdr4.sin_port)
-				goto isloop;
-			continue;
-#endif
-		default:
-			continue;
-		}
-	isloop:
-		getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0,
-			    NI_NUMERICHOST|NI_WITHSCOPEID);
-		syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s",
-		       sep->se_service, sep->se_proto,
-		       se2->se_service, se2->se_proto,
-		       pname);
-		return 1;
+	struct rlimit rl;
+
+	if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
+		syslog(LOG_ERR, "getrlimit: %m");
+		return;
+	}
+	rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
+	if (rl.rlim_cur <= rlim_ofile_cur) {
+		syslog(LOG_ERR,
+		    "bump_nofile: cannot extend file limit, max = %d",
+		    (int)rl.rlim_cur);
+		return;
 	}
-	return 0;
+
+	if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
+		syslog(LOG_ERR, "setrlimit: %m");
+		return;
+	}
+
+	rlim_ofile_cur = rl.rlim_cur;
+	return;
+
+#else
+	syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
+	return;
+#endif
 }
 
 /*
- * print_service:
- *	Dump relevant information to stderr
+ * Internet services provided internally by inetd:
  */
-void
-print_service(const char *action, const struct servtab *sep)
+#define	BUFSIZE	4096
+
+/* ARGSUSED */
+static void
+echo_stream(int s, struct servtab *sep)	/* Echo service -- echo data back */
 {
-	fprintf(stderr,
-	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s"
-#ifdef LOGIN_CAP
-	    "class=%s"
-#endif
-	    " builtin=%p server=%s"
-#ifdef IPSEC
-	    " policy=\"%s\""
-#endif
-	    "\n",
-	    action, sep->se_service, sep->se_proto,
-	    sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group,
-#ifdef LOGIN_CAP
-	    sep->se_class,
-#endif
-	    (void *) sep->se_bi, sep->se_server
-#ifdef IPSEC
-	    , (sep->se_policy ? sep->se_policy : "")
-#endif
-	    );
+	char buffer[BUFSIZE];
+	int i;
+
+	inetd_setproctitle(sep->se_service, s);
+	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
+	    write(s, buffer, i) > 0)
+		;
 }
 
-#define CPMHSIZE	256
-#define CPMHMASK	(CPMHSIZE-1)
-#define CHTGRAN		10
-#define CHTSIZE		6
+/* ARGSUSED */
+static void
+echo_dg(int s, struct servtab *sep)	/* Echo service -- echo data back */
+{
+	char buffer[BUFSIZE];
+	int i;
+	socklen_t size;
+	struct sockaddr_storage ss;
+	struct sockaddr *sa;
 
-typedef struct CTime {
-	unsigned long 	ct_Ticks;
-	int		ct_Count;
-} CTime;
+	sa = (struct sockaddr *)&ss;
+	size = sizeof(ss);
+	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, sa, &size)) < 0)
+		return;
+	if (port_good_dg(sa))
+		(void) sendto(s, buffer, i, 0, sa, size);
+}
 
-typedef struct CHash {
-	union {
-		struct in_addr	c4_Addr;
-		struct in6_addr	c6_Addr;
-	} cu_Addr;
-#define	ch_Addr4	cu_Addr.c4_Addr
-#define	ch_Addr6	cu_Addr.c6_Addr
-	int		ch_Family;
-	time_t		ch_LTime;
-	char		*ch_Service;
-	CTime		ch_Times[CHTSIZE];
-} CHash;
+/* ARGSUSED */
+static void
+discard_stream(int s, struct servtab *sep) /* Discard service -- ignore data */
+{
+	char buffer[BUFSIZE];
 
-CHash	CHashAry[CPMHSIZE];
+	inetd_setproctitle(sep->se_service, s);
+	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
+			errno == EINTR)
+		;
+}
 
-int
-cpmip(const struct servtab *sep, int ctrl)
+/* ARGSUSED */
+static void
+discard_dg(int s, struct servtab *sep)	/* Discard service -- ignore data */
+	
 {
-	struct sockaddr_storage rss;
-	socklen_t rssLen = sizeof(rss);
-	int r = 0;
+	char buffer[BUFSIZE];
 
-	/*
-	 * If getpeername() fails, just let it through (if logging is
-	 * enabled the condition is caught elsewhere)
-	 */
+	(void) read(s, buffer, sizeof(buffer));
+}
 
-	if (sep->se_maxcpm > 0 && 
-	    getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) {
-		time_t t = time(NULL);
-		int hv = 0xABC3D20F;
-		int i;
-		int cnt = 0;
-		CHash *chBest = NULL;
-		unsigned int ticks = t / CHTGRAN;
-		struct sockaddr_in *sin4;
-#ifdef INET6
-		struct sockaddr_in6 *sin6;
-#endif
+#include <ctype.h>
+#define LINESIZ 72
+char ring[128];
+char *endring;
 
-		sin4 = (struct sockaddr_in *)&rss;
-#ifdef INET6
-		sin6 = (struct sockaddr_in6 *)&rss;
-#endif
-		{
-			char *p;
-			int addrlen;
+static void
+initring(void)
+{
+	int i;
 
-			switch (rss.ss_family) {
-			case AF_INET:
-				p = (char *)&sin4->sin_addr;
-				addrlen = sizeof(struct in_addr);
-				break;
-#ifdef INET6
-			case AF_INET6:
-				p = (char *)&sin6->sin6_addr;
-				addrlen = sizeof(struct in6_addr);
-				break;
-#endif
-			default:
-				/* should not happen */
-				return -1;
-			}
+	endring = ring;
 
-			for (i = 0; i < addrlen; ++i, ++p) {
-				hv = (hv << 5) ^ (hv >> 23) ^ *p;
-			}
-			hv = (hv ^ (hv >> 16));
-		}
-		for (i = 0; i < 5; ++i) {
-			CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
+	for (i = 0; i <= 128; ++i)
+		if (isprint(i))
+			*endring++ = i;
+}
 
-			if (rss.ss_family == AF_INET &&
-			    ch->ch_Family == AF_INET &&
-			    sin4->sin_addr.s_addr == ch->ch_Addr4.s_addr &&
-			    ch->ch_Service && strcmp(sep->se_service,
-			    ch->ch_Service) == 0) {
-				chBest = ch;
-				break;
-			}
-#ifdef INET6
-			if (rss.ss_family == AF_INET6 &&
-			    ch->ch_Family == AF_INET6 &&
-			    IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
-					       &ch->ch_Addr6) != 0 &&
-			    ch->ch_Service && strcmp(sep->se_service,
-			    ch->ch_Service) == 0) {
-				chBest = ch;
-				break;
-			}
-#endif
-			if (chBest == NULL || ch->ch_LTime == 0 || 
-			    ch->ch_LTime < chBest->ch_LTime) {
-				chBest = ch;
-			}
-		}
-		if ((rss.ss_family == AF_INET &&
-		     (chBest->ch_Family != AF_INET ||
-		      sin4->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) ||
-		    chBest->ch_Service == NULL ||
-		    strcmp(sep->se_service, chBest->ch_Service) != 0) {
-			chBest->ch_Family = sin4->sin_family;
-			chBest->ch_Addr4 = sin4->sin_addr;
-			if (chBest->ch_Service)
-				free(chBest->ch_Service);
-			chBest->ch_Service = strdup(sep->se_service);
-			bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
-		} 
-#ifdef INET6
-		if ((rss.ss_family == AF_INET6 &&
-		     (chBest->ch_Family != AF_INET6 ||
-		      IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
-					 &chBest->ch_Addr6) == 0)) ||
-		    chBest->ch_Service == NULL ||
-		    strcmp(sep->se_service, chBest->ch_Service) != 0) {
-			chBest->ch_Family = sin6->sin6_family;
-			chBest->ch_Addr6 = sin6->sin6_addr;
-			if (chBest->ch_Service)
-				free(chBest->ch_Service);
-			chBest->ch_Service = strdup(sep->se_service);
-			bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
-		}
-#endif
-		chBest->ch_LTime = t;
-		{
-			CTime *ct = &chBest->ch_Times[ticks % CHTSIZE];
-			if (ct->ct_Ticks != ticks) {
-				ct->ct_Ticks = ticks;
-				ct->ct_Count = 0;
-			}
-			++ct->ct_Count;
-		}
-		for (i = 0; i < CHTSIZE; ++i) {
-			CTime *ct = &chBest->ch_Times[i];
-			if (ct->ct_Ticks <= ticks &&
-			    ct->ct_Ticks >= ticks - CHTSIZE) {
-				cnt += ct->ct_Count;
-			}
-		}
-		if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) {
-			char pname[INET6_ADDRSTRLEN];
-
-			getnameinfo((struct sockaddr *)&rss,
-				    ((struct sockaddr *)&rss)->sa_len,
-				    pname, sizeof(pname), NULL, 0,
-				    NI_NUMERICHOST|NI_WITHSCOPEID);
-			r = -1;
-			syslog(LOG_ERR,
-			    "%s from %s exceeded counts/min (limit %d/min)",
-			    sep->se_service, pname,
-			    sep->se_maxcpm);
+/* ARGSUSED */
+static void
+chargen_stream(int s,struct servtab *sep)	/* Character generator */
+{
+	int len;
+	char *rs, text[LINESIZ+2];
+
+	inetd_setproctitle(sep->se_service, s);
+
+	if (!endring) {
+		initring();
+		rs = ring;
+	}
+
+	text[LINESIZ] = '\r';
+	text[LINESIZ + 1] = '\n';
+	for (rs = ring;;) {
+		if ((len = endring - rs) >= LINESIZ)
+			memmove(text, rs, LINESIZ);
+		else {
+			memmove(text, rs, len);
+			memmove(text + len, ring, LINESIZ - len);
 		}
+		if (++rs == endring)
+			rs = ring;
+		if (write(s, text, sizeof(text)) != sizeof(text))
+			break;
 	}
-	return(r);
 }
 
-static struct conninfo *
-search_conn(struct servtab *sep, int ctrl)
+/* ARGSUSED */
+static void
+chargen_dg(int s, struct servtab *sep)		/* Character generator */
 {
 	struct sockaddr_storage ss;
-	socklen_t sslen = sizeof(ss);
-	struct conninfo *conn;
-	int hv;
-	char pname[NI_MAXHOST],  pname2[NI_MAXHOST];
+	struct sockaddr *sa;
+	static char *rs;
+	int len;
+	socklen_t size;
+	char text[LINESIZ+2];
 
-	if (sep->se_maxperip <= 0)
-		return NULL;
+	if (endring == 0) {
+		initring();
+		rs = ring;
+	}
 
-	/*
-	 * If getpeername() fails, just let it through (if logging is
-	 * enabled the condition is caught elsewhere)
-	 */
-	if (getpeername(ctrl, (struct sockaddr *)&ss, &sslen) != 0)
-		return NULL;
+	sa = (struct sockaddr *)&ss;
+	size = sizeof(ss);
+	if (recvfrom(s, text, sizeof(text), 0, sa, &size) < 0)
+		return;
 
-	switch (ss.ss_family) {
-	case AF_INET:
-		hv = hashval((char *)&((struct sockaddr_in *)&ss)->sin_addr,
-		    sizeof(struct in_addr));
-		break;
-#ifdef INET6
-	case AF_INET6:
-		hv = hashval((char *)&((struct sockaddr_in6 *)&ss)->sin6_addr,
-		    sizeof(struct in6_addr));
-		break;
-#endif
-	default:
-		/*
-		 * Since we only support AF_INET and AF_INET6, just
-		 * let other than AF_INET and AF_INET6 through.
-		 */
-		return NULL;
-	}
+	if (!port_good_dg(sa))
+		return;
 
-	if (getnameinfo((struct sockaddr *)&ss, sslen, pname, sizeof(pname),
-	    NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID) != 0)
-		return NULL;
-
-	LIST_FOREACH(conn, &sep->se_conn[hv], co_link) {
-		if (getnameinfo((struct sockaddr *)&conn->co_addr,
-		    conn->co_addr.ss_len, pname2, sizeof(pname2), NULL, 0,
-		    NI_NUMERICHOST | NI_WITHSCOPEID) == 0 &&
-		    strcmp(pname, pname2) == 0)
-			break;
+	if ((len = endring - rs) >= LINESIZ)
+		memmove(text, rs, LINESIZ);
+	else {
+		memmove(text, rs, len);
+		memmove(text + len, ring, LINESIZ - len);
 	}
+	if (++rs == endring)
+		rs = ring;
+	text[LINESIZ] = '\r';
+	text[LINESIZ + 1] = '\n';
+	(void) sendto(s, text, sizeof(text), 0, sa, size);
+}
 
-	if (conn == NULL) {
-		if ((conn = malloc(sizeof(struct conninfo))) == NULL) {
-			syslog(LOG_ERR, "malloc: %m");
-			exit(EX_OSERR);
-		}
-		conn->co_proc = malloc(sep->se_maxperip * sizeof(*conn->co_proc));
-		if (conn->co_proc == NULL) {
-			syslog(LOG_ERR, "malloc: %m");
-			exit(EX_OSERR);
-		}
-		memcpy(&conn->co_addr, (struct sockaddr *)&ss, sslen);
-		conn->co_numchild = 0;
-		LIST_INSERT_HEAD(&sep->se_conn[hv], conn, co_link);
+/*
+ * Return a machine readable date and time, in the form of the
+ * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
+ * returns the number of seconds since midnight, Jan 1, 1970,
+ * we must add 2208988800 seconds to this figure to make up for
+ * some seventy years Bell Labs was asleep.
+ */
+
+static uint32_t
+machtime(void)
+{
+	struct timeval tv;
+
+	if (gettimeofday(&tv, NULL) < 0) {
+		if (debug)
+			fprintf(stderr, "Unable to get time of day\n");
+		return (0);
 	}
+#define	OFFSET ((uint32_t)25567 * 24*60*60)
+	return (htonl((uint32_t)(tv.tv_sec + OFFSET)));
+#undef OFFSET
+}
 
-	/*
-	 * Since a child process is not invoked yet, we cannot
-	 * determine a pid of a child.  So, co_proc and co_numchild
-	 * should be filled leter.
-	 */
+/* ARGSUSED */
+static void
+machtime_stream(int s, struct servtab *sep)
+{
+	uint32_t result;
 
-	return conn;
+	result = machtime();
+	(void) write(s, (char *) &result, sizeof(result));
 }
 
-static int
-room_conn(struct servtab *sep, struct conninfo *conn)
+/* ARGSUSED */
+void
+machtime_dg(int s, struct servtab *sep)
 {
-	char pname[NI_MAXHOST];
+	uint32_t result;
+	struct sockaddr_storage ss;
+	struct sockaddr *sa;
+	socklen_t size;
 
-	if (conn->co_numchild >= sep->se_maxperip) {
-		getnameinfo((struct sockaddr *)&conn->co_addr,
-		    conn->co_addr.ss_len, pname, sizeof(pname), NULL, 0,
-		    NI_NUMERICHOST | NI_WITHSCOPEID);
-		syslog(LOG_ERR, "%s from %s exceeded counts (limit %d)",
-		    sep->se_service, pname, sep->se_maxperip);
-		return 0;
-	}
-	return 1;
+	sa = (struct sockaddr *)&ss;
+	size = sizeof(ss);
+	if (recvfrom(s, (char *)&result, sizeof(result), 0, sa, &size) < 0)
+		return;
+	if (!port_good_dg(sa))
+		return;
+	result = machtime();
+	(void) sendto(s, (char *) &result, sizeof(result), 0, sa, size);
 }
 
+/* ARGSUSED */
 static void
-addchild_conn(struct conninfo *conn, pid_t pid)
+daytime_stream(int s,struct servtab *sep)
+/* Return human-readable time of day */
 {
-	struct procinfo *proc;
+	char buffer[256];
+	time_t clock;
+	int len;
 
-	if (conn == NULL)
+	clock = time((time_t *) 0);
+
+	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
+	(void) write(s, buffer, len);
+}
+
+/* ARGSUSED */
+void
+daytime_dg(int s, struct servtab *sep)
+/* Return human-readable time of day */
+{
+	char buffer[256];
+	time_t clock;
+	struct sockaddr_storage ss;
+	struct sockaddr *sa;
+	socklen_t size;
+	int len;
+
+	clock = time((time_t *) 0);
+
+	sa = (struct sockaddr *)&ss;
+	size = sizeof(ss);
+	if (recvfrom(s, buffer, sizeof(buffer), 0, sa, &size) < 0)
 		return;
+	if (!port_good_dg(sa))
+		return;
+	len = snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
+	(void) sendto(s, buffer, len, 0, sa, size);
+}
 
-	if ((proc = search_proc(pid, 1)) != NULL) {
-		if (proc->pr_conn != NULL) {
-			syslog(LOG_ERR,
-			    "addchild_conn: child already on process list");
-			exit(EX_OSERR);
-		}
-		proc->pr_conn = conn;
-	}
+/*
+ * print_service:
+ *	Dump relevant information to stderr
+ */
+static void
+print_service(char *action, struct servtab *sep)
+{
 
-	conn->co_proc[conn->co_numchild++] = proc;
+	if (isrpcservice(sep))
+		fprintf(stderr,
+		    "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user:group=%s:%s builtin=%lx server=%s"
+#ifdef IPSEC
+		    " policy=\"%s\""
+#endif
+		    "\n",
+		    action, sep->se_service,
+		    sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
+		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
+		    (long)sep->se_bi, sep->se_server
+#ifdef IPSEC
+		    , (sep->se_policy ? sep->se_policy : "")
+#endif
+		    );
+	else
+		fprintf(stderr,
+		    "%s: %s proto=%s%s, wait.max=%d.%d, user:group=%s:%s builtin=%lx server=%s"
+#ifdef IPSEC
+		    " policy=%s"
+#endif
+		    "\n",
+		    action, sep->se_service,
+		    sep->se_type == FAITH_TYPE ? "faith/" : "",
+		    sep->se_proto,
+		    sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
+		    (long)sep->se_bi, sep->se_server
+#ifdef IPSEC
+		    , (sep->se_policy ? sep->se_policy : "")
+#endif
+		    );
 }
 
 static void
-reapchild_conn(pid_t pid)
+usage(void)
 {
-	struct procinfo *proc;
-	struct conninfo *conn;
-	int i;
+#ifdef LIBWRAP
+	(void)fprintf(stderr, "usage: %s [-dl] [conf]\n", getprogname());
+#else
+	(void)fprintf(stderr, "usage: %s [-d] [conf]\n", getprogname());
+#endif
+	exit(1);
+}
 
-	if ((proc = search_proc(pid, 0)) == NULL)
-		return;
-	if ((conn = proc->pr_conn) == NULL)
-		return;
-	for (i = 0; i < conn->co_numchild; ++i)
-		if (conn->co_proc[i] == proc) {
-			conn->co_proc[i] = conn->co_proc[--conn->co_numchild];
-			break;
+
+/*
+ *  Based on TCPMUX.C by Mark K. Lottor November 1988
+ *  sri-nic::ps:<mkl>tcpmux.c
+ */
+
+static int		/* # of characters upto \r,\n or \0 */
+getline(int fd,	char *buf, int len)
+{
+	int count = 0, n;
+
+	do {
+		n = read(fd, buf, len-count);
+		if (n == 0)
+			return (count);
+		if (n < 0)
+			return (-1);
+		while (--n >= 0) {
+			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
+				return (count);
+			count++;
+			buf++;
 		}
-	free_proc(proc);
-	free_conn(conn);
+	} while (count < len);
+	return (count);
 }
 
+#define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
+
+#define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
+
 static void
-resize_conn(struct servtab *sep, int maxpip)
+tcpmux(int ctrl, struct servtab *sep)
 {
-	struct conninfo *conn;
-	int i, j;
+	char service[MAX_SERV_LEN+1];
+	int len;
 
-	if (sep->se_maxperip <= 0)
-		return;
-	if (maxpip <= 0) {
-		free_connlist(sep);
-		return;
+	/* Get requested service name */
+	if ((len = getline(ctrl, service, MAX_SERV_LEN)) < 0) {
+		strwrite(ctrl, "-Error reading service name\r\n");
+		goto reject;
 	}
-	for (i = 0; i < PERIPSIZE; ++i) {
-		LIST_FOREACH(conn, &sep->se_conn[i], co_link) {
-			for (j = maxpip; j < conn->co_numchild; ++j)
-				free_proc(conn->co_proc[j]);
-			conn->co_proc = realloc(conn->co_proc,
-			    maxpip * sizeof(*conn->co_proc));
-			if (conn->co_proc == NULL) {
-				syslog(LOG_ERR, "realloc: %m");
-				exit(EX_OSERR);
-			}
-			if (conn->co_numchild > maxpip)
-				conn->co_numchild = maxpip;
+	service[len] = '\0';
+
+	if (debug)
+		fprintf(stderr, "tcpmux: someone wants %s\n", service);
+
+	/*
+	 * Help is a required command, and lists available services,
+	 * one per line.
+	 */
+	if (!strcasecmp(service, "help")) {
+		strwrite(ctrl, "+Available services:\r\n");
+		strwrite(ctrl, "help\r\n");
+		for (sep = servtab; sep != NULL; sep = sep->se_next) {
+			if (!ISMUX(sep))
+				continue;
+			(void)write(ctrl, sep->se_service,
+			    strlen(sep->se_service));
+			strwrite(ctrl, "\r\n");
 		}
+		goto reject;
 	}
+
+	/* Try matching a service in inetd.conf with the request */
+	for (sep = servtab; sep != NULL; sep = sep->se_next) {
+		if (!ISMUX(sep))
+			continue;
+		if (!strcasecmp(service, sep->se_service)) {
+			if (ISMUXPLUS(sep))
+				strwrite(ctrl, "+Go\r\n");
+			run_service(ctrl, sep);
+			return;
+		}
+	}
+	strwrite(ctrl, "-Service not available\r\n");
+reject:
+	_exit(1);
 }
 
-static void
-free_connlist(struct servtab *sep)
+#ifdef MULOG
+void
+dolog(struct servtab *sep, int ctrl)
 {
-	struct conninfo *conn;
-	int i, j;
+	struct sockaddr_storage	ss;
+	struct sockaddr		*sa = (struct sockaddr *)&ss;
+	socklen_t		len = sizeof(ss);
+	char			*host, *dp, buf[BUFSIZ];
+	int			connected = 1;
+
+	switch (sep->se_family) {
+	case AF_INET:
+#ifdef INET6
+	case AF_INET6:
+#endif
+		break;
+	default:
+		return;
+	}
 
-	for (i = 0; i < PERIPSIZE; ++i) {
-		while ((conn = LIST_FIRST(&sep->se_conn[i])) != NULL) {
-			for (j = 0; j < conn->co_numchild; ++j)
-				free_proc(conn->co_proc[j]);
-			conn->co_numchild = 0;
-			free_conn(conn);
+	if (getpeername(ctrl, sa, &len) < 0) {
+		if (errno != ENOTCONN) {
+			syslog(LOG_ERR, "getpeername: %m");
+			return;
 		}
+		if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, sa, &len) < 0) {
+			syslog(LOG_ERR, "recvfrom: %m");
+			return;
+		}
+		connected = 0;
+	}
+	switch (sa->sa_family) {
+	case AF_INET:
+#ifdef INET6
+	case AF_INET6:
+#endif
+		break;
+	default:
+		syslog(LOG_ERR, "unexpected address family %u", sa->sa_family);
+		return;
+	}
+
+	if (getnameinfo(sa, len, buf, sizeof(buf), NULL, 0, 0) != 0)
+		strlcpy(buf, "?", sizeof(buf));
+	host = buf;
+
+	switch (sep->se_log & ~MULOG_RFC931) {
+	case 0:
+		return;
+	case 1:
+		if (curdom == NULL || *curdom == '\0')
+			break;
+		dp = host + strlen(host) - strlen(curdom);
+		if (dp < host)
+			break;
+		if (debug)
+			fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
+			    host, curdom);
+		if (strcasecmp(dp, curdom) == 0)
+			return;
+		break;
+	case 2:
+	default:
+		break;
 	}
+
+	openlog("", LOG_NOWAIT, MULOG);
+
+	if (connected && (sep->se_log & MULOG_RFC931))
+		syslog(LOG_INFO, "%s@%s wants %s",
+		    rfc931_name(sa, ctrl), host, sep->se_service);
+	else
+		syslog(LOG_INFO, "%s wants %s",
+		    host, sep->se_service);
 }
 
+/*
+ * From tcp_log by
+ *  Wietse Venema, Eindhoven University of Technology, The Netherlands.
+ */
+#if 0
+static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
+#endif
+
+#include <setjmp.h>
+
+#define	RFC931_PORT	113		/* Semi-well-known port */
+#define	TIMEOUT		4
+#define	TIMEOUT2	10
+
+static jmp_buf timebuf;
+
+/* timeout - handle timeouts */
+
 static void
-free_conn(struct conninfo *conn)
+timeout(int sig)
 {
-	if (conn == NULL)
-		return;
-	if (conn->co_numchild <= 0) {
-		LIST_REMOVE(conn, co_link);
-		free(conn->co_proc);
-		free(conn);
-	}
+	longjmp(timebuf, sig);
 }
 
-static struct procinfo *
-search_proc(pid_t pid, int add)
+/* rfc931_name - return remote user name */
+
+char *
+rfc931_name(struct sockaddr *there,	/* remote link information */
+    int ctrl)
 {
-	struct procinfo *proc;
-	int hv;
+	struct sockaddr_storage here;	/* local link information */
+	struct sockaddr_storage sin;	/* for talking to RFC931 daemon */
+	socklen_t	length;
+	int		s;
+	unsigned	remote;
+	unsigned	local;
+	static char	user[256];		/* XXX */
+	char		buf[256];
+	char		*cp;
+	char		*result = "USER_UNKNOWN";
+	int		len;
+	u_int16_t	myport, hisport;
+
+	/* Find out local port number of our stdin. */
+
+	length = sizeof(here);
+	if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
+		syslog(LOG_ERR, "getsockname: %m");
+		return (result);
+	}
+	switch (here.ss_family) {
+	case AF_INET:
+		myport = ((struct sockaddr_in *)&here)->sin_port;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		myport = ((struct sockaddr_in6 *)&here)->sin6_port;
+		break;
+#endif
+	}
+	switch (there->sa_family) {
+	case AF_INET:
+		hisport = ((struct sockaddr_in *)&there)->sin_port;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		hisport = ((struct sockaddr_in6 *)&there)->sin6_port;
+		break;
+#endif
+	}
+	/* Set up timer so we won't get stuck. */
+
+	if ((s = socket(here.ss_family, SOCK_STREAM, 0)) == -1) {
+		syslog(LOG_ERR, "socket: %m");
+		return (result);
+	}
+
+	sin = here;
+	switch (sin.ss_family) {
+	case AF_INET:
+		((struct sockaddr_in *)&sin)->sin_port = htons(0);
+		break;
+#ifdef INET6
+	case AF_INET6:
+		((struct sockaddr_in6 *)&sin)->sin6_port = htons(0);
+		break;
+#endif
+	}
+	if (bind(s, (struct sockaddr *) &sin, sin.ss_len) == -1) {
+		syslog(LOG_ERR, "bind: %m");
+		return (result);
+	}
+
+	signal(SIGALRM, timeout);
+	if (setjmp(timebuf)) {
+		close(s);			/* not: fclose(fp) */
+		return (result);
+	}
+	alarm(TIMEOUT);
+
+	/* Connect to the RFC931 daemon. */
+
+	memcpy(&sin, there, there->sa_len);
+	switch (sin.ss_family) {
+	case AF_INET:
+		((struct sockaddr_in *)&sin)->sin_port = htons(RFC931_PORT);
+		break;
+#ifdef INET6
+	case AF_INET6:
+		((struct sockaddr_in6 *)&sin)->sin6_port = htons(RFC931_PORT);
+		break;
+#endif
+	}
+	if (connect(s, (struct sockaddr *) &sin, sin.ss_len) == -1) {
+		close(s);
+		alarm(0);
+		return (result);
+	}
 
-	hv = hashval((char *)&pid, sizeof(pid));
-	LIST_FOREACH(proc, &proctable[hv], pr_link) {
-		if (proc->pr_pid == pid)
+	/* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
+	(void)snprintf(buf, sizeof buf, "%u,%u\r\n", ntohs(hisport),
+	    ntohs(myport));
+
+	for (len = 0, cp = buf; len < strlen(buf); ) {
+		int	n;
+
+		if ((n = write(s, cp, strlen(buf) - len)) == -1) {
+			close(s);
+			alarm(0);
+			return (result);
+		}
+		cp += n;
+		len += n;
+	}
+
+	/* Read response */
+	for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
+		char	c;
+		if (read(s, &c, 1) != 1) {
+			close(s);
+			alarm(0);
+			return (result);
+		}
+		if (c == '\n')
 			break;
+		*cp++ = c;
 	}
-	if (proc == NULL && add) {
-		if ((proc = malloc(sizeof(struct procinfo))) == NULL) {
-			syslog(LOG_ERR, "malloc: %m");
-			exit(EX_OSERR);
+	*cp = '\0';
+
+	if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local,
+	    user) == 3 && ntohs(hisport) == remote && ntohs(myport) == local) {
+		/* Strip trailing carriage return. */
+		if ((cp = strchr(user, '\r')) != NULL)
+			*cp = 0;
+		result = user;
+	}
+
+	alarm(0);
+	close(s);
+	return (result);
+}
+#endif
+
+/*
+ * check if the address/port where send data to is one of the obvious ports
+ * that are used for denial of service attacks like two echo ports
+ * just echoing data between them
+ */
+static int
+port_good_dg(struct sockaddr *sa)
+{
+	struct in_addr in;
+#ifdef INET6
+	struct in6_addr *in6;
+#endif
+	u_int16_t port;
+	int i, bad;
+	char hbuf[NI_MAXHOST];
+
+	bad = 0;
+
+	switch (sa->sa_family) {
+	case AF_INET:
+		in.s_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
+		port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+#ifdef INET6
+	v4chk:
+#endif
+		if (IN_MULTICAST(in.s_addr))
+			goto bad;
+		switch ((in.s_addr & 0xff000000) >> 24) {
+		case 0: case 127: case 255:
+			goto bad;
 		}
-		proc->pr_pid = pid;
-		proc->pr_conn = NULL;
-		LIST_INSERT_HEAD(&proctable[hv], proc, pr_link);
+		if (dg_broadcast(&in))
+			goto bad;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
+		port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+		if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
+			goto bad;
+		if (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6)) {
+			memcpy(&in, &in6->s6_addr[12], sizeof(in));
+			in.s_addr = ntohl(in.s_addr);
+			goto v4chk;
+		}
+		break;
+#endif
+	default:
+		/* XXX unsupported af, is it safe to assume it to be safe? */
+		return (1);
 	}
-	return proc;
+
+	for (i = 0; bad_ports[i] != 0; i++) {
+		if (port == bad_ports[i])
+			goto bad;
+	}
+
+	return (1);
+
+bad:
+	if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
+	    niflags) != 0)
+		strlcpy(hbuf, "?", sizeof(hbuf));
+	syslog(LOG_WARNING,"Possible DoS attack from %s, Port %d",
+		hbuf, port);
+	return (0);
 }
 
-static void
-free_proc(struct procinfo *proc)
+/* XXX need optimization */
+static int
+dg_broadcast(struct in_addr *in)
 {
-	if (proc == NULL)
-		return;
-	LIST_REMOVE(proc, pr_link);
-	free(proc);
+	struct ifaddrs *ifa, *ifap;
+	struct sockaddr_in *sin;
+
+	if (getifaddrs(&ifap) < 0)
+		return (0);
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr->sa_family != AF_INET ||
+		    (ifa->ifa_flags & IFF_BROADCAST) == 0)
+			continue;
+		sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
+		if (sin->sin_addr.s_addr == in->s_addr) {
+			freeifaddrs(ifap);
+			return (1);
+		}
+	}
+	freeifaddrs(ifap);
+	return (0);
 }
 
 static int
-hashval(char *p, int len)
+my_kevent(const struct kevent *changelist, size_t nchanges,
+    struct kevent *eventlist, size_t nevents)
+{
+	int	result;
+
+	while ((result = kevent(kq, changelist, nchanges, eventlist, nevents,
+	    NULL)) < 0)
+		if (errno != EINTR) {
+			syslog(LOG_ERR, "kevent: %m");
+			exit(EXIT_FAILURE);
+		}
+
+	return (result);
+}
+
+static struct kevent *
+allocchange(void)
 {
-	int i, hv = 0xABC3D20F;
+	if (changes == A_CNT(changebuf)) {
+		(void) my_kevent(changebuf, A_CNT(changebuf), NULL, 0);
+		changes = 0;
+	}
 
-	for (i = 0; i < len; ++i, ++p)
-		hv = (hv << 5) ^ (hv >> 23) ^ *p;
-	hv = (hv ^ (hv >> 16)) & (PERIPSIZE - 1);
-	return hv;
+	return (&changebuf[changes++]);
 }
Only in /usr/src/usr.sbin/inetd/: inetd.h
diff -ur --unidirectional-new-file /usr/src/usr.sbin/inetd/ipsec.c /usr/src-new/usr.sbin/inetd/ipsec.c
--- /usr/src/usr.sbin/inetd/ipsec.c	1969-12-31 18:00:00.000000000 -0600
+++ /usr/src-new/usr.sbin/inetd/ipsec.c	2006-06-20 11:02:09.000000000 -0500
@@ -0,0 +1,167 @@
+/*	$NetBSD: ipsec.c,v 1.2 2004/10/29 21:27:34 dsl Exp $	*/
+
+/*
+ * Copyright (C) 1999 WIDE Project.
+ * 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. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT 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/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#ifndef IPSEC_POLICY_IPSEC	/* no ipsec support on old ipsec */
+#undef IPSEC
+#endif
+#endif
+
+#include "ipsec.h"
+
+#ifdef IPSEC
+int
+ipsecsetup(af, fd, policy)
+	int af;
+	int fd;
+	const char *policy;
+{
+	char *p0, *p;
+	int error;
+
+	if (!policy || policy == '\0')
+		p0 = p = strdup("in entrust; out entrust");
+	else
+		p0 = p = strdup(policy);
+
+	error = 0;
+	while (1) {
+		p = strtok(p, ";");
+		if (p == NULL)
+			break;
+		while (*p && isspace((unsigned char)*p))
+			p++;
+		if (!*p) {
+			p = NULL;
+			continue;
+		}
+		error = ipsecsetup0(af, fd, p, 1);
+		if (error < 0)
+			break;
+		p = NULL;
+	}
+
+	free(p0);
+	return error;
+}
+
+int
+ipsecsetup_test(policy)
+	const char *policy;
+{
+	char *p0, *p;
+	char *buf;
+	int error;
+
+	if (!policy)
+		return -1;
+	p0 = p = strdup((char *)policy);
+
+	error = 0;
+	while (1) {
+		p = strtok(p, ";");
+		if (p == NULL)
+			break;
+		while (*p && isspace((unsigned char)*p))
+			p++;
+		if (!*p) {
+			p = NULL;
+			continue;
+		}
+		buf = ipsec_set_policy((char *)p, strlen(p));
+		if (buf == NULL) {
+			error = -1;
+			break;
+		}
+		free(buf);
+		p = NULL;
+	}
+
+	free(p0);
+	return error;
+}
+
+int
+ipsecsetup0(af, fd, policy, commit)
+	int af;
+	int fd;
+	const char *policy;
+	int commit;
+{
+	int level;
+	int opt;
+	char *buf;
+	int error;
+
+	switch (af) {
+	case AF_INET:
+		level = IPPROTO_IP;
+		opt = IP_IPSEC_POLICY;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		level = IPPROTO_IPV6;
+		opt = IPV6_IPSEC_POLICY;
+		break;
+#endif
+	default:
+		return -1;
+	}
+
+	buf = ipsec_set_policy((char *)policy, strlen(policy));
+	if (buf != NULL) {
+		error = 0;
+		if (commit && setsockopt(fd, level, opt,
+				buf, ipsec_get_policylen(buf)) < 0) {
+			error = -1;
+		}
+		free(buf);
+	} else
+		error = -1;
+	return error;
+}
+#endif
+
+
diff -ur --unidirectional-new-file /usr/src/usr.sbin/inetd/ipsec.h /usr/src-new/usr.sbin/inetd/ipsec.h
--- /usr/src/usr.sbin/inetd/ipsec.h	1969-12-31 18:00:00.000000000 -0600
+++ /usr/src-new/usr.sbin/inetd/ipsec.h	2006-06-20 11:05:55.000000000 -0500
@@ -0,0 +1,36 @@
+/*	$NetBSD: ipsec.h,v 1.1 2000/01/31 14:28:20 itojun Exp $	*/
+
+/*
+ * Copyright (C) 1999 WIDE Project.
+ * 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. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT 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.
+ */
+
+extern int ipsecsetup (int, int, const char *);
+extern int ipsecsetup_test (const char *);
+extern int ipsecsetup0 (int, int, const char *, int);
+
+
