several tcp apps IPv6 update

-inetd
 -rshd
 -rlogind
 -telnetd
 -rsh
 -rlogin

Reviewed by: freebsd-arch, cvs-committers
Obtained from: KAME project
This commit is contained in:
Yoshinobu Inoue 2000-01-25 14:52:10 +00:00
parent 71207448cf
commit 0cac72f42c
26 changed files with 1185 additions and 199 deletions

View File

@ -165,6 +165,8 @@ int profil __P((char *, size_t, vm_offset_t, int));
ssize_t pwrite __P((int, const void *, size_t, off_t));
int rcmd __P((char **, int, const char *,
const char *, const char *, int *));
int rcmd_af __P((char **, int, const char *,
const char *, const char *, int *, int));
char *re_comp __P((const char *));
int re_exec __P((const char *));
int readlink __P((const char *, char *, int));

View File

@ -58,7 +58,9 @@ MLINKS+=if_indextoname.3 if_nametoindex.3 if_indextoname.3 if_nameindex.3 \
if_indextoname.3 if_freenameindex.3
MLINKS+=linkaddr.3 link_addr.3 linkaddr.3 link_ntoa.3
#MLINKS+=ns.3 ns_addr.3 ns.3 ns_ntoa.3
MLINKS+=rcmd.3 iruserok.3 rcmd.3 rresvport.3 rcmd.3 ruserok.3
MLINKS+=rcmd.3 iruserok.3 rcmd.3 rresvport.3 rcmd.3 ruserok.3 \
rcmd.3 iruserok_af.3 rcmd.3 rresvport_af.3 rcmd.3 ruserok_af.3 \
rcmd.3 rcmd_af.3
MLINKS+=resolver.3 dn_comp.3 resolver.3 dn_expand.3 resolver.3 res_init.3 \
resolver.3 res_mkquery.3 resolver.3 res_query.3 \
resolver.3 res_search.3 resolver.3 res_send.3

View File

@ -40,6 +40,7 @@
.Nm rresvport ,
.Nm iruserok ,
.Nm ruserok ,
.Nm rcmd_af ,
.Nm rresvport_af ,
.Nm iruserok_af ,
.Nm ruserok_af
@ -55,7 +56,9 @@
.Ft int
.Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser"
.Ft int
.Fn rresvport_af "int *port" "int family"
.Fn rcmd_af "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" "int af"
.Ft int
.Fn rresvport_af "int *port" "int af"
.Ft int
.Fn iruserok_af "void *raddr" "int superuser" "const char *ruser" "const char *luser" "int af"
.Ft int
@ -184,17 +187,26 @@ It requires trusting the local DNS at most, while the
function requires trusting the entire DNS, which can be spoofed.
.Pp
Functions with ``_af'' suffix, i.e.
.Fn rcmd_af ,
.Fn rresvport_af ,
.Fn iruserok_af and
.Fn iruserok_af
and
.Fn ruserok_af ,
works just as same as functions without ``_af'', and is capable of
handling both IPv6 port and IPv4 port.
Functions without
.Dq Li _af
works for IPv4 only.
To switch address family,
.Fa af
argument must be filled with
.Dv AF_INET
.Dv AF_INET ,
or
.Dv AF_INET6 .
For
.Fn rcmd_af ,
.Dv PF_UNSPEC
is also allowed.
.Sh DIAGNOSTICS
The
.Fn rcmd
@ -230,6 +242,9 @@ functions appeared in
.Fn rresvport_af
appeared in RFC2292, and implemented by WIDE project
for Hydrangea IPv6 protocol stack kit.
.Fn rcmd_af
appeared in draft-ietf-ipngwg-rfc2292bis-01.txt,
and implemented by WIDE/KAME IPv6 protocol stack kit.
.Fn iruserok_af
and
.Fn rusreok_af

View File

@ -79,6 +79,17 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
u_short rport;
const char *locuser, *remuser, *cmd;
int *fd2p;
{
return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
}
int
rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
char **ahost;
u_short rport;
const char *locuser, *remuser, *cmd;
int *fd2p;
int af;
{
struct addrinfo hints, *res, *ai;
struct sockaddr_storage from;
@ -94,7 +105,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
(void)snprintf(num, sizeof(num), "%d", ntohs(rport));

View File

@ -5,6 +5,7 @@ LIB= util
SHLIB_MAJOR= 2
SHLIB_MINOR= 2
CFLAGS+=-Wall -DLIBC_SCCS -I${.CURDIR} -I${.CURDIR}/../../sys
CFLAGS+=-DINET6
SRCS= login.c login_tty.c logout.c logwtmp.c pty.c setproctitle.c \
login_cap.c login_class.c login_auth.c login_times.c login_ok.c \
_secure_path.c uucplock.c property.c auth.c realhostname.c fparseln.c \
@ -13,7 +14,7 @@ INCS= libutil.h login_cap.h
MAN3+= login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \
setproctitle.3 login_cap.3 login_class.3 login_times.3 login_ok.3 \
_secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
trimdomain.3 fparseln.3
realhostname_sa.3 trimdomain.3 fparseln.3
MAN5+= login.conf.5 auth.conf.5
MLINKS+= property.3 properties_read.3 property.3 properties_free.3
MLINKS+= property.3 property_find.3

View File

@ -60,6 +60,9 @@ void properties_free __P((properties list));
char *property_find __P((properties list, const char *name));
char *auth_getval __P((const char *name));
int realhostname __P((char *host, size_t hsize, const struct in_addr *ip));
struct sockaddr;
int realhostname_sa __P((char *host, size_t hsize, struct sockaddr *addr,
int addrlen));
#ifdef _STDIO_H_ /* avoid adding new includes */
char *fparseln __P((FILE *, size_t *, size_t *, const char[3], int));
#endif

View File

@ -103,4 +103,5 @@ now contains the numeric value of
.Sh SEE ALSO
.Xr gethostbyaddr 3 ,
.Xr gethostbyname 3 ,
.Xr inet_ntoa 3
.Xr inet_ntoa 3 ,
.Xr realhostname_sa 3

View File

@ -38,6 +38,17 @@
#include "libutil.h"
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
struct sockinet {
u_char si_len;
u_char si_family;
u_short si_port;
};
int
realhostname(char *host, size_t hsize, const struct in_addr *ip)
{
@ -71,3 +82,87 @@ realhostname(char *host, size_t hsize, const struct in_addr *ip)
return result;
}
int
realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen)
{
int result, error;
result = HOSTNAME_INVALIDADDR;
error = getnameinfo(addr, addrlen, host, hsize, NULL, 0, 0);
if (error == NULL) {
struct addrinfo hints, *res, *ores;
struct sockaddr *sa;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo(host, NULL, &hints, &res);
if (error) {
result = HOSTNAME_INVALIDNAME;
goto numeric;
} else for (ores = res; ; res = res->ai_next) {
if (res == NULL) {
freeaddrinfo(ores);
result = HOSTNAME_INCORRECTNAME;
goto numeric;
}
sa = res->ai_addr;
if (sa == NULL) {
freeaddrinfo(ores);
result = HOSTNAME_INCORRECTNAME;
goto numeric;
}
if (sa->sa_len == addrlen &&
sa->sa_family == addr->sa_family) {
u_int16_t port;
port = ((struct sockinet *)addr)->si_port;
((struct sockinet *)addr)->si_port = 0;
if (!memcmp(sa, addr, sa->sa_len)) {
strncpy(host, res->ai_canonname,
hsize);
result = HOSTNAME_FOUND;
((struct sockinet *)addr)->si_port =
port;
break;
}
((struct sockinet *)addr)->si_port = port;
}
#ifdef INET6
/*
* XXX IPv4 mapped IPv6 addr consideraton,
* specified in rfc2373.
*/
if (sa->sa_family == AF_INET &&
addr->sa_family == AF_INET6) {
struct in_addr *in;
struct in6_addr *in6;
in = &((struct sockaddr_in *)sa)->sin_addr;
in6 = &((struct sockaddr_in6 *)addr)->sin6_addr;
if (IN6_IS_ADDR_V4MAPPED(in6) &&
!memcmp(&in6->s6_addr[12], in,
sizeof(*in))) {
strncpy(host, res->ai_canonname,
hsize);
result = HOSTNAME_FOUND;
break;
}
}
#endif
}
freeaddrinfo(ores);
} else {
numeric:
getnameinfo(addr, addrlen, host, hsize, NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
/* XXX: do 'error' check */
}
return result;
}

View File

@ -0,0 +1,135 @@
.\" Copyright (C) 1995, 1996, 1997, 1998, 1999, and 2000 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.
.\"
.\" Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd January 11, 2000
.Os
.Dt REALHOSTNAME_SA 3
.Sh NAME
.Nm realhostname_sa
.Nd "convert an struct sockaddr to the real host name"
.Sh SYNOPSIS
.Fd #include <sys/types.h>
.Fd #include <netinet/in.h>
.Fd #include <libutil.h>
.Ft int
.Fn realhostname_sa "char *host" "size_t hsize" "struct sockaddr *addr" \
"int addrlen"
.Pp
Link with
.Va -lutil
on the
.Xr cc 1
command line.
.Sh DESCRIPTION
The function
.Fn realhostname_sa
converts
.Ar addr
to the corresponding host name. This is done by resolving
.Ar addr
to a host name and then ensuring that the host name resolves
back to
.Ar addr .
.Pp
.Ar host
must point to a buffer of at least
.Ar hsize
bytes, and will always be written to by this function.
.Pp
If the name resolution doesn't work both ways or if the host name is longer
than
.Ar hsize
bytes,
.Xr getnameinfo 3
with NI_NUMERICHOST specified, is used to convert
.Ar addr
to an ASCII form.
.Pp
If the string written to
.Ar host
is
.Ar hsize
bytes long,
.Ar host
will not be NUL terminated.
.Sh RETURN VALUES
.Fn realhostname_sa
will return one of the following constants which are defined in
.Pa libutil.h :
.Pp
.Bl -tag -width XXX -offset XXX
.It Li HOSTNAME_FOUND
A valid host name was found.
.It Li HOSTNAME_INCORRECTNAME
A host name was found, but it did not resolve back to the passed
.Ar ip .
.Ar host
now contains the numeric value of
.Ar ip .
.It Li HOSTNAME_INVALIDADDR
.Ar ip
could not be resolved.
.Ar host
now contains the numeric value of
.Ar ip .
.It Li HOSTNAME_INVALIDNAME
A host name was found, but it could not be resolved back to any ip number.
.Ar host
now contains the numeric value of
.Ar ip .
.El
.Sh SEE ALSO
.Xr getaddrinfo 3 ,
.Xr getnameinfo 3 ,
.Xr realhostname 3

View File

@ -6,7 +6,7 @@ SRCS= rlogind.c
MAN8= rlogind.8
DPADD= ${LIBUTIL}
LDADD= -lutil
CFLAGS+= -Wall
CFLAGS+= -Wall -DINET6
.if defined(NOPAM)
CFLAGS+= -DNO_PAM

View File

@ -204,3 +204,5 @@ The
.Nm
command appeared in
.Bx 4.2 .
.Pp
IPv6 support was added by WIDE/KAME project.

View File

@ -91,6 +91,11 @@ static const char rcsid[] =
#define ARGSTR "Dalnx"
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
char *env[2];
#define NMAX 30
char lusername[NMAX+1], rusername[NMAX+1];
@ -102,12 +107,25 @@ int no_delay;
struct passwd *pwd;
void doit __P((int, struct sockaddr_in *));
union sockunion {
struct sockinet {
u_char si_len;
u_char si_family;
u_short si_port;
} su_si;
struct sockaddr_in su_sin;
struct sockaddr_in6 su_sin6;
};
#define su_len su_si.si_len
#define su_family su_si.si_family
#define su_port su_si.si_port
void doit __P((int, union sockunion *));
int control __P((int, char *, int));
void protocol __P((int, int));
void cleanup __P((int));
void fatal __P((int, char *, int));
int do_rlogin __P((struct sockaddr_in *));
int do_rlogin __P((union sockunion *));
void getstr __P((char *, int, char *));
void setup_term __P((int));
int do_krb_login __P((struct sockaddr_in *));
@ -123,7 +141,7 @@ main(argc, argv)
char *argv[];
{
extern int __check_rhosts_file;
struct sockaddr_in from;
union sockunion from;
int ch, fromlen, on;
openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
@ -168,9 +186,12 @@ main(argc, argv)
if (no_delay &&
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
if (from.su_family == AF_INET)
{
on = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
doit(0, &from);
return 0;
@ -187,11 +208,12 @@ struct winsize win = { 0, 0, 0, 0 };
void
doit(f, fromp)
int f;
struct sockaddr_in *fromp;
union sockunion *fromp;
{
int master, pid, on = 1;
int authenticated = 0;
char hostname[MAXHOSTNAMELEN];
char hostname[2 * MAXHOSTNAMELEN + 1];
char nameinfo[2 * INET6_ADDRSTRLEN + 1];
char c;
alarm(60);
@ -201,20 +223,33 @@ doit(f, fromp)
exit(1);
alarm(0);
fromp->sin_port = ntohs((u_short)fromp->sin_port);
realhostname(hostname, sizeof(hostname) - 1, &fromp->sin_addr);
realhostname_sa(hostname, sizeof(hostname) - 1,
(struct sockaddr *)fromp, fromp->su_len);
/* error check ? */
fromp->su_port = ntohs((u_short)fromp->su_port);
hostname[sizeof(hostname) - 1] = '\0';
{
if (fromp->sin_family != AF_INET ||
fromp->sin_port >= IPPORT_RESERVED ||
fromp->sin_port < IPPORT_RESERVED/2) {
if ((fromp->su_family != AF_INET &&
#ifdef INET6
fromp->su_family != AF_INET6
#endif
) ||
fromp->su_port >= IPPORT_RESERVED ||
fromp->su_port < IPPORT_RESERVED/2) {
getnameinfo((struct sockaddr *)fromp,
fromp->su_len,
nameinfo, sizeof(nameinfo), NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
/* error check ? */
syslog(LOG_NOTICE, "Connection from %s on illegal port",
inet_ntoa(fromp->sin_addr));
nameinfo);
fatal(f, "Permission denied", 0);
}
#ifdef IP_OPTIONS
{
if (fromp->su_family == AF_INET)
{
u_char optbuf[BUFSIZ/3];
int optsize = sizeof(optbuf), ipproto, i;
struct protoent *ip;
@ -230,7 +265,7 @@ doit(f, fromp)
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
syslog(LOG_NOTICE,
"Connection refused from %s with IP option %s",
inet_ntoa(fromp->sin_addr),
inet_ntoa(fromp->su_sin.sin_addr),
c == IPOPT_LSRR ? "LSRR" : "SSRR");
exit(1);
}
@ -239,7 +274,7 @@ doit(f, fromp)
i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
}
}
}
}
#endif
if (do_rlogin(fromp) == 0)
authenticated++;
@ -533,9 +568,11 @@ fatal(f, msg, syserr)
int
do_rlogin(dest)
struct sockaddr_in *dest;
union sockunion *dest;
{
int retval;
int af;
char *addr;
getstr(rusername, sizeof(rusername), "remuser too long");
getstr(lusername, sizeof(lusername), "locuser too long");
@ -559,8 +596,22 @@ do_rlogin(dest)
if (pwd == NULL)
return (-1);
/* XXX why don't we syslog() failure? */
return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0,
rusername, lusername));
af = dest->su_family;
switch (af) {
case AF_INET:
addr = (char *)&dest->su_sin.sin_addr;
break;
#ifdef INET6
case AF_INET6:
addr = (char *)&dest->su_sin6.sin6_addr;
break;
#endif
default:
return -1; /*EAFNOSUPPORT*/
}
return (iruserok_af(addr, pwd->pw_uid == 0, rusername, lusername, af));
}
void

View File

@ -19,6 +19,9 @@ CFLAGS+=-DLOGIN_CAP -Wall
DPADD+= ${LIBUTIL}
LDADD+= -lutil
# IPv6 support
CFLAGS+= -DINET6
.include <bsd.prog.mk>
.PATH: ${.CURDIR}/../rlogind

View File

@ -250,3 +250,5 @@ A facility to allow all data exchanges to be encrypted should be
present.
.Pp
A more extensible protocol (such as Telnet) should be used.
.Sh HISTORY
IPv6 support was added by WIDE/KAME project.

View File

@ -80,6 +80,11 @@ static const char rcsid[] =
#include <login_cap.h>
#endif
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
int keepalive = 1;
int log_success; /* If TRUE, log all successful accesses */
int sent_null;
@ -88,7 +93,20 @@ int no_delay;
int doencrypt = 0;
#endif
void doit __P((struct sockaddr_in *));
union sockunion {
struct sockinet {
u_char si_len;
u_char si_family;
u_short si_port;
} su_si;
struct sockaddr_in su_sin;
struct sockaddr_in6 su_sin6;
};
#define su_len su_si.si_len
#define su_family su_si.si_family
#define su_port su_si.si_port
void doit __P((union sockunion *));
void error __P((const char *, ...));
void getstr __P((char *, int, char *));
int local_domain __P((char *));
@ -109,7 +127,7 @@ main(argc, argv)
extern int __check_rhosts_file;
struct linger linger;
int ch, on = 1, fromlen;
struct sockaddr_in from;
struct sockaddr_storage from;
openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
@ -169,7 +187,7 @@ main(argc, argv)
if (no_delay &&
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
doit(&from);
doit((union sockunion *)&from);
/* NOTREACHED */
return(0);
}
@ -184,7 +202,7 @@ char **environ;
void
doit(fromp)
struct sockaddr_in *fromp;
union sockunion *fromp;
{
extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */
struct passwd *pwd;
@ -195,7 +213,9 @@ doit(fromp)
char *errorstr;
char *cp, sig, buf[BUFSIZ];
char cmdbuf[NCARGS+1], locuser[16], remuser[16];
char fromhost[MAXHOSTNAMELEN];
char fromhost[2 * MAXHOSTNAMELEN + 1];
char numericname[INET6_ADDRSTRLEN];
int af = fromp->su_family, err;
int retval;
#ifdef CRYPT
int rc;
@ -216,14 +236,21 @@ doit(fromp)
}
}
#endif
fromp->sin_port = ntohs((u_short)fromp->sin_port);
if (fromp->sin_family != AF_INET) {
syslog(LOG_ERR, "malformed \"from\" address (af %d)",
fromp->sin_family);
fromp->su_port = ntohs((u_short)fromp->su_port);
if (af != AF_INET
#ifdef INET6
&& af != AF_INET6
#endif
) {
syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af);
exit(1);
}
err = getnameinfo((struct sockaddr *)fromp, fromp->su_len, numericname,
sizeof(numericname), NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
/* XXX: do 'err' check */
#ifdef IP_OPTIONS
{
if (af == AF_INET) {
u_char optbuf[BUFSIZ/3];
int optsize = sizeof(optbuf), ipproto, i;
struct protoent *ip;
@ -239,7 +266,7 @@ doit(fromp)
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
syslog(LOG_NOTICE,
"connection refused from %s with IP option %s",
inet_ntoa(fromp->sin_addr),
numericname,
c == IPOPT_LSRR ? "LSRR" : "SSRR");
exit(1);
}
@ -251,12 +278,12 @@ doit(fromp)
}
#endif
if (fromp->sin_port >= IPPORT_RESERVED ||
fromp->sin_port < IPPORT_RESERVED/2) {
if (fromp->su_port >= IPPORT_RESERVED ||
fromp->su_port < IPPORT_RESERVED/2) {
syslog(LOG_NOTICE|LOG_AUTH,
"connection from %s on illegal port %u",
inet_ntoa(fromp->sin_addr),
fromp->sin_port);
numericname,
fromp->su_port);
exit(1);
}
@ -279,7 +306,7 @@ doit(fromp)
(void) alarm(0);
if (port != 0) {
int lport = IPPORT_RESERVED - 1;
s = rresvport(&lport);
s = rresvport_af(&lport, af);
if (s < 0) {
syslog(LOG_ERR, "can't get stderr port: %m");
exit(1);
@ -288,11 +315,11 @@ doit(fromp)
port < IPPORT_RESERVED/2) {
syslog(LOG_NOTICE|LOG_AUTH,
"2nd socket from %s on unreserved port %u",
inet_ntoa(fromp->sin_addr),
numericname,
port);
exit(1);
}
fromp->sin_port = htons(port);
fromp->su_port = htons(port);
if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
syslog(LOG_INFO, "connect second port %d: %m", port);
exit(1);
@ -300,11 +327,13 @@ doit(fromp)
}
errorstr = NULL;
realhostname(fromhost, sizeof(fromhost) - 1, &fromp->sin_addr);
realhostname_sa(fromhost, sizeof(fromhost) - 1,
(struct sockaddr *)fromp,
fromp->su_len);
fromhost[sizeof(fromhost) - 1] = '\0';
#ifdef CRYPT
if (doencrypt) {
if (doencrypt && af == AF_INET) {
struct sockaddr_in local_addr;
rc = sizeof(local_addr);
if (getsockname(0, (struct sockaddr *)&local_addr,
@ -379,8 +408,14 @@ doit(fromp)
if (errorstr ||
(pwd->pw_expire && time(NULL) >= pwd->pw_expire) ||
(pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0,
remuser, locuser) < 0)) {
iruserok_af(
#ifdef INET6
(af == AF_INET6)
? (void *)&fromp->su_sin6.sin6_addr :
#endif
(void *)&fromp->su_sin.sin_addr,
pwd->pw_uid == 0,
remuser, locuser, af) < 0)) {
if (__rcmd_errstr)
syslog(LOG_INFO|LOG_AUTH,
"%s@%s as %s: permission denied (%s). cmd='%.80s'",
@ -402,10 +437,10 @@ doit(fromp)
exit(1);
}
#ifdef LOGIN_CAP
if (lc != NULL) {
if (lc != NULL && fromp->su_family == AF_INET) { /*XXX*/
char remote_ip[MAXHOSTNAMELEN];
strncpy(remote_ip, inet_ntoa(fromp->sin_addr),
strncpy(remote_ip, numericname,
sizeof(remote_ip) - 1);
remote_ip[sizeof(remote_ip) - 1] = 0;
if (!auth_hostok(lc, fromhost, remote_ip)) {

View File

@ -6,6 +6,7 @@ CFLAGS+=-DLINEMODE -DUSE_TERMIO -DDIAGNOSTICS
#CFLAGS+=-DKLUDGELINEMODE
CFLAGS+=-DOLD_ENVIRON -DENV_HACK
CFLAGS+=-I${.CURDIR}/../../lib
CFLAGS+=-DINET6
SRCS= global.c slc.c state.c sys_term.c telnetd.c \
termstat.c utility.c
DPADD= ${LIBUTIL} ${LIBTERMCAP} ${LIBTELNET}

View File

@ -623,3 +623,5 @@ never sends
.Tn TELNET
.Dv IAC GA
(go ahead) commands.
.Sh HISTORY
IPv6 support was added by WIDE/KAME project.

View File

@ -71,6 +71,12 @@ static const char rcsid[] =
#include <sys/secparm.h>
#include <sys/usrv.h>
# endif /* SO_SEC_MULTI */
/* wrapper for KAME-special getnameinfo() */
#ifndef NI_WITHSCOPEID
#define NI_WITHSCOPEID 0
#endif
int secflag;
char tty_dev[16];
struct secdev dv;
@ -137,7 +143,7 @@ int debug = 0;
int keepalive = 1;
char *altlogin;
void doit __P((struct sockaddr_in *));
void doit __P((struct sockaddr *));
int terminaltypeok __P((char *));
void startslave __P((char *, int, char *));
extern void usage P((void));
@ -149,6 +155,7 @@ extern void usage P((void));
*/
char valid_opts[] = {
'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
'4', '6',
#ifdef AUTHENTICATION
'a', ':', 'X', ':',
#endif
@ -173,11 +180,13 @@ char valid_opts[] = {
'\0'
};
int
int family = AF_INET;
int
main(argc, argv)
char *argv[];
{
struct sockaddr_in from;
struct sockaddr_storage from;
int on = 1, fromlen;
register int ch;
#if defined(IPPROTO_IP) && defined(IP_TOS)
@ -381,6 +390,16 @@ main(argc, argv)
break;
#endif /* AUTHENTICATION */
case '4':
family = AF_INET;
break;
#ifdef INET6
case '6':
family = AF_INET6;
break;
#endif
default:
warnx("%c: unknown option", ch);
/* FALLTHROUGH */
@ -394,43 +413,41 @@ main(argc, argv)
argv += optind;
if (debug) {
int s, ns, foo;
struct servent *sp;
static struct sockaddr_in sin = { AF_INET };
int s, ns, foo, error;
char *service = "telnet";
struct addrinfo hints, *res;
if (argc > 1) {
usage();
/* NOT REACHED */
} else if (argc == 1) {
if ((sp = getservbyname(*argv, "tcp"))) {
sin.sin_port = sp->s_port;
} else {
sin.sin_port = atoi(*argv);
if ((int)sin.sin_port <= 0) {
warnx("%s: bad port #", *argv);
usage();
/* NOT REACHED */
}
sin.sin_port = htons((u_short)sin.sin_port);
}
} else {
sp = getservbyname("telnet", "tcp");
if (sp == 0)
errx(1, "tcp/telnet: unknown service");
sin.sin_port = sp->s_port;
} else if (argc == 1)
service = *argv;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
error = getaddrinfo(NULL, service, &hints, &res);
if (error) {
errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
if (error == EAI_SYSTEM)
errx(1, "tcp/%s: %s\n", service, strerror(errno));
usage();
}
s = socket(AF_INET, SOCK_STREAM, 0);
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0)
err(1, "socket");
(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0)
if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
err(1, "bind");
if (listen(s, 1) < 0)
err(1, "listen");
foo = sizeof sin;
ns = accept(s, (struct sockaddr *)&sin, &foo);
foo = res->ai_addrlen;
ns = accept(s, res->ai_addr, &foo);
if (ns < 0)
err(1, "accept");
(void) dup2(ns, 0);
@ -512,7 +529,7 @@ main(argc, argv)
}
#if defined(IPPROTO_IP) && defined(IP_TOS)
{
if (from.ss_family == AF_INET) {
# if defined(HAS_GETTOS)
struct tosent *tp;
if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@ -528,7 +545,7 @@ main(argc, argv)
}
#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
net = 0;
doit(&from);
doit((struct sockaddr *)&from);
/* NOTREACHED */
return(0);
} /* end of main */
@ -773,8 +790,9 @@ char user_name[256];
*/
void
doit(who)
struct sockaddr_in *who;
struct sockaddr *who;
{
int err;
int ptynum;
/*
@ -817,16 +835,18 @@ doit(who)
#endif /* _SC_CRAY_SECURE_SYS */
/* get name of connected client */
if (realhostname(remote_hostname, sizeof(remote_hostname) - 1,
&who->sin_addr) == HOSTNAME_INVALIDADDR && registerd_host_only)
if (realhostname_sa(remote_hostname, sizeof(remote_hostname) - 1,
who, who->sa_len) == HOSTNAME_INVALIDADDR && registerd_host_only)
fatal(net, "Couldn't resolve your address into a host name.\r\n\
Please contact your net administrator");
remote_hostname[sizeof(remote_hostname) - 1] = '\0';
trimdomain(remote_hostname, UT_HOSTSIZE);
if (!isdigit(remote_hostname[0]) && strlen(remote_hostname) > utmp_len)
strncpy(remote_hostname, inet_ntoa(who->sin_addr),
sizeof(remote_hostname) - 1);
err = getnameinfo(who, who->sa_len, remote_hostname,
sizeof(remote_hostname), NULL, 0,
NI_NUMERICHOST|NI_WITHSCOPEID);
/* XXX: do 'err' check */
(void) gethostname(host_name, sizeof(host_name) - 1);
host_name[sizeof(host_name) - 1] = '\0';

View File

@ -226,6 +226,8 @@ The
.Nm
command appeared in
.Bx 4.2 .
.Pp
IPv6 support was added by WIDE/KAME project.
.Sh BUGS
.Nm Rlogin
will be replaced by

View File

@ -154,6 +154,8 @@ main(argc, argv)
#ifdef KERBEROS
char *k;
#endif
struct sockaddr_storage ss;
int sslen;
argoff = dflag = Dflag = 0;
one = 1;
@ -331,10 +333,11 @@ main(argc, argv)
if (doencrypt)
errx(1, "the -x flag requires Kerberos authentication");
#endif /* CRYPT */
rem = rcmd(&host, sp->s_port, localname, user, term, 0);
rem = rcmd_af(&host, sp->s_port, localname, user, term, 0,
PF_UNSPEC);
}
#else
rem = rcmd(&host, sp->s_port, localname, user, term, 0);
rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, PF_UNSPEC);
#endif /* KERBEROS */
if (rem < 0)
@ -347,9 +350,16 @@ main(argc, argv)
setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
warn("setsockopt NODELAY (ignored)");
sslen = sizeof(ss);
one = IPTOS_LOWDELAY;
if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 &&
ss.ss_family == AF_INET) {
if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one,
sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
} else
if (ss.ss_family == AF_INET)
warn("setsockopt getsockname failed");
(void)setuid(uid);
doit(omask);

View File

@ -269,10 +269,12 @@ main(argc, argv)
} else {
if (doencrypt)
errx(1, "the -x flag requires Kerberos authentication");
rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
&rfd2, PF_UNSPEC);
}
#else
rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
PF_UNSPEC);
#endif
if (rem < 0)

View File

@ -10,7 +10,8 @@ MAINTAINER=des@freebsd.org
COPTS+= -Wall -DLOGIN_CAP
#COPTS+= -DSANITY_CHECK
DPADD+= ${LIBUTIL} ${LIBWRAP}
LDADD+= -lutil -lwrap
CFLAGS+=-DINET6 -DIPSEC
DPADD+= ${LIBUTIL} ${LIBWRAP} ${LIBIPSEC}
LDADD+= -lutil -lwrap -lipsec
.include <bsd.prog.mk>

View File

@ -57,7 +57,7 @@ extern struct servtab *servtab;
char ring[128];
char *endring;
int check_loop __P((struct sockaddr_in *, struct servtab *sep));
int check_loop __P((struct sockaddr *, struct servtab *sep));
void inetd_setproctitle __P((char *, int));
struct biltin biltins[] = {
@ -111,7 +111,7 @@ chargen_dg(s, sep) /* Character generator */
int s;
struct servtab *sep;
{
struct sockaddr_in sin;
struct sockaddr_storage ss;
static char *rs;
int len, size;
char text[LINESIZ+2];
@ -121,12 +121,12 @@ chargen_dg(s, sep) /* Character generator */
rs = ring;
}
size = sizeof(sin);
size = sizeof(ss);
if (recvfrom(s, text, sizeof(text), 0,
(struct sockaddr *)&sin, &size) < 0)
(struct sockaddr *)&ss, &size) < 0)
return;
if (check_loop(&sin, sep))
if (check_loop((struct sockaddr *)&ss, sep))
return;
if ((len = endring - rs) >= LINESIZ)
@ -140,7 +140,7 @@ chargen_dg(s, sep) /* Character generator */
text[LINESIZ] = '\r';
text[LINESIZ + 1] = '\n';
(void) sendto(s, text, sizeof(text), 0,
(struct sockaddr *)&sin, sizeof(sin));
(struct sockaddr *)&ss, sizeof(ss));
}
/* ARGSUSED */
@ -189,22 +189,22 @@ daytime_dg(s, sep) /* Return human-readable time of day */
{
char buffer[256];
time_t clock;
struct sockaddr_in sin;
struct sockaddr_storage ss;
int size;
clock = time((time_t *) 0);
size = sizeof(sin);
size = sizeof(ss);
if (recvfrom(s, buffer, sizeof(buffer), 0,
(struct sockaddr *)&sin, &size) < 0)
(struct sockaddr *)&ss, &size) < 0)
return;
if (check_loop(&sin, sep))
if (check_loop((struct sockaddr *)&ss, sep))
return;
(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
(void) sendto(s, buffer, strlen(buffer), 0,
(struct sockaddr *)&sin, sizeof(sin));
(struct sockaddr *)&ss, sizeof(ss));
}
/* ARGSUSED */
@ -270,18 +270,18 @@ echo_dg(s, sep) /* Echo service -- echo data back */
{
char buffer[BUFSIZE];
int i, size;
struct sockaddr_in sin;
struct sockaddr_storage ss;
size = sizeof(sin);
size = sizeof(ss);
if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
(struct sockaddr *)&sin, &size)) < 0)
(struct sockaddr *)&ss, &size)) < 0)
return;
if (check_loop(&sin, sep))
if (check_loop((struct sockaddr *)&ss, sep))
return;
(void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
sizeof(sin));
(void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss,
sizeof(ss));
}
/* ARGSUSED */
@ -335,6 +335,8 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
struct utsname un;
struct stat sb;
struct sockaddr_in sin[2];
struct sockaddr_in6 sin6[2];
struct sockaddr_storage ss[2];
struct ucred uc;
struct timeval tv = {
10,
@ -345,7 +347,7 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
char buf[BUFSIZE], *cp = NULL, *p, **av, *osname = NULL, garbage[7];
char *fallback = NULL;
int len, c, fflag = 0, nflag = 0, rflag = 0, argc = 0, usedfallback = 0;
int gflag = 0, Rflag = 0;
int gflag = 0, Rflag = 0, getcredfail = 0;
u_short lport, fport;
inetd_setproctitle(sep->se_service, s);
@ -434,11 +436,11 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
iderror(0, 0, s, errno);
osname = un.sysname;
}
len = sizeof(sin[0]);
if (getsockname(s, (struct sockaddr *)&sin[0], &len) == -1)
len = sizeof(ss[0]);
if (getsockname(s, (struct sockaddr *)&ss[0], &len) == -1)
iderror(0, 0, s, errno);
len = sizeof(sin[1]);
if (getpeername(s, (struct sockaddr *)&sin[1], &len) == -1)
len = sizeof(ss[1]);
if (getpeername(s, (struct sockaddr *)&ss[1], &len) == -1)
iderror(0, 0, s, errno);
/*
* We're going to prepare for and execute reception of a
@ -476,11 +478,35 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
* arrays have been filled in above via get{peer,sock}name(),
* so right here we are only setting the ports.
*/
sin[0].sin_port = htons(lport);
sin[1].sin_port = htons(fport);
if (ss[0].ss_family != ss[1].ss_family)
iderror(lport, fport, s, errno);
len = sizeof(uc);
if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin,
sizeof(sin)) == -1) {
switch (ss[0].ss_family) {
case AF_INET:
sin[0] = *(struct sockaddr_in *)&ss[0];
sin[0].sin_port = htons(lport);
sin[1] = *(struct sockaddr_in *)&ss[1];
sin[1].sin_port = htons(fport);
if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin,
sizeof(sin)) == -1)
getcredfail = 1;
break;
#ifdef INET6
case AF_INET6:
sin6[0] = *(struct sockaddr_in6 *)&ss[0];
sin6[0].sin6_port = htons(lport);
sin6[1] = *(struct sockaddr_in6 *)&ss[1];
sin6[1].sin6_port = htons(fport);
if (sysctlbyname("net.inet6.tcp6.getcred", &uc, &len, sin6,
sizeof(sin6)) == -1)
getcredfail = 1;
break;
#endif
default: /* should not reach here */
getcredfail = 1;
break;
}
if (getcredfail != 0) {
if (fallback == NULL) /* Use a default, if asked to */
iderror(lport, fport, s, errno);
usedfallback = 1;
@ -611,20 +637,20 @@ machtime_dg(s, sep)
struct servtab *sep;
{
unsigned long result;
struct sockaddr_in sin;
struct sockaddr_storage ss;
int size;
size = sizeof(sin);
size = sizeof(ss);
if (recvfrom(s, (char *)&result, sizeof(result), 0,
(struct sockaddr *)&sin, &size) < 0)
(struct sockaddr *)&ss, &size) < 0)
return;
if (check_loop(&sin, sep))
if (check_loop((struct sockaddr *)&ss, sep))
return;
result = machtime();
(void) sendto(s, (char *) &result, sizeof(result), 0,
(struct sockaddr *)&sin, sizeof(sin));
(struct sockaddr *)&ss, sizeof(ss));
}
/* ARGSUSED */

View File

@ -47,7 +47,7 @@
.Op Fl W
.Op Fl c Ar maximum
.Op Fl C Ar rate
.Op Fl a Ar address
.Op Fl a Ar address|hostname
.Op Fl p Ar filename
.Op Fl R Ar rate
.Op Ar configuration file
@ -101,6 +101,22 @@ Specify the maximum number of times a service can be invoked
in one minute; the default is 256.
.It Fl a
Specify a specific IP address to bind to.
Or a hostname can also be specified, and then an IP address and/or an
IPv6 address corresponds to the hostname is used. Usually hostname
specification is used in conjunction with
.Xr jail 8 ,
where the hostname corresponds to a jail environment.
When hostname specification is used and either of IPv4 bind and IPv6
bind is desired, you need to specify 2 entry for each service, one for
IPv4 and one for IPv6, in /etc/inetd.conf.
For example,
.Bd -literal
telnet stream tcp4 nowait root /usr/libexec/telnetd telnetd
telnet stream tcp6 nowait root /usr/libexec/telnetd telnetd
.Ed
See explanation for protocol field in /etc/inetd.conf for details.
.It Fl p
Specify an alternate file in which to store the process ID.
.El
@ -221,14 +237,39 @@ Examples might be
.Dq tcp
or
.Dq udp .
In this case, this entry only accept IPv4 to keep backword
compatibility.
The names
.Dq tcp4 ,
.Dq udp4
specialized the entry to IPv4 only.
The names
.Dq tcp6 ,
.Dq udp6
specialized the entry to IPv6 only.
The names
.Dq tcp46 ,
.Dq udp46
let the entry accept each of IPv4 and IPv6 via AF_INET6 wildcard binded socket.
If it is desired that the service is reachable via T/TCP, one should
specify
.Dq tcp/ttcp .
This entry only accept IPv4 to keep backword compatibility.
The name
.Dq tcp4/ttcp ,
specialized the entry to IPv4 only.
The name
.Dq tcp6/ttcp ,
specialized the entry to IPv6 only.
The name
.Dq tcp46/ttcp ,
let the entry accept each of IPv4 and IPv6 via AF_INET6 wildcard binded socket.
Rpc based services are specified with the
.Dq rpc/tcp
or
.Dq rpc/udp
service type.
Currently only IPv4 is supported for rpc services.
TCPMUX services must use
.Dq tcp .
.Pp
@ -436,6 +477,9 @@ in
tcpmux stream tcp nowait root internal
.Ed
.Pp
Or if you wish to provide TCPMUX services also over IPv6, you can
specify tcp46 or tcp6 instead of tcp above.
.Pp
When given the
.Fl l
option
@ -528,6 +572,30 @@ causes
.Nm
to list TCPMUX services in
.Pa inetd.conf .
.Sh IPSEC
The implementation includes tiny hack to support IPsec policy setting for
each of the socket.
A special form of comment line, starting with
.Dq Li "#@" ,
will work as policy specifier.
The content of the above comment line will be treated as IPsec policy string,
as described in
.Xr ipsec_set_policy 3 .
A
.Li "#@"
line will affect all the following lines in
.Pa inetd.conf ,
so you may want to reset IPsec policy by using a comment line with
.Li "#@"
only
.Pq with no policy string .
.Pp
If invalid IPsec policy string appears on
.Pa inetd.conf ,
.Nm
will leave error message using
.Xr syslog 3 ,
and terminates itself.
.Sh "FILES"
.Bl -tag -width /var/run/inetd.pid -compact
.It Pa /etc/inetd.conf
@ -546,9 +614,14 @@ 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
#@ ipsec ah/require
chargen stream tcp nowait root internal
#@
.Ed
.Sh "ERROR MESSAGES"
The
@ -632,6 +705,7 @@ socket but was unable to.
.Sh SEE ALSO
.Xr hosts_access 5 ,
.Xr hosts_options 5 ,
.Xr ipsec_set_policy 3 ,
.Xr login.conf 5 ,
.Xr passwd 5 ,
.Xr rpc 5 ,
@ -662,6 +736,7 @@ based services is modeled after that
provided by
.Tn SunOS
4.1.
IPsec hack was made by KAME project, in 1999.
The
.Tn FreeBSD
TCP Wrappers support first appeared in

View File

@ -102,6 +102,13 @@ static const char rcsid[] =
* server program arguments maximum of MAXARGS
*
* Comment lines are indicated by a `#' in column 1.
*
* #ifdef IPSEC
* Comment lines that start with "#@" denote IPsec policy string, as described
* in ipsec_set_policy(3). This will affect all the following items in
* inetd.conf(8). To reset the policy, just use "#@" line. By default,
* there's no IPsec policy.
* #endif
*/
#include <sys/param.h>
#include <sys/ioctl.h>
@ -130,10 +137,23 @@ static const char rcsid[] =
#include <unistd.h>
#include <libutil.h>
#include <sysexits.h>
#include <ctype.h>
#include "inetd.h"
#include "pathnames.h"
#ifdef IPSEC
#include <netinet6/ipsec.h>
#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
#endif
#ifndef LIBWRAP_ALLOW_FACILITY
# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
#endif
@ -193,7 +213,13 @@ int maxchild = MAXCHILD;
int maxcpm = MAXCPM;
struct servent *sp;
struct rpcent *rpc;
struct in_addr bind_address;
char *hostname = NULL;
struct sockaddr_in *bind_sa4;
int no_v4bind = 1;
#ifdef INET6
struct sockaddr_in6 *bind_sa6;
int no_v6bind = 1;
#endif
int signalpipe[2];
#ifdef SANITY_CHECK
int nsock;
@ -248,8 +274,20 @@ main(argc, argv, envp)
int denied;
char *service = NULL;
char *pnm;
struct sockaddr_in peer;
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;
char *servname;
int error;
#ifdef OLD_SETPROCTITLE
@ -263,7 +301,6 @@ main(argc, argv, envp)
openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
bind_address.s_addr = htonl(INADDR_ANY);
while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1)
switch(ch) {
case 'd':
@ -286,11 +323,7 @@ main(argc, argv, envp)
"-C %s: bad value for maximum children/minute");
break;
case 'a':
if (!inet_aton(optarg, &bind_address)) {
syslog(LOG_ERR,
"-a %s: invalid IP address", optarg);
exit(EX_USAGE);
}
hostname = optarg;
break;
case 'p':
pid_file = optarg;
@ -309,6 +342,66 @@ main(argc, argv, envp)
" [-p pidfile] [conf-file]");
exit(EX_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;
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);
}
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);
}
argc -= optind;
argv += optind;
@ -457,18 +550,33 @@ main(argc, argv, envp)
} else
ctrl = sep->se_fd;
if (log && !ISWRAP(sep)) {
char pname[INET6_ADDRSTRLEN];
pnm = "unknown";
i = sizeof peer;
i = sizeof peermax;
if (getpeername(ctrl, (struct sockaddr *)
&peer, &i)) {
i = sizeof peer;
&peermax, &i)) {
i = sizeof peermax;
if (recvfrom(ctrl, buf, sizeof(buf),
MSG_PEEK,
(struct sockaddr *)&peer, &i) >= 0)
pnm = inet_ntoa(peer.sin_addr);
(struct sockaddr *)&peermax,
&i) >= 0) {
getnameinfo((struct sockaddr *)&peermax,
sizeof(peermax),
pname, sizeof(pname),
NULL, 0,
NI_NUMERICHOST|
NI_WITHSCOPEID);
pnm = pname;
}
} else {
getnameinfo((struct sockaddr *)&peermax,
sizeof(peermax),
pname, sizeof(pname),
NULL, 0,
NI_NUMERICHOST|
NI_WITHSCOPEID);
pnm = pname;
}
else
pnm = inet_ntoa(peer.sin_addr);
syslog(LOG_INFO,"%s from %s", sep->se_service, pnm);
}
(void) sigblock(SIGBLOCK);
@ -783,13 +891,18 @@ void config()
#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)
strcmp(sep->se_proto, new->se_proto) == 0 &&
sep->se_family == new->se_family)
break;
if (sep != 0) {
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 && new->se_maxchild) {
new->se_numchild = sep->se_numchild;
@ -823,6 +936,10 @@ void config()
SWAP(sep->se_server_name, new->se_server_name);
for (i = 0; i < MAXARGV; i++)
SWAP(sep->se_argv[i], new->se_argv[i]);
#ifdef IPSEC
SWAP(sep->se_policy, new->se_policy);
ipsecsetup(sep);
#endif
sigsetmask(omask);
freeconfig(new);
if (debug)
@ -837,21 +954,63 @@ void config()
sep->se_fd = -1;
continue;
}
switch (sep->se_family) {
case AF_INET:
if (no_v4bind != 0) {
sep->se_fd = -1;
continue;
}
break;
#ifdef INET6
case AF_INET6:
if (no_v6bind != 0) {
sep->se_fd = -1;
continue;
}
break;
#endif
}
if (!sep->se_rpc) {
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_service, sep->se_proto);
sep->se_checked = 0;
continue;
}
if (sp->s_port != sep->se_ctrladdr.sin_port) {
sep->se_ctrladdr.sin_family = AF_INET;
sep->se_ctrladdr.sin_addr = bind_address;
sep->se_ctrladdr.sin_port = sp->s_port;
if (sep->se_fd >= 0)
close_sep(sep);
switch (sep->se_family) {
case AF_INET:
if (sep->se_ctladdrinitok == 0) {
memcpy(&sep->se_ctrladdr4, bind_sa4,
sizeof(sep->se_ctrladdr4));
sep->se_ctrladdr_size =
sizeof(sep->se_ctrladdr4);
}
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 (sep->se_ctladdrinitok == 0) {
memcpy(&sep->se_ctrladdr6, bind_sa6,
sizeof(sep->se_ctrladdr6));
sep->se_ctrladdr_size =
sizeof(sep->se_ctrladdr6);
}
if (sp->s_port !=
sep->se_ctrladdr6.sin6_port) {
sep->se_ctrladdr6.sin6_port =
sp->s_port;
sep->se_reset = 1;
}
break;
#endif
}
if (sep->se_reset != 0 && sep->se_fd >= 0)
close_sep(sep);
} else {
rpc = getrpcbyname(sep->se_service);
if (rpc == 0) {
@ -950,7 +1109,7 @@ setup(sep)
{
int on = 1;
if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
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);
@ -969,13 +1128,38 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
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");
#ifdef IPV6_BINDV6ONLY
if ((sep->se_family == AF_INET6) &&
(sep->se_nomapped != 0) &&
(setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
(char *)&on, sizeof (on)) < 0))
syslog(LOG_ERR, "setsockopt (IPV6_BINDV6ONLY): %m");
#endif /* IPV6_BINDV6ONLY */
#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) {
syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
}
}
#endif
#ifdef IPSEC
ipsecsetup(sep);
#endif
if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
sizeof (sep->se_ctrladdr)) < 0) {
sep->se_ctrladdr_size) < 0) {
if (debug)
warn("bind failed on %s/%s",
sep->se_service, sep->se_proto);
@ -990,8 +1174,16 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
return;
}
if (sep->se_rpc) {
int i, len = sizeof(struct sockaddr);
int i, 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);
(void) 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",
@ -1007,9 +1199,8 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
pmap_set(sep->se_rpc_prog, i,
(sep->se_socktype == SOCK_DGRAM)
? IPPROTO_UDP : IPPROTO_TCP,
ntohs(sep->se_ctrladdr.sin_port));
ntohs(sep->se_ctrladdr4.sin_port));
}
}
if (sep->se_socktype == SOCK_STREAM)
listen(sep->se_fd, 64);
@ -1020,6 +1211,80 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
}
}
#ifdef IPSEC
void
ipsecsetup(sep)
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;
}
if (!sep->se_policy || sep->se_policy[0] == '\0') {
policy_in = "in entrust";
policy_out = "out entrust";
} 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) {
syslog(LOG_ERR,
"%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) {
syslog(LOG_ERR,
"%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);
}
}
#endif
/*
* Finish with a service and its socket.
*/
@ -1173,10 +1438,42 @@ getconfigent()
char *versp;
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
more:
while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
;
while ((cp = nextline(fconfig)) != NULL) {
#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++)
;
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);
}
}
#endif
if (*cp == '#' || *cp == '\0')
continue;
break;
}
if (cp == NULL)
return ((struct servtab *)0);
/*
@ -1216,21 +1513,29 @@ getconfigent()
sep->se_socktype = -1;
arg = sskip(&cp);
if (strcmp(arg, "tcp/ttcp") == 0) {
sep->se_type = TTCP_TYPE;
sep->se_proto = newstr("tcp");
} else {
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
sep->se_proto = newstr(arg);
}
if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
if (sep->se_family != AF_INET) {
syslog(LOG_ERR, "IPv6 for RPC is not supported yet");
freeconfig(sep);
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;
sep->se_ctrladdr.sin_family = AF_INET;
sep->se_ctrladdr.sin_port = 0;
sep->se_ctrladdr.sin_addr = bind_address;
memcpy(&sep->se_ctrladdr4, bind_sa4,
sizeof(sep->se_ctrladdr4));
if ((versp = rindex(sep->se_service, '/'))) {
*versp++ = '\0';
switch (sscanf(versp, "%d-%d",
@ -1255,6 +1560,64 @@ getconfigent()
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_INFO, "IPv6 bind is ignored for %s",
sep->se_service);
freeconfig(sep);
goto more;
}
sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
v6bind = 1;
continue;
}
#endif
if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') {
sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
v4bind = 1;
continue;
}
/* illegal version num */
syslog(LOG_ERR, "bad IP version for %s", sep->se_proto);
freeconfig(sep);
goto more;
}
#ifdef INET6
if (v6bind != 0) {
sep->se_family = AF_INET6;
if (v4bind == 0 || no_v4bind != 0)
sep->se_nomapped = 1;
}
#endif
else { /* default to v4 bind if not v6 bind */
if (no_v4bind != 0) {
syslog(LOG_INFO, "IPv4 bind is ignored for %s",
sep->se_service);
freeconfig(sep);
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);
sep->se_ctladdrinitok = 1;
break;
#ifdef INET6
case AF_INET6:
memcpy(&sep->se_ctrladdr6, bind_sa6,
sizeof(sep->se_ctrladdr6));
sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6);
sep->se_ctladdrinitok = 1;
break;
#endif
}
arg = sskip(&cp);
if (!strncmp(arg, "wait", 4))
sep->se_accept = 0;
@ -1372,6 +1735,9 @@ getconfigent()
}
while (argc <= MAXARGV)
sep->se_argv[argc++] = NULL;
#ifdef IPSEC
sep->se_policy = policy ? newstr(policy) : NULL;
#endif
return (sep);
}
@ -1400,6 +1766,10 @@ freeconfig(cp)
for (i = 0; i < MAXARGV; i++)
if (cp->se_argv[i])
free(cp->se_argv[i]);
#ifdef IPSEC
if (cp->se_policy)
free(cp->se_policy);
#endif
}
@ -1490,14 +1860,16 @@ inetd_setproctitle(a, s)
{
int size;
char *cp;
struct sockaddr_in sin;
char buf[80];
struct sockaddr_storage ss;
char buf[80], pbuf[INET6_ADDRSTRLEN];
cp = Argv[0];
size = sizeof(sin);
if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
else
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);
(void) sprintf(buf, "-%s [%s]", a, pbuf);
} else
(void) sprintf(buf, "-%s", a);
strncpy(cp, buf, LastArg - cp);
cp += strlen(cp);
@ -1511,13 +1883,15 @@ inetd_setproctitle(a, s)
int s;
{
int size;
struct sockaddr_in sin;
char buf[80];
struct sockaddr_storage ss;
char buf[80], pbuf[INET6_ADDRSTRLEN];
size = sizeof(sin);
if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
else
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);
(void) sprintf(buf, "%s [%s]", a, pbuf);
} else
(void) sprintf(buf, "%s", a);
setproctitle("%s", buf);
}
@ -1528,24 +1902,41 @@ inetd_setproctitle(a, s)
* Internet services provided internally by inetd:
*/
int check_loop(sin, sep)
struct sockaddr_in *sin;
int check_loop(sa, sep)
struct sockaddr *sa;
struct servtab *sep;
{
struct servtab *se2;
char pname[INET6_ADDRSTRLEN];
for (se2 = servtab; se2; se2 = se2->se_next) {
if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
continue;
if (sin->sin_port == se2->se_ctrladdr.sin_port) {
syslog(LOG_WARNING,
"%s/%s:%s/%s loop request REFUSED from %s",
sep->se_service, sep->se_proto,
se2->se_service, se2->se_proto,
inet_ntoa(sin->sin_addr));
return 1;
switch (se2->se_family) {
case AF_INET:
if (((struct sockaddr_in *)sa)->sin_port ==
se2->se_ctrladdr4.sin_port)
goto isloop;
continue;
#ifdef INET6
case AF_INET6:
if (((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;
}
return 0;
}
@ -1560,17 +1951,25 @@ print_service(action, sep)
struct servtab *sep;
{
fprintf(stderr,
"%s: %s proto=%s accept=%d max=%d user=%s group=%s"
#ifdef LOGIN_CAP
"%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%p server=%s\n",
#else
"%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%p server=%s\n",
"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);
(void *) sep->se_bi, sep->se_server
#ifdef IPSEC
, (sep->se_policy ? sep->se_policy : "")
#endif
);
}
#define CPMHSIZE 256
@ -1584,7 +1983,13 @@ typedef struct CTime {
} CTime;
typedef struct CHash {
struct in_addr ch_Addr;
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];
@ -1597,8 +2002,8 @@ cpmip(sep, ctrl)
struct servtab *sep;
int ctrl;
{
struct sockaddr_in rsin;
int rsinLen = sizeof(rsin);
struct sockaddr_storage rss;
int rssLen = sizeof(rss);
int r = 0;
/*
@ -1607,21 +2012,43 @@ cpmip(sep, ctrl)
*/
if (sep->se_maxcpm > 0 &&
getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 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 *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
sin = (struct sockaddr_in *)&rss;
#ifdef INET6
sin6 = (struct sockaddr_in6 *)&rss;
#endif
{
char *p;
int i;
int i, addrlen;
for (i = 0, p = (char *)&rsin.sin_addr;
i < sizeof(rsin.sin_addr);
++i, ++p) {
switch (rss.ss_family) {
case AF_INET:
p = (char *)&sin->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;
}
for (i = 0; i < addrlen; ++i, ++p) {
hv = (hv << 5) ^ (hv >> 23) ^ *p;
}
hv = (hv ^ (hv >> 16));
@ -1629,26 +2056,57 @@ cpmip(sep, ctrl)
for (i = 0; i < 5; ++i) {
CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr &&
if (rss.ss_family == AF_INET &&
ch->ch_Family == AF_INET &&
sin->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 (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr ||
if ((rss.ss_family == AF_INET &&
(chBest->ch_Family != AF_INET ||
sin->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) ||
chBest->ch_Service == NULL ||
strcmp(sep->se_service, chBest->ch_Service) != 0) {
chBest->ch_Addr = rsin.sin_addr;
chBest->ch_Family = sin->sin_family;
chBest->ch_Addr4 = sin->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];
@ -1666,10 +2124,16 @@ cpmip(sep, ctrl)
}
}
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, inet_ntoa(rsin.sin_addr),
sep->se_service, pname,
sep->se_maxcpm);
}
}

View File

@ -47,6 +47,7 @@
#define MUX_TYPE 1
#define MUXPLUS_TYPE 2
#define TTCP_TYPE 3
#define FAITH_TYPE 4
#define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \
((sep)->se_type == MUXPLUS_TYPE))
#define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE)
@ -55,6 +56,7 @@
struct servtab {
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_maxchild; /* max number of children */
int se_maxcpm; /* max connects per IP per minute */
@ -70,8 +72,19 @@ struct servtab {
char *se_server_name; /* server program without path */
#define MAXARGV 20
char *se_argv[MAXARGV+1]; /* program arguments */
#ifdef IPSEC
char *se_policy; /* IPsec poilcy string */
#endif
int se_fd; /* open descriptor */
struct sockaddr_in se_ctrladdr;/* bound address */
union { /* bound address */
struct sockaddr se_un_ctrladdr;
struct sockaddr_in se_un_ctrladdr4;
struct sockaddr_in6 se_un_ctrladdr6;
} se_un;
#define se_ctrladdr se_un.se_un_ctrladdr
#define se_ctrladdr4 se_un.se_un_ctrladdr4
#define se_ctrladdr6 se_un.se_un_ctrladdr6
int se_ctrladdr_size;
u_char se_type; /* type: normal, mux, or mux+ */
u_char se_checked; /* looked at during merge */
u_char se_accept; /* i.e., wait/nowait mode */
@ -82,8 +95,17 @@ struct servtab {
int se_count; /* number started since se_time */
struct timeval se_time; /* start of se_count */
struct servtab *se_next;
struct se_flags {
u_int se_nomapped : 1;
u_int se_ctladdrinitok : 1;
u_int se_reset : 1;
} se_flags;
};
#define se_nomapped se_flags.se_nomapped
#define se_ctladdrinitok se_flags.se_ctladdrinitok
#define se_reset se_flags.se_reset
void chargen_dg __P((int, struct servtab *));
void chargen_stream __P((int, struct servtab *));
void close_sep __P((struct servtab *));
@ -117,6 +139,9 @@ void flag_retry __P((int));
void retry __P((void));
int setconfig __P((void));
void setup __P((struct servtab *));
#ifdef IPSEC
void ipsecsetup __P((struct servtab *));
#endif
char *sskip __P((char **));
char *skip __P((char **));
struct servtab *tcpmux __P((int));