summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2000-01-14 15:45:46 +1100
committerDamien Miller <djm@mindrot.org>2000-01-14 15:45:46 +1100
commit34132e54cbd221d17d373fc54f4e3f7b85727f7f (patch)
tree7c73917b1082ff91786f9e02d25b853bedd1d472
parent25e4256ad4f453d8a7c1866243ec1984f859b1de (diff)
- Merged OpenBSD IPv6 patch:
- [sshd.c sshd.8 sshconnect.c ssh.h ssh.c servconf.h servconf.c scp.1] [scp.c packet.h packet.c login.c log.c canohost.c channels.c] [hostfile.c sshd_config] ipv6 support: mostly gethostbyname->getaddrinfo/getnameinfo, new features: sshd allows multiple ListenAddress and Port options. note that libwrap is not IPv6-ready. (based on patches from fujiwara@rcac.tdi.co.jp) - [ssh.c canohost.c] more hints (hints.ai_socktype=SOCK_STREAM) for getaddrinfo, from itojun@ - [channels.c] listen on _all_ interfaces for X11-Fwd (hints.ai_flags = AI_PASSIVE) - [packet.h] allow auth-kerberos for IPv4 only - [scp.1 sshd.8 servconf.h scp.c] document -4, -6, and 'ssh -L 2022/::1/22' - [ssh.c] 'ssh @host' is illegal (null user name), from karsten@gedankenpolizei.de - [sshconnect.c] better error message - [sshd.c] allow auth-kerberos for IPv4 only - Big IPv6 merge: - Cleanup overrun in sockaddr copying on RHL 6.1 - Replacements for getaddrinfo, getnameinfo, etc based on versions from patch from KIKUCHI Takahiro <kick@kyoto.wide.ad.jp> - Replacement for missing structures on systems that lack IPv6 - record_login needed to know about AF_INET6 addresses - Borrowed more code from OpenBSD: rresvport_af and requisites
-rw-r--r--ChangeLog33
-rw-r--r--Makefile.in62
-rw-r--r--TODO2
-rw-r--r--acconfig.h28
-rw-r--r--bsd-bindresvport.c116
-rw-r--r--bsd-bindresvport.h10
-rw-r--r--bsd-rresvport.c107
-rw-r--r--bsd-rresvport.h10
-rw-r--r--canohost.c184
-rw-r--r--channels.c388
-rw-r--r--configure.in88
-rw-r--r--defines.h4
-rw-r--r--fake-gai-errnos.h12
-rw-r--r--fake-getaddrinfo.c119
-rw-r--r--fake-getaddrinfo.h44
-rw-r--r--fake-getnameinfo.c61
-rw-r--r--fake-getnameinfo.h17
-rw-r--r--fake-socket.h49
-rwxr-xr-xfixpaths2
-rw-r--r--hostfile.c2
-rw-r--r--includes.h9
-rw-r--r--log.c2
-rw-r--r--login.c42
-rw-r--r--nchan.c30
-rw-r--r--nchan.ms9
-rw-r--r--packet.c65
-rw-r--r--packet.h6
-rw-r--r--scp.1.in12
-rw-r--r--scp.c56
-rw-r--r--servconf.c88
-rw-r--r--servconf.h12
-rw-r--r--ssh.1.in22
-rw-r--r--ssh.c54
-rw-r--r--ssh.h17
-rw-r--r--sshconnect.c207
-rw-r--r--sshd.8.in17
-rw-r--r--sshd.c249
-rw-r--r--sshd_config.in1
38 files changed, 1633 insertions, 603 deletions
diff --git a/ChangeLog b/ChangeLog
index e96dfb803..701bf403f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
120000114
2 - Merged OpenBSD IPv6 patch:
3 - [sshd.c sshd.8 sshconnect.c ssh.h ssh.c servconf.h servconf.c scp.1]
4 [scp.c packet.h packet.c login.c log.c canohost.c channels.c]
5 [hostfile.c sshd_config]
6 ipv6 support: mostly gethostbyname->getaddrinfo/getnameinfo, new
7 features: sshd allows multiple ListenAddress and Port options. note
8 that libwrap is not IPv6-ready. (based on patches from
9 fujiwara@rcac.tdi.co.jp)
10 - [ssh.c canohost.c]
11 more hints (hints.ai_socktype=SOCK_STREAM) for getaddrinfo,
12 from itojun@
13 - [channels.c]
14 listen on _all_ interfaces for X11-Fwd (hints.ai_flags = AI_PASSIVE)
15 - [packet.h]
16 allow auth-kerberos for IPv4 only
17 - [scp.1 sshd.8 servconf.h scp.c]
18 document -4, -6, and 'ssh -L 2022/::1/22'
19 - [ssh.c]
20 'ssh @host' is illegal (null user name), from
21 karsten@gedankenpolizei.de
22 - [sshconnect.c]
23 better error message
24 - [sshd.c]
25 allow auth-kerberos for IPv4 only
26 - Big IPv6 merge:
27 - Cleanup overrun in sockaddr copying on RHL 6.1
28 - Replacements for getaddrinfo, getnameinfo, etc based on versions
29 from patch from KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
30 - Replacement for missing structures on systems that lack IPv6
31 - record_login needed to know about AF_INET6 addresses
32 - Borrowed more code from OpenBSD: rresvport_af and requisites
33
120000110 3420000110
2 - Fixes to auth-skey to enable it to use the standard OpenSSL libraries 35 - Fixes to auth-skey to enable it to use the standard OpenSSL libraries
3 36
diff --git a/Makefile.in b/Makefile.in
index 23f005822..786cd4368 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -19,7 +19,6 @@ CC=@CC@
19PATHS=-DETCDIR=\"$(sysconfdir)\" -DSSH_PROGRAM=\"$(SSH_PROGRAM)\" -DSSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" 19PATHS=-DETCDIR=\"$(sysconfdir)\" -DSSH_PROGRAM=\"$(SSH_PROGRAM)\" -DSSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\"
20CFLAGS=@CFLAGS@ $(PATHS) @DEFS@ 20CFLAGS=@CFLAGS@ $(PATHS) @DEFS@
21EXTRA_TARGETS=@GNOME_ASKPASS@ 21EXTRA_TARGETS=@GNOME_ASKPASS@
22TARGETS=libssh.a ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
23LIBS=@LIBS@ 22LIBS=@LIBS@
24AR=@AR@ 23AR=@AR@
25RANLIB=@RANLIB@ 24RANLIB=@RANLIB@
@@ -30,34 +29,19 @@ LDFLAGS=-L. @LDFLAGS@
30GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui` 29GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui`
31GNOME_LIBS=`gnome-config --libs gnome gnomeui` 30GNOME_LIBS=`gnome-config --libs gnome gnomeui`
32 31
33OBJS= atomicio.o authfd.o authfile.o auth-krb4.o auth-passwd.o auth-pam.o \ 32TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
34 auth-rhosts.o auth-rh-rsa.o auth-rsa.o auth-skey.o bsd-daemon.o \ 33
35 bsd-login.o bsd-misc.o bsd-mktemp.o bsd-snprintf.o bsd-strlcat.o \ 34LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o log.o match.o mpaux.o nchan.o packet.o radix.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o
36 bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o \
37 clientloop.o compress.o crc32.o deattack.o hostfile.o \
38 log-client.o login.o log-server.o match.o md5crypt.o mpaux.o \
39 packet.o pty.o radix.o readconf.o readpass.o rsa.o servconf.o \
40 serverloop.o sshconnect.o tildexpand.o ttymodes.o uidswap.o \
41 xmalloc.o
42
43LIBOBJS= atomicio.o authfd.o authfile.o bsd-daemon.o bsd-misc.o \
44 bsd-mktemp.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o \
45 buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o \
46 deattack.o fingerprint.o hostfile.o log.o match.o mpaux.o nchan.o \
47 packet.o radix.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o \
48 xmalloc.o
49 35
50SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o 36SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o
51 37
52SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o \ 38SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o bsd-login.o md5crypt.o
53 auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o \
54 serverloop.o bsd-login.o md5crypt.o
55 39
56MANPAGES=scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 40MANPAGES=scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8
57 41
58CONFIGFILES=sshd_config ssh_config 42CONFIGFILES=sshd_config ssh_config
59 43
60all: $(OBJS) $(TARGETS) $(MANPAGES) $(CONFIGFILES) 44all: $(TARGETS) $(MANPAGES) $(CONFIGFILES)
61 45
62$(OBJS): config.h 46$(OBJS): config.h
63 47
@@ -67,31 +51,27 @@ libssh.a: $(LIBOBJS)
67 $(AR) rv $@ $(LIBOBJS) 51 $(AR) rv $@ $(LIBOBJS)
68 $(RANLIB) $@ 52 $(RANLIB) $@
69 53
70ssh: $(SSHOBJS) libssh.a 54ssh: libssh.a $(SSHOBJS)
71 $(CC) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh $(LIBS) 55 $(CC) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh $(LIBS)
72 56
73sshd: $(SSHDOBJS) libssh.a 57sshd: libssh.a $(SSHDOBJS)
74 $(CC) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh $(LIBS) 58 $(CC) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh $(LIBS)
75 59
76scp: scp.o libssh.a 60scp: libssh.a scp.o
77 $(CC) -o $@ scp.o $(LDFLAGS) -lssh $(LIBS) 61 $(CC) -o $@ scp.o $(LDFLAGS) -lssh $(LIBS)
78 62
79ssh-add: ssh-add.o log-client.o libssh.a 63ssh-add: libssh.a ssh-add.o log-client.o
80 $(CC) -o $@ ssh-add.o log-client.o $(LDFLAGS) -lssh $(LIBS) 64 $(CC) -o $@ ssh-add.o log-client.o $(LDFLAGS) -lssh $(LIBS)
81 65
82ssh-agent: ssh-agent.o log-client.o libssh.a 66ssh-agent: libssh.a ssh-agent.o log-client.o
83 $(CC) -o $@ ssh-agent.o log-client.o $(LDFLAGS) -lssh $(LIBS) 67 $(CC) -o $@ ssh-agent.o log-client.o $(LDFLAGS) -lssh $(LIBS)
84 68
85ssh-keygen: ssh-keygen.o log-client.o libssh.a 69ssh-keygen: libssh.a ssh-keygen.o log-client.o
86 $(CC) -o $@ ssh-keygen.o log-client.o $(LDFLAGS) -lssh $(LIBS) 70 $(CC) -o $@ ssh-keygen.o log-client.o $(LDFLAGS) -lssh $(LIBS)
87 71
88gnome-ssh-askpass: gnome-ssh-askpass.c 72gnome-ssh-askpass: gnome-ssh-askpass.c
89 $(CC) $(CFLAGS) $(GNOME_CFLAGS) -o $@ gnome-ssh-askpass.c $(GNOME_LIBS) 73 $(CC) $(CFLAGS) $(GNOME_CFLAGS) -o $@ gnome-ssh-askpass.c $(GNOME_LIBS)
90 74
91clean:
92 rm -f *.o $(TARGETS) config.status config.cache config.log core \
93 *.1 *.8 sshd_config ssh_config
94
95scp.1: scp.1.in 75scp.1: scp.1.in
96 $(PERL) $(FIXPATHS) -Dsysconfdir=${sysconfdir} $(srcdir)/scp.1.in 76 $(PERL) $(FIXPATHS) -Dsysconfdir=${sysconfdir} $(srcdir)/scp.1.in
97 77
@@ -116,6 +96,18 @@ sshd_config: sshd_config.in
116ssh_config: ssh_config.in 96ssh_config: ssh_config.in
117 $(PERL) $(FIXPATHS) -Dsysconfdir=${sysconfdir} ssh_config.in 97 $(PERL) $(FIXPATHS) -Dsysconfdir=${sysconfdir} ssh_config.in
118 98
99clean:
100 rm -f *.o *.a $(TARGETS) config.status config.cache config.log
101 rm -f core *.1 *.8 sshd_config ssh_config
102
103distclean: clean
104 rm -f Makefile config.h core *~
105
106mrproper: distclean
107
108veryclean: distclean
109 rm -f configure config.h.in
110
119install: $(TARGETS) 111install: $(TARGETS)
120 $(INSTALL) -d $(bindir) 112 $(INSTALL) -d $(bindir)
121 $(INSTALL) -d $(sbindir) 113 $(INSTALL) -d $(sbindir)
@@ -180,11 +172,3 @@ uninstall:
180 -rm -f ${ASKPASS_PROGRAM} 172 -rm -f ${ASKPASS_PROGRAM}
181 -rmdir $(libexecdir)/ssh ; 173 -rmdir $(libexecdir)/ssh ;
182 174
183distclean: clean
184 rm -f Makefile config.h core *~
185
186mrproper: distclean
187
188veryclean: distclean
189 rm -f configure config.h.in
190
diff --git a/TODO b/TODO
index e3249fd15..0eccc9be4 100644
--- a/TODO
+++ b/TODO
@@ -7,6 +7,8 @@
7- Replace the horror in acconfig.h which tries to comphensate for the 7- Replace the horror in acconfig.h which tries to comphensate for the
8 lack of u_intXX_t types. There must be a better way. 8 lack of u_intXX_t types. There must be a better way.
9 9
10- Move all compatability cruft (bsd-*, fake-*) into subordinate library
11
10- Hanging on logout: 12- Hanging on logout:
11 13
12localhost$ ssh remotehost 14localhost$ ssh remotehost
diff --git a/acconfig.h b/acconfig.h
index e61bfd33a..52aef76a6 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -40,31 +40,17 @@
40 * message at run-time. */ 40 * message at run-time. */
41#undef RSAREF 41#undef RSAREF
42 42
43/* Define is utmp.h has a ut_host field */ 43/* struct utmp and struct utmpx fields */
44#undef HAVE_HOST_IN_UTMP 44#undef HAVE_HOST_IN_UTMP
45
46/* Define is utmpx.h has a ut_host field */
47#undef HAVE_HOST_IN_UTMPX 45#undef HAVE_HOST_IN_UTMPX
48
49/* Define is utmp.h has a ut_addr field */
50#undef HAVE_ADDR_IN_UTMP 46#undef HAVE_ADDR_IN_UTMP
51
52/* Define is utmpx.h has a ut_addr field */
53#undef HAVE_ADDR_IN_UTMPX 47#undef HAVE_ADDR_IN_UTMPX
54 48#undef HAVE_ADDR_V6_IN_UTMP
55/* Define is utmpx.h has a syslen field */ 49#undef HAVE_ADDR_V6_IN_UTMPX
56#undef HAVE_SYSLEN_IN_UTMPX 50#undef HAVE_SYSLEN_IN_UTMPX
57
58/* Define is utmp.h has a ut_pid field */
59#undef HAVE_PID_IN_UTMP 51#undef HAVE_PID_IN_UTMP
60
61/* Define is utmp.h has a ut_type field */
62#undef HAVE_TYPE_IN_UTMP 52#undef HAVE_TYPE_IN_UTMP
63
64/* Define is utmp.h has a ut_tv field */
65#undef HAVE_TV_IN_UTMP 53#undef HAVE_TV_IN_UTMP
66
67/* Define is utmp.h has a ut_id field */
68#undef HAVE_ID_IN_UTMP 54#undef HAVE_ID_IN_UTMP
69 55
70/* Define if you want to use utmpx */ 56/* Define if you want to use utmpx */
@@ -125,6 +111,14 @@
125#undef HAVE_UINTXX_T 111#undef HAVE_UINTXX_T
126#undef HAVE_SOCKLEN_T 112#undef HAVE_SOCKLEN_T
127#undef HAVE_SIZE_T 113#undef HAVE_SIZE_T
114#undef HAVE_STRUCT_SOCKADDR_STORAGE
115#undef HAVE_STRUCT_ADDRINFO
116#undef HAVE_STRUCT_IN6_ADDR
117#undef HAVE_STRUCT_SOCKADDR_IN6
118
119/* Fields in struct sockaddr_storage */
120#undef HAVE_SS_FAMILY_IN_SS
121#undef HAVE___SS_FAMILY_IN_SS
128 122
129/* Define if you have /dev/ptmx */ 123/* Define if you have /dev/ptmx */
130#undef HAVE_DEV_PTMX 124#undef HAVE_DEV_PTMX
diff --git a/bsd-bindresvport.c b/bsd-bindresvport.c
new file mode 100644
index 000000000..3ea37ee52
--- /dev/null
+++ b/bsd-bindresvport.c
@@ -0,0 +1,116 @@
1/*
2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
8 *
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12 *
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
16 *
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
20 *
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
24 *
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California 94043
28 */
29
30#include "config.h"
31
32#ifndef HAVE_BINRESVPORT_AF
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char *rcsid = "$OpenBSD: bindresvport.c,v 1.11 1999/12/17 19:22:08 deraadt Exp $";
36#endif /* LIBC_SCCS and not lint */
37
38/*
39 * Copyright (c) 1987 by Sun Microsystems, Inc.
40 *
41 * Portions Copyright(C) 1996, Jason Downs. All rights reserved.
42 */
43
44#include "includes.h"
45
46#define STARTPORT 600
47#define ENDPORT (IPPORT_RESERVED - 1)
48#define NPORTS (ENDPORT - STARTPORT + 1)
49
50#if 0
51/*
52 * Bind a socket to a privileged IP port
53 */
54int
55bindresvport(sd, sin)
56 int sd;
57 struct sockaddr_in *sin;
58{
59 return bindresvport_af(sd, (struct sockaddr *)sin, AF_INET);
60}
61#endif
62
63/*
64 * Bind a socket to a privileged IP port
65 */
66int
67bindresvport_af(sd, sa, af)
68 int sd;
69 struct sockaddr *sa;
70 int af;
71{
72 int error;
73 struct sockaddr_storage myaddr;
74 struct sockaddr_in *sin;
75 struct sockaddr_in6 *sin6;
76 u_int16_t *portp;
77 int salen;
78 int i;
79
80 if (sa == NULL) {
81 memset(&myaddr, 0, sizeof(myaddr));
82 sa = (struct sockaddr *)&myaddr;
83 }
84
85 if (af == AF_INET) {
86 sin = (struct sockaddr_in *)sa;
87 salen = sizeof(struct sockaddr_in);
88 portp = &sin->sin_port;
89 } else if (af == AF_INET6) {
90 sin6 = (struct sockaddr_in6 *)sa;
91 salen = sizeof(struct sockaddr_in6);
92 portp = &sin6->sin6_port;
93 } else {
94 errno = EPFNOSUPPORT;
95 return (-1);
96 }
97 sa->sa_family = af;
98
99 if (*portp == 0)
100 *portp = (getpid() % NPORTS) + STARTPORT;
101
102 for(i = 0; i < NPORTS; i++) {
103 error = bind(sd, sa, salen);
104
105 if ((error == 0) || ((error < 0) && (errno != EADDRINUSE)))
106 break;
107
108 (*portp)++;
109 if (*portp < ENDPORT)
110 *portp = STARTPORT;
111 }
112
113 return (error);
114}
115
116#endif /* HAVE_BINRESVPORT_AF */
diff --git a/bsd-bindresvport.h b/bsd-bindresvport.h
new file mode 100644
index 000000000..df084e3dc
--- /dev/null
+++ b/bsd-bindresvport.h
@@ -0,0 +1,10 @@
1#ifndef _BSD_BINRESVPORT_H
2#define _BSD_BINRESVPORT_H
3
4#include "config.h"
5
6#ifndef HAVE_BINRESVPORT_AF
7int bindresvport_af(int sd, struct sockaddr *sa, int af);
8#endif /* !HAVE_BINRESVPORT_AF */
9
10#endif /* _BSD_BINRESVPORT_H */
diff --git a/bsd-rresvport.c b/bsd-rresvport.c
new file mode 100644
index 000000000..c29165faa
--- /dev/null
+++ b/bsd-rresvport.c
@@ -0,0 +1,107 @@
1/*
2 * Copyright (c) 1995, 1996, 1998 Theo de Raadt. All rights reserved.
3 * Copyright (c) 1983, 1993, 1994
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * This product includes software developed by Theo de Raadt.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "config.h"
37
38#ifndef HAVE_RRESVPORT_AF
39
40#if defined(LIBC_SCCS) && !defined(lint)
41static char *rcsid = "$OpenBSD: rresvport.c,v 1.4 1999/12/17 20:48:03 deraadt Exp $";
42#endif /* LIBC_SCCS and not lint */
43
44#include "includes.h"
45
46#if 0
47int
48rresvport(alport)
49 int *alport;
50{
51 return rresvport_af(alport, AF_INET);
52}
53#endif
54
55int
56rresvport_af(alport, af)
57 int *alport;
58 int af;
59{
60 struct sockaddr_storage ss;
61 struct sockaddr *sa;
62 u_int16_t *portp;
63 int s;
64 int sa_len;
65
66 bzero(&ss, sizeof ss);
67 sa = (struct sockaddr *)&ss;
68
69 switch (af) {
70 case AF_INET:
71 sa_len = sizeof(struct sockaddr_in);
72 portp = &((struct sockaddr_in *)sa)->sin_port;
73 break;
74 case AF_INET6:
75 sa_len = sizeof(struct sockaddr_in6);
76 portp = &((struct sockaddr_in6 *)sa)->sin6_port;
77 break;
78 default:
79 errno = EPFNOSUPPORT;
80 return (-1);
81 }
82 sa->sa_family = af;
83
84 s = socket(af, SOCK_STREAM, 0);
85 if (s < 0)
86 return (-1);
87
88 *portp = htons(*alport);
89 if (*alport < IPPORT_RESERVED - 1) {
90 if (bind(s, sa, sa_len) >= 0)
91 return (s);
92 if (errno != EADDRINUSE) {
93 (void)close(s);
94 return (-1);
95 }
96 }
97
98 *portp = 0;
99 if (bindresvport_af(s, sa, af) == -1) {
100 (void)close(s);
101 return (-1);
102 }
103 *alport = ntohs(*portp);
104 return (s);
105}
106
107#endif /* HAVE_RRESVPORT_AF */
diff --git a/bsd-rresvport.h b/bsd-rresvport.h
new file mode 100644
index 000000000..69d6bbd9f
--- /dev/null
+++ b/bsd-rresvport.h
@@ -0,0 +1,10 @@
1#ifndef _BSD_RRESVPORT_H
2#define _BSD_RRESVPORT_H
3
4#include "config.h"
5
6#ifndef HAVE_RRESVPORT_AF
7int rresvport_af(int *alport, int af);
8#endif /* !HAVE_RRESVPORT_AF */
9
10#endif /* _BSD_RRESVPORT_H */
diff --git a/canohost.c b/canohost.c
index edfaa94e1..9a6d8b732 100644
--- a/canohost.c
+++ b/canohost.c
@@ -14,7 +14,7 @@
14 */ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: canohost.c,v 1.6 1999/12/18 09:57:40 damien Exp $"); 17RCSID("$Id: canohost.c,v 1.7 2000/01/14 04:45:48 damien Exp $");
18 18
19#include "packet.h" 19#include "packet.h"
20#include "xmalloc.h" 20#include "xmalloc.h"
@@ -28,10 +28,12 @@ RCSID("$Id: canohost.c,v 1.6 1999/12/18 09:57:40 damien Exp $");
28char * 28char *
29get_remote_hostname(int socket) 29get_remote_hostname(int socket)
30{ 30{
31 struct sockaddr_in from; 31 struct sockaddr_storage from;
32 int fromlen, i; 32 int i;
33 struct hostent *hp; 33 socklen_t fromlen;
34 struct addrinfo hints, *ai, *aitop;
34 char name[MAXHOSTNAMELEN]; 35 char name[MAXHOSTNAMELEN];
36 char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
35 37
36 /* Get IP address of client. */ 38 /* Get IP address of client. */
37 fromlen = sizeof(from); 39 fromlen = sizeof(from);
@@ -40,20 +42,15 @@ get_remote_hostname(int socket)
40 debug("getpeername failed: %.100s", strerror(errno)); 42 debug("getpeername failed: %.100s", strerror(errno));
41 fatal_cleanup(); 43 fatal_cleanup();
42 } 44 }
43 /* Map the IP address to a host name. */ 45 if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
44 hp = gethostbyaddr((char *) &from.sin_addr, sizeof(struct in_addr), 46 NULL, 0, NI_NUMERICHOST) != 0)
45 from.sin_family); 47 fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
46 if (hp) {
47 /* Got host name, find canonic host name. */
48 if (strchr(hp->h_name, '.') != 0)
49 strlcpy(name, hp->h_name, sizeof(name));
50 else if (hp->h_aliases != 0
51 && hp->h_aliases[0] != 0
52 && strchr(hp->h_aliases[0], '.') != 0)
53 strlcpy(name, hp->h_aliases[0], sizeof(name));
54 else
55 strlcpy(name, hp->h_name, sizeof(name));
56 48
49 /* Map the IP address to a host name. */
50 if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
51 NULL, 0, NI_NAMEREQD) == 0) {
52 /* Got host name. */
53 name[sizeof(name) - 1] = '\0';
57 /* 54 /*
58 * Convert it to all lowercase (which is expected by the rest 55 * Convert it to all lowercase (which is expected by the rest
59 * of this software). 56 * of this software).
@@ -71,32 +68,34 @@ get_remote_hostname(int socket)
71 * fooled if the intruder has access to the name server of 68 * fooled if the intruder has access to the name server of
72 * the domain). 69 * the domain).
73 */ 70 */
74 hp = gethostbyname(name); 71 memset(&hints, 0, sizeof(hints));
75 if (!hp) { 72 hints.ai_family = from.ss_family;
76 log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); 73 hints.ai_socktype = SOCK_STREAM;
77 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 74 if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
75 log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
76 strlcpy(name, ntop, sizeof name);
78 goto check_ip_options; 77 goto check_ip_options;
79 } 78 }
80 /* Look for the address from the list of addresses. */ 79 /* Look for the address from the list of addresses. */
81 for (i = 0; hp->h_addr_list[i]; i++) 80 for (ai = aitop; ai; ai = ai->ai_next) {
82 if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr)) 81 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
83 == 0) 82 sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
84 break; 83 (strcmp(ntop, ntop2) == 0))
85 /* 84 break;
86 * If we reached the end of the list, the address was not 85 }
87 * there. 86 freeaddrinfo(aitop);
88 */ 87 /* If we reached the end of the list, the address was not there. */
89 if (!hp->h_addr_list[i]) { 88 if (!ai) {
90 /* Address not found for the host name. */ 89 /* Address not found for the host name. */
91 log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!", 90 log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
92 inet_ntoa(from.sin_addr), name); 91 ntop, name);
93 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 92 strlcpy(name, ntop, sizeof name);
94 goto check_ip_options; 93 goto check_ip_options;
95 } 94 }
96 /* Address was found for the host name. We accept the host name. */ 95 /* Address was found for the host name. We accept the host name. */
97 } else { 96 } else {
98 /* Host name not found. Use ascii representation of the address. */ 97 /* Host name not found. Use ascii representation of the address. */
99 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 98 strlcpy(name, ntop, sizeof name);
100 log("Could not reverse map address %.100s.", name); 99 log("Could not reverse map address %.100s.", name);
101 } 100 }
102 101
@@ -113,10 +112,12 @@ check_ip_options:
113 * rest of the interaction and could still bypass security. So we 112 * rest of the interaction and could still bypass security. So we
114 * exit here if we detect any IP options. 113 * exit here if we detect any IP options.
115 */ 114 */
116 { 115 /* IP options -- IPv4 only */
116 if (from.ss_family == AF_INET) {
117 unsigned char options[200], *ucp; 117 unsigned char options[200], *ucp;
118 char text[1024], *cp; 118 char text[1024], *cp;
119 int option_size, ipproto; 119 socklen_t option_size;
120 int ipproto;
120 struct protoent *ip; 121 struct protoent *ip;
121 122
122 if ((ip = getprotobyname("ip")) != NULL) 123 if ((ip = getprotobyname("ip")) != NULL)
@@ -125,47 +126,21 @@ check_ip_options:
125 ipproto = IPPROTO_IP; 126 ipproto = IPPROTO_IP;
126 option_size = sizeof(options); 127 option_size = sizeof(options);
127 if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options, 128 if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options,
128 &option_size) >= 0 && option_size != 0) { 129 &option_size) >= 0 && option_size != 0) {
129 cp = text; 130 cp = text;
130 /* Note: "text" buffer must be at least 3x as big as options. */ 131 /* Note: "text" buffer must be at least 3x as big as options. */
131 for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3) 132 for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
132 sprintf(cp, " %2.2x", *ucp); 133 sprintf(cp, " %2.2x", *ucp);
133 log("Connection from %.100s with IP options:%.800s", 134 log("Connection from %.100s with IP options:%.800s",
134 inet_ntoa(from.sin_addr), text); 135 ntop, text);
135 packet_disconnect("Connection from %.100s with IP options:%.800s", 136 packet_disconnect("Connection from %.100s with IP options:%.800s",
136 inet_ntoa(from.sin_addr), text); 137 ntop, text);
137 } 138 }
138 } 139 }
139 140
140 return xstrdup(name); 141 return xstrdup(name);
141} 142}
142 143
143static char *canonical_host_name = NULL;
144static char *canonical_host_ip = NULL;
145
146/* Returns 1 if remote host is connected via socket, 0 if not. */
147
148int
149peer_connection_is_on_socket()
150{
151 struct sockaddr_in from;
152 int fromlen;
153 int in = packet_get_connection_in();
154 int out = packet_get_connection_out();
155
156 /* filedescriptors in and out are the same, so it's a socket */
157 if (in == out)
158 return 1;
159 fromlen = sizeof(from);
160 memset(&from, 0, sizeof(from));
161 if (getpeername(in, (struct sockaddr *) & from, &fromlen) < 0)
162 return 0;
163 if (from.sin_family != AF_INET)
164 return 0;
165
166 return 1;
167}
168
169/* 144/*
170 * Return the canonical name of the host in the other side of the current 145 * Return the canonical name of the host in the other side of the current
171 * connection. The host name is cached, so it is efficient to call this 146 * connection. The host name is cached, so it is efficient to call this
@@ -175,12 +150,14 @@ peer_connection_is_on_socket()
175const char * 150const char *
176get_canonical_hostname() 151get_canonical_hostname()
177{ 152{
153 static char *canonical_host_name = NULL;
154
178 /* Check if we have previously retrieved this same name. */ 155 /* Check if we have previously retrieved this same name. */
179 if (canonical_host_name != NULL) 156 if (canonical_host_name != NULL)
180 return canonical_host_name; 157 return canonical_host_name;
181 158
182 /* Get the real hostname if socket; otherwise return UNKNOWN. */ 159 /* Get the real hostname if socket; otherwise return UNKNOWN. */
183 if (peer_connection_is_on_socket()) 160 if (packet_connection_is_on_socket())
184 canonical_host_name = get_remote_hostname(packet_get_connection_in()); 161 canonical_host_name = get_remote_hostname(packet_get_connection_in());
185 else 162 else
186 canonical_host_name = xstrdup("UNKNOWN"); 163 canonical_host_name = xstrdup("UNKNOWN");
@@ -190,21 +167,24 @@ get_canonical_hostname()
190 167
191/* 168/*
192 * Returns the IP-address of the remote host as a string. The returned 169 * Returns the IP-address of the remote host as a string. The returned
193 * string need not be freed. 170 * string must not be freed.
194 */ 171 */
195 172
196const char * 173const char *
197get_remote_ipaddr() 174get_remote_ipaddr()
198{ 175{
199 struct sockaddr_in from; 176 static char *canonical_host_ip = NULL;
200 int fromlen, socket; 177 struct sockaddr_storage from;
178 socklen_t fromlen;
179 int socket;
180 char ntop[NI_MAXHOST];
201 181
202 /* Check whether we have chached the name. */ 182 /* Check whether we have chached the name. */
203 if (canonical_host_ip != NULL) 183 if (canonical_host_ip != NULL)
204 return canonical_host_ip; 184 return canonical_host_ip;
205 185
206 /* If not a socket, return UNKNOWN. */ 186 /* If not a socket, return UNKNOWN. */
207 if (!peer_connection_is_on_socket()) { 187 if (!packet_connection_is_on_socket()) {
208 canonical_host_ip = xstrdup("UNKNOWN"); 188 canonical_host_ip = xstrdup("UNKNOWN");
209 return canonical_host_ip; 189 return canonical_host_ip;
210 } 190 }
@@ -219,48 +199,76 @@ get_remote_ipaddr()
219 fatal_cleanup(); 199 fatal_cleanup();
220 } 200 }
221 /* Get the IP address in ascii. */ 201 /* Get the IP address in ascii. */
222 canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr)); 202 if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
203 NULL, 0, NI_NUMERICHOST) != 0)
204 fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
205
206 canonical_host_ip = xstrdup(ntop);
223 207
224 /* Return ip address string. */ 208 /* Return ip address string. */
225 return canonical_host_ip; 209 return canonical_host_ip;
226} 210}
227 211
228/* Returns the port of the peer of the socket. */ 212/* Returns the local/remote port for the socket. */
229 213
230int 214int
231get_peer_port(int sock) 215get_sock_port(int sock, int local)
232{ 216{
233 struct sockaddr_in from; 217 struct sockaddr_storage from;
234 int fromlen; 218 socklen_t fromlen;
219 char strport[NI_MAXSERV];
235 220
236 /* Get IP address of client. */ 221 /* Get IP address of client. */
237 fromlen = sizeof(from); 222 fromlen = sizeof(from);
238 memset(&from, 0, sizeof(from)); 223 memset(&from, 0, sizeof(from));
239 if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) { 224 if (local) {
240 debug("getpeername failed: %.100s", strerror(errno)); 225 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
241 fatal_cleanup(); 226 error("getsockname failed: %.100s", strerror(errno));
227 return 0;
228 }
229 } else {
230 if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
231 debug("getpeername failed: %.100s", strerror(errno));
232 fatal_cleanup();
233 }
242 } 234 }
243 /* Return port number. */ 235 /* Return port number. */
244 return ntohs(from.sin_port); 236 if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
237 strport, sizeof(strport), NI_NUMERICSERV) != 0)
238 fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
239 return atoi(strport);
245} 240}
246 241
247/* Returns the port number of the remote host. */ 242/* Returns remote/local port number for the current connection. */
248 243
249int 244int
250get_remote_port() 245get_port(int local)
251{ 246{
252 int socket;
253
254 /* 247 /*
255 * If the connection is not a socket, return 65535. This is 248 * If the connection is not a socket, return 65535. This is
256 * intentionally chosen to be an unprivileged port number. 249 * intentionally chosen to be an unprivileged port number.
257 */ 250 */
258 if (!peer_connection_is_on_socket()) 251 if (!packet_connection_is_on_socket())
259 return 65535; 252 return 65535;
260 253
261 /* Get client socket. */ 254 /* Get socket and return the port number. */
262 socket = packet_get_connection_in(); 255 return get_sock_port(packet_get_connection_in(), local);
256}
257
258int
259get_peer_port(int sock)
260{
261 return get_sock_port(sock, 0);
262}
263 263
264 /* Get and return the peer port number. */ 264int
265 return get_peer_port(socket); 265get_remote_port()
266{
267 return get_port(0);
268}
269
270int
271get_local_port()
272{
273 return get_port(1);
266} 274}
diff --git a/channels.c b/channels.c
index 8455518e2..c4f54a88f 100644
--- a/channels.c
+++ b/channels.c
@@ -16,7 +16,7 @@
16 */ 16 */
17 17
18#include "includes.h" 18#include "includes.h"
19RCSID("$Id: channels.c,v 1.14 1999/12/27 12:54:55 damien Exp $"); 19RCSID("$Id: channels.c,v 1.15 2000/01/14 04:45:48 damien Exp $");
20 20
21#include "ssh.h" 21#include "ssh.h"
22#include "packet.h" 22#include "packet.h"
@@ -374,7 +374,8 @@ void
374channel_after_select(fd_set * readset, fd_set * writeset) 374channel_after_select(fd_set * readset, fd_set * writeset)
375{ 375{
376 struct sockaddr addr; 376 struct sockaddr addr;
377 int addrlen, newsock, i, newch, len; 377 int newsock, i, newch, len;
378 socklen_t addrlen;
378 Channel *ch; 379 Channel *ch;
379 char buf[16384], *remote_hostname; 380 char buf[16384], *remote_hostname;
380 381
@@ -412,7 +413,7 @@ channel_after_select(fd_set * readset, fd_set * writeset)
412 * forwarded TCP/IP port. 413 * forwarded TCP/IP port.
413 */ 414 */
414 if (FD_ISSET(ch->sock, readset)) { 415 if (FD_ISSET(ch->sock, readset)) {
415 debug("Connection to port %d forwarding to %.100s:%d requested.", 416 debug("Connection to port %d forwarding to %.100s port %d requested.",
416 ch->listening_port, ch->path, ch->host_port); 417 ch->listening_port, ch->path, ch->host_port);
417 addrlen = sizeof(addr); 418 addrlen = sizeof(addr);
418 newsock = accept(ch->sock, &addr, &addrlen); 419 newsock = accept(ch->sock, &addr, &addrlen);
@@ -421,7 +422,7 @@ channel_after_select(fd_set * readset, fd_set * writeset)
421 break; 422 break;
422 } 423 }
423 remote_hostname = get_remote_hostname(newsock); 424 remote_hostname = get_remote_hostname(newsock);
424 snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d", 425 snprintf(buf, sizeof buf, "listen port %d for %.100s port %d, connect from %.200s port %d",
425 ch->listening_port, ch->path, ch->host_port, 426 ch->listening_port, ch->path, ch->host_port,
426 remote_hostname, get_peer_port(newsock)); 427 remote_hostname, get_peer_port(newsock));
427 xfree(remote_hostname); 428 xfree(remote_hostname);
@@ -532,10 +533,19 @@ channel_output_poll()
532 533
533 for (i = 0; i < channels_alloc; i++) { 534 for (i = 0; i < channels_alloc; i++) {
534 ch = &channels[i]; 535 ch = &channels[i];
536
535 /* We are only interested in channels that can have buffered incoming data. */ 537 /* We are only interested in channels that can have buffered incoming data. */
536 if (ch->type != SSH_CHANNEL_OPEN && 538 if (compat13) {
537 ch->type != SSH_CHANNEL_INPUT_DRAINING) 539 if (ch->type != SSH_CHANNEL_OPEN &&
538 continue; 540 ch->type != SSH_CHANNEL_INPUT_DRAINING)
541 continue;
542 } else {
543 if (ch->type != SSH_CHANNEL_OPEN)
544 continue;
545 if (ch->istate != CHAN_INPUT_OPEN &&
546 ch->istate != CHAN_INPUT_WAIT_DRAIN)
547 continue;
548 }
539 549
540 /* Get the amount of buffered data for this channel. */ 550 /* Get the amount of buffered data for this channel. */
541 len = buffer_len(&ch->input); 551 len = buffer_len(&ch->input);
@@ -575,25 +585,33 @@ channel_output_poll()
575void 585void
576channel_input_data(int payload_len) 586channel_input_data(int payload_len)
577{ 587{
578 int channel; 588 int id;
579 char *data; 589 char *data;
580 unsigned int data_len; 590 unsigned int data_len;
591 Channel *ch;
581 592
582 /* Get the channel number and verify it. */ 593 /* Get the channel number and verify it. */
583 channel = packet_get_int(); 594 id = packet_get_int();
584 if (channel < 0 || channel >= channels_alloc || 595 if (id < 0 || id >= channels_alloc)
585 channels[channel].type == SSH_CHANNEL_FREE) 596 packet_disconnect("Received data for nonexistent channel %d.", id);
586 packet_disconnect("Received data for nonexistent channel %d.", channel); 597 ch = &channels[id];
598
599 if (ch->type == SSH_CHANNEL_FREE)
600 packet_disconnect("Received data for free channel %d.", ch->self);
587 601
588 /* Ignore any data for non-open channels (might happen on close) */ 602 /* Ignore any data for non-open channels (might happen on close) */
589 if (channels[channel].type != SSH_CHANNEL_OPEN && 603 if (ch->type != SSH_CHANNEL_OPEN &&
590 channels[channel].type != SSH_CHANNEL_X11_OPEN) 604 ch->type != SSH_CHANNEL_X11_OPEN)
605 return;
606
607 /* same for protocol 1.5 if output end is no longer open */
608 if (!compat13 && ch->ostate != CHAN_OUTPUT_OPEN)
591 return; 609 return;
592 610
593 /* Get the data. */ 611 /* Get the data. */
594 data = packet_get_string(&data_len); 612 data = packet_get_string(&data_len);
595 packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA); 613 packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA);
596 buffer_append(&channels[channel].output, data, data_len); 614 buffer_append(&ch->output, data, data_len);
597 xfree(data); 615 xfree(data);
598} 616}
599 617
@@ -610,23 +628,11 @@ channel_not_very_much_buffered_data()
610 628
611 for (i = 0; i < channels_alloc; i++) { 629 for (i = 0; i < channels_alloc; i++) {
612 ch = &channels[i]; 630 ch = &channels[i];
613 switch (ch->type) { 631 if (ch->type == SSH_CHANNEL_OPEN) {
614 case SSH_CHANNEL_X11_LISTENER:
615 case SSH_CHANNEL_PORT_LISTENER:
616 case SSH_CHANNEL_AUTH_SOCKET:
617 continue;
618 case SSH_CHANNEL_OPEN:
619 if (buffer_len(&ch->input) > packet_get_maxsize()) 632 if (buffer_len(&ch->input) > packet_get_maxsize())
620 return 0; 633 return 0;
621 if (buffer_len(&ch->output) > packet_get_maxsize()) 634 if (buffer_len(&ch->output) > packet_get_maxsize())
622 return 0; 635 return 0;
623 continue;
624 case SSH_CHANNEL_INPUT_DRAINING:
625 case SSH_CHANNEL_OUTPUT_DRAINING:
626 case SSH_CHANNEL_X11_OPEN:
627 case SSH_CHANNEL_FREE:
628 default:
629 continue;
630 } 636 }
631 } 637 }
632 return 1; 638 return 1;
@@ -853,9 +859,11 @@ channel_open_message()
853 case SSH_CHANNEL_X11_OPEN: 859 case SSH_CHANNEL_X11_OPEN:
854 case SSH_CHANNEL_INPUT_DRAINING: 860 case SSH_CHANNEL_INPUT_DRAINING:
855 case SSH_CHANNEL_OUTPUT_DRAINING: 861 case SSH_CHANNEL_OUTPUT_DRAINING:
856 snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d o%d)\r\n", 862 snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d)\r\n",
857 c->self, c->remote_name, 863 c->self, c->remote_name,
858 c->type, c->remote_id, c->istate, c->ostate); 864 c->type, c->remote_id,
865 c->istate, buffer_len(&c->input),
866 c->ostate, buffer_len(&c->output));
859 buffer_append(&buffer, buf, strlen(buf)); 867 buffer_append(&buffer, buf, strlen(buf));
860 continue; 868 continue;
861 default: 869 default:
@@ -878,50 +886,76 @@ void
878channel_request_local_forwarding(u_short port, const char *host, 886channel_request_local_forwarding(u_short port, const char *host,
879 u_short host_port, int gateway_ports) 887 u_short host_port, int gateway_ports)
880{ 888{
881 int ch, sock, on = 1; 889 int success, ch, sock, on = 1;
882 struct sockaddr_in sin; 890 struct addrinfo hints, *ai, *aitop;
891 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
883 struct linger linger; 892 struct linger linger;
884 893
885 if (strlen(host) > sizeof(channels[0].path) - 1) 894 if (strlen(host) > sizeof(channels[0].path) - 1)
886 packet_disconnect("Forward host name too long."); 895 packet_disconnect("Forward host name too long.");
887 896
888 /* Create a port to listen for the host. */
889 sock = socket(AF_INET, SOCK_STREAM, 0);
890 if (sock < 0)
891 packet_disconnect("socket: %.100s", strerror(errno));
892
893 /* Initialize socket address. */
894 memset(&sin, 0, sizeof(sin));
895 sin.sin_family = AF_INET;
896 if (gateway_ports == 1)
897 sin.sin_addr.s_addr = htonl(INADDR_ANY);
898 else
899 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
900 sin.sin_port = htons(port);
901
902 /* 897 /*
903 * Set socket options. We would like the socket to disappear as soon 898 * getaddrinfo returns a loopback address if the hostname is
904 * as it has been closed for whatever reason. 899 * set to NULL and hints.ai_flags is not AI_PASSIVE
905 */ 900 */
906 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); 901 memset(&hints, 0, sizeof(hints));
907 linger.l_onoff = 1; 902 hints.ai_family = IPv4or6;
908 linger.l_linger = 5; 903 hints.ai_flags = gateway_ports ? AI_PASSIVE : 0;
909 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); 904 hints.ai_socktype = SOCK_STREAM;
910 905 snprintf(strport, sizeof strport, "%d", port);
911 /* Bind the socket to the address. */ 906 if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
912 if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) 907 packet_disconnect("getaddrinfo: fatal error");
913 packet_disconnect("bind: %.100s", strerror(errno)); 908
914 909 success = 0;
915 /* Start listening for connections on the socket. */ 910 for (ai = aitop; ai; ai = ai->ai_next) {
916 if (listen(sock, 5) < 0) 911 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
917 packet_disconnect("listen: %.100s", strerror(errno)); 912 continue;
918 913 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
919 /* Allocate a channel number for the socket. */ 914 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
920 ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, 915 error("channel_request_local_forwarding: getnameinfo failed");
921 xstrdup("port listener")); 916 continue;
922 strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); 917 }
923 channels[ch].host_port = host_port; 918 /* Create a port to listen for the host. */
924 channels[ch].listening_port = port; 919 sock = socket(ai->ai_family, SOCK_STREAM, 0);
920 if (sock < 0) {
921 /* this is no error since kernel may not support ipv6 */
922 verbose("socket: %.100s", strerror(errno));
923 continue;
924 }
925 /*
926 * Set socket options. We would like the socket to disappear
927 * as soon as it has been closed for whatever reason.
928 */
929 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
930 linger.l_onoff = 1;
931 linger.l_linger = 5;
932 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
933 debug("Local forwarding listening on %s port %s.", ntop, strport);
934
935 /* Bind the socket to the address. */
936 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
937 /* address can be in use ipv6 address is already bound */
938 verbose("bind: %.100s", strerror(errno));
939 close(sock);
940 continue;
941 }
942 /* Start listening for connections on the socket. */
943 if (listen(sock, 5) < 0) {
944 error("listen: %.100s", strerror(errno));
945 close(sock);
946 continue;
947 }
948 /* Allocate a channel number for the socket. */
949 ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock,
950 xstrdup("port listener"));
951 strlcpy(channels[ch].path, host, sizeof(channels[ch].path));
952 channels[ch].host_port = host_port;
953 channels[ch].listening_port = port;
954 success = 1;
955 }
956 if (success == 0)
957 packet_disconnect("cannot listen port: %d", port);
958 freeaddrinfo(aitop);
925} 959}
926 960
927/* 961/*
@@ -1000,12 +1034,13 @@ channel_input_port_forward_request(int is_root)
1000void 1034void
1001channel_input_port_open(int payload_len) 1035channel_input_port_open(int payload_len)
1002{ 1036{
1003 int remote_channel, sock, newch, i; 1037 int remote_channel, sock = 0, newch, i;
1004 u_short host_port; 1038 u_short host_port;
1005 struct sockaddr_in sin;
1006 char *host, *originator_string; 1039 char *host, *originator_string;
1007 struct hostent *hp;
1008 int host_len, originator_len; 1040 int host_len, originator_len;
1041 struct addrinfo hints, *ai, *aitop;
1042 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
1043 int gaierr;
1009 1044
1010 /* Get remote channel number. */ 1045 /* Get remote channel number. */
1011 remote_channel = packet_get_int(); 1046 remote_channel = packet_get_int();
@@ -1047,41 +1082,47 @@ channel_input_port_open(int payload_len)
1047 packet_send(); 1082 packet_send();
1048 } 1083 }
1049 } 1084 }
1050 memset(&sin, 0, sizeof(sin)); 1085
1051 sin.sin_addr.s_addr = inet_addr(host); 1086 memset(&hints, 0, sizeof(hints));
1052 if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) { 1087 hints.ai_family = IPv4or6;
1053 /* It was a valid numeric host address. */ 1088 hints.ai_socktype = SOCK_STREAM;
1054 sin.sin_family = AF_INET; 1089 snprintf(strport, sizeof strport, "%d", host_port);
1055 } else { 1090 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
1056 /* Look up the host address from the name servers. */ 1091 error("%.100s: unknown host (%s)", host, gai_strerror(gaierr));
1057 hp = gethostbyname(host); 1092 goto fail;
1058 if (!hp) { 1093 }
1059 error("%.100s: unknown host.", host); 1094
1060 goto fail; 1095 for (ai = aitop; ai; ai = ai->ai_next) {
1096 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
1097 continue;
1098 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
1099 strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
1100 error("channel_input_port_open: getnameinfo failed");
1101 continue;
1061 } 1102 }
1062 if (!hp->h_addr_list[0]) { 1103 /* Create the socket. */
1063 error("%.100s: host has no IP address.", host); 1104 sock = socket(ai->ai_family, SOCK_STREAM, 0);
1064 goto fail; 1105 if (sock < 0) {
1106 error("socket: %.100s", strerror(errno));
1107 continue;
1065 } 1108 }
1066 sin.sin_family = hp->h_addrtype; 1109 /* Connect to the host/port. */
1067 memcpy(&sin.sin_addr, hp->h_addr_list[0], 1110 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
1068 sizeof(sin.sin_addr)); 1111 error("connect %.100s port %s: %.100s", ntop, strport,
1069 } 1112 strerror(errno));
1070 sin.sin_port = htons(host_port); 1113 close(sock);
1114 continue; /* fail -- try next */
1115 }
1116 break; /* success */
1071 1117
1072 /* Create the socket. */
1073 sock = socket(sin.sin_family, SOCK_STREAM, 0);
1074 if (sock < 0) {
1075 error("socket: %.100s", strerror(errno));
1076 goto fail;
1077 } 1118 }
1078 /* Connect to the host/port. */ 1119 freeaddrinfo(aitop);
1079 if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { 1120
1080 error("connect %.100s:%d: %.100s", host, host_port, 1121 if (!ai) {
1081 strerror(errno)); 1122 error("connect %.100s port %d: failed.", host, host_port);
1082 close(sock);
1083 goto fail; 1123 goto fail;
1084 } 1124 }
1125
1085 /* Successful connection. */ 1126 /* Successful connection. */
1086 1127
1087 /* Allocate a channel for this connection. */ 1128 /* Allocate a channel for this connection. */
@@ -1115,48 +1156,73 @@ fail:
1115 * occurs. 1156 * occurs.
1116 */ 1157 */
1117 1158
1159#define NUM_SOCKS 10
1160
1118char * 1161char *
1119x11_create_display_inet(int screen_number, int x11_display_offset) 1162x11_create_display_inet(int screen_number, int x11_display_offset)
1120{ 1163{
1121 int display_number, sock; 1164 int display_number, sock;
1122 u_short port; 1165 u_short port;
1123 struct sockaddr_in sin; 1166 struct addrinfo hints, *ai, *aitop;
1124 char buf[512]; 1167 char strport[NI_MAXSERV];
1168 int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
1169 char display[512];
1125 char hostname[MAXHOSTNAMELEN]; 1170 char hostname[MAXHOSTNAMELEN];
1126 1171
1127 for (display_number = x11_display_offset; 1172 for (display_number = x11_display_offset;
1128 display_number < MAX_DISPLAYS; 1173 display_number < MAX_DISPLAYS;
1129 display_number++) { 1174 display_number++) {
1130 port = 6000 + display_number; 1175 port = 6000 + display_number;
1131 memset(&sin, 0, sizeof(sin)); 1176 memset(&hints, 0, sizeof(hints));
1132 sin.sin_family = AF_INET; 1177 hints.ai_family = IPv4or6;
1133 sin.sin_addr.s_addr = htonl(INADDR_ANY); 1178 hints.ai_flags = AI_PASSIVE; /* XXX loopback only ? */
1134 sin.sin_port = htons(port); 1179 hints.ai_socktype = SOCK_STREAM;
1135 1180 snprintf(strport, sizeof strport, "%d", port);
1136 sock = socket(AF_INET, SOCK_STREAM, 0); 1181 if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
1137 if (sock < 0) { 1182 error("getaddrinfo: %.100s", gai_strerror(gaierr));
1138 error("socket: %.100s", strerror(errno));
1139 return NULL; 1183 return NULL;
1140 } 1184 }
1141 if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { 1185 for (ai = aitop; ai; ai = ai->ai_next) {
1142 debug("bind port %d: %.100s", port, strerror(errno)); 1186 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
1143 shutdown(sock, SHUT_RDWR); 1187 continue;
1144 close(sock); 1188 sock = socket(ai->ai_family, SOCK_STREAM, 0);
1145 continue; 1189 if (sock < 0) {
1190 error("socket: %.100s", strerror(errno));
1191 return NULL;
1192 }
1193 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
1194 debug("bind port %d: %.100s", port, strerror(errno));
1195 shutdown(sock, SHUT_RDWR);
1196 close(sock);
1197 for (n = 0; n < num_socks; n++) {
1198 shutdown(socks[n], SHUT_RDWR);
1199 close(socks[n]);
1200 }
1201 num_socks = 0;
1202 break;
1203 }
1204 socks[num_socks++] = sock;
1205 if (num_socks == NUM_SOCKS)
1206 break;
1146 } 1207 }
1147 break; 1208 if (num_socks > 0)
1209 break;
1148 } 1210 }
1149 if (display_number >= MAX_DISPLAYS) { 1211 if (display_number >= MAX_DISPLAYS) {
1150 error("Failed to allocate internet-domain X11 display socket."); 1212 error("Failed to allocate internet-domain X11 display socket.");
1151 return NULL; 1213 return NULL;
1152 } 1214 }
1153 /* Start listening for connections on the socket. */ 1215 /* Start listening for connections on the socket. */
1154 if (listen(sock, 5) < 0) { 1216 for (n = 0; n < num_socks; n++) {
1155 error("listen: %.100s", strerror(errno)); 1217 sock = socks[n];
1156 shutdown(sock, SHUT_RDWR); 1218 if (listen(sock, 5) < 0) {
1157 close(sock); 1219 error("listen: %.100s", strerror(errno));
1158 return NULL; 1220 shutdown(sock, SHUT_RDWR);
1221 close(sock);
1222 return NULL;
1223 }
1159 } 1224 }
1225
1160 /* Set up a suitable value for the DISPLAY variable. */ 1226 /* Set up a suitable value for the DISPLAY variable. */
1161 1227
1162 if (gethostname(hostname, sizeof(hostname)) < 0) 1228 if (gethostname(hostname, sizeof(hostname)) < 0)
@@ -1192,21 +1258,24 @@ x11_create_display_inet(int screen_number, int x11_display_offset)
1192 memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); 1258 memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
1193 1259
1194 /* Set DISPLAY to <ip address>:screen.display */ 1260 /* Set DISPLAY to <ip address>:screen.display */
1195 snprintf(buf, sizeof(buf), "%.50s:%d.%d", inet_ntoa(my_addr), 1261 snprintf(display, sizeof(display), "%.50s:%d.%d", inet_ntoa(my_addr),
1196 display_number, screen_number); 1262 display_number, screen_number);
1197 } 1263 }
1198#else /* IPADDR_IN_DISPLAY */ 1264#else /* IPADDR_IN_DISPLAY */
1199 /* Just set DISPLAY to hostname:screen.display */ 1265 /* Just set DISPLAY to hostname:screen.display */
1200 snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname, 1266 snprintf(display, sizeof display, "%.400s:%d.%d", hostname,
1201 display_number, screen_number); 1267 display_number, screen_number);
1202#endif /* IPADDR_IN_DISPLAY */ 1268#endif /* IPADDR_IN_DISPLAY */
1203 1269
1204 /* Allocate a channel for the socket. */ 1270 /* Allocate a channel for each socket. */
1205 (void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock, 1271 for (n = 0; n < num_socks; n++) {
1206 xstrdup("X11 inet listener")); 1272 sock = socks[n];
1273 (void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock,
1274 xstrdup("X11 inet listener"));
1275 }
1207 1276
1208 /* Return a suitable value for the DISPLAY environment variable. */ 1277 /* Return a suitable value for the DISPLAY environment variable. */
1209 return xstrdup(buf); 1278 return xstrdup(display);
1210} 1279}
1211 1280
1212#ifndef X_UNIX_PATH 1281#ifndef X_UNIX_PATH
@@ -1252,12 +1321,13 @@ connect_local_xsocket(unsigned int dnr)
1252void 1321void
1253x11_input_open(int payload_len) 1322x11_input_open(int payload_len)
1254{ 1323{
1255 int remote_channel, display_number, sock, newch; 1324 int remote_channel, display_number, sock = 0, newch;
1256 const char *display; 1325 const char *display;
1257 struct sockaddr_in sin;
1258 char buf[1024], *cp, *remote_host; 1326 char buf[1024], *cp, *remote_host;
1259 struct hostent *hp;
1260 int remote_len; 1327 int remote_len;
1328 struct addrinfo hints, *ai, *aitop;
1329 char strport[NI_MAXSERV];
1330 int gaierr;
1261 1331
1262 /* Get remote channel number. */ 1332 /* Get remote channel number. */
1263 remote_channel = packet_get_int(); 1333 remote_channel = packet_get_int();
@@ -1323,42 +1393,38 @@ x11_input_open(int payload_len)
1323 display); 1393 display);
1324 goto fail; 1394 goto fail;
1325 } 1395 }
1326 /* Try to parse the host name as a numeric IP address. */
1327 memset(&sin, 0, sizeof(sin));
1328 sin.sin_addr.s_addr = inet_addr(buf);
1329 if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) {
1330 /* It was a valid numeric host address. */
1331 sin.sin_family = AF_INET;
1332 } else {
1333 /* Not a numeric IP address. */
1334 /* Look up the host address from the name servers. */
1335 hp = gethostbyname(buf);
1336 if (!hp) {
1337 error("%.100s: unknown host.", buf);
1338 goto fail;
1339 }
1340 if (!hp->h_addr_list[0]) {
1341 error("%.100s: host has no IP address.", buf);
1342 goto fail;
1343 }
1344 sin.sin_family = hp->h_addrtype;
1345 memcpy(&sin.sin_addr, hp->h_addr_list[0],
1346 sizeof(sin.sin_addr));
1347 }
1348 /* Set port number. */
1349 sin.sin_port = htons(6000 + display_number);
1350 1396
1351 /* Create a socket. */ 1397 /* Look up the host address */
1352 sock = socket(sin.sin_family, SOCK_STREAM, 0); 1398 memset(&hints, 0, sizeof(hints));
1353 if (sock < 0) { 1399 hints.ai_family = IPv4or6;
1354 error("socket: %.100s", strerror(errno)); 1400 hints.ai_socktype = SOCK_STREAM;
1401 snprintf(strport, sizeof strport, "%d", 6000 + display_number);
1402 if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
1403 error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr));
1355 goto fail; 1404 goto fail;
1356 } 1405 }
1406 for (ai = aitop; ai; ai = ai->ai_next) {
1407 /* Create a socket. */
1408 sock = socket(ai->ai_family, SOCK_STREAM, 0);
1409 if (sock < 0) {
1410 debug("socket: %.100s", strerror(errno));
1411 continue;
1412 }
1357 /* Connect it to the display. */ 1413 /* Connect it to the display. */
1358 if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { 1414 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
1359 error("connect %.100s:%d: %.100s", buf, 6000 + display_number, 1415 debug("connect %.100s port %d: %.100s", buf, 6000 + display_number,
1360 strerror(errno)); 1416 strerror(errno));
1361 close(sock); 1417 close(sock);
1418 continue;
1419 }
1420 /* Success */
1421 break;
1422
1423 } /* (ai = aitop, ai; ai = ai->ai_next) */
1424 freeaddrinfo(aitop);
1425 if (!ai) {
1426 error("connect %.100s port %d: %.100s", buf, 6000 + display_number,
1427 strerror(errno));
1362 goto fail; 1428 goto fail;
1363 } 1429 }
1364success: 1430success:
diff --git a/configure.in b/configure.in
index a6654022b..ab175d409 100644
--- a/configure.in
+++ b/configure.in
@@ -128,7 +128,7 @@ dnl Checks for header files.
128AC_CHECK_HEADERS(bstring.h endian.h lastlog.h login.h maillock.h netdb.h netgroup.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stropts.h sys/time.h sys/ttcompat.h util.h utmp.h utmpx.h) 128AC_CHECK_HEADERS(bstring.h endian.h lastlog.h login.h maillock.h netdb.h netgroup.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stropts.h sys/time.h sys/ttcompat.h util.h utmp.h utmpx.h)
129 129
130dnl Checks for library functions. 130dnl Checks for library functions.
131AC_CHECK_FUNCS(arc4random getpagesize _getpty innetgr md5_crypt mkdtemp openpty setenv seteuid setlogin setproctitle setreuid snprintf strlcat strlcpy updwtmpx vsnprintf) 131AC_CHECK_FUNCS(arc4random bindresvport_af freeaddrinfo gai_strerror getaddrinfo getpagesize getnameinfo _getpty innetgr md5_crypt mkdtemp openpty rresvport_af setenv seteuid setlogin setproctitle setreuid snprintf strlcat strlcpy updwtmpx vsnprintf)
132 132
133AC_CHECK_FUNC(login, 133AC_CHECK_FUNC(login,
134 [AC_DEFINE(HAVE_LOGIN)], 134 [AC_DEFINE(HAVE_LOGIN)],
@@ -169,7 +169,7 @@ AC_TRY_COMPILE(
169 [AC_MSG_RESULT(no)] 169 [AC_MSG_RESULT(no)]
170) 170)
171 171
172AC_MSG_CHECKING([For uintXX_t types]) 172AC_MSG_CHECKING([for uintXX_t types])
173AC_TRY_COMPILE( 173AC_TRY_COMPILE(
174 [#include <sys/types.h>], 174 [#include <sys/types.h>],
175 [uint16_t c; uint32_t d; c = 1235; d = 1235;], 175 [uint16_t c; uint32_t d; c = 1235; d = 1235;],
@@ -180,7 +180,7 @@ AC_TRY_COMPILE(
180 [AC_MSG_RESULT(no)] 180 [AC_MSG_RESULT(no)]
181) 181)
182 182
183AC_MSG_CHECKING([For socklen_t]) 183AC_MSG_CHECKING([for socklen_t])
184AC_TRY_COMPILE( 184AC_TRY_COMPILE(
185 [ 185 [
186 #include <sys/types.h> 186 #include <sys/types.h>
@@ -194,7 +194,7 @@ AC_TRY_COMPILE(
194 [AC_MSG_RESULT(no)] 194 [AC_MSG_RESULT(no)]
195) 195)
196 196
197AC_MSG_CHECKING([For size_t]) 197AC_MSG_CHECKING([for size_t])
198AC_TRY_COMPILE( 198AC_TRY_COMPILE(
199 [#include <sys/types.h>], 199 [#include <sys/types.h>],
200 [size_t foo; foo = 1235;], 200 [size_t foo; foo = 1235;],
@@ -205,6 +205,53 @@ AC_TRY_COMPILE(
205 [AC_MSG_RESULT(no)] 205 [AC_MSG_RESULT(no)]
206) 206)
207 207
208AC_MSG_CHECKING([for struct sockaddr_storage])
209AC_TRY_COMPILE(
210 [#include <sys/socket.h>],
211 [struct sockaddr_storage s;],
212 [
213 AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE)
214 AC_MSG_RESULT(yes)
215 ],
216 [AC_MSG_RESULT(no)]
217)
218
219AC_MSG_CHECKING([for struct sockaddr_in6])
220AC_TRY_COMPILE(
221 [#include <netinet/in.h>],
222 [struct sockaddr_in6 s; s.sin6_family = 0;],
223 [
224 AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6)
225 AC_MSG_RESULT(yes)
226 ],
227 [AC_MSG_RESULT(no)]
228)
229
230AC_MSG_CHECKING([for struct in6_addr])
231AC_TRY_COMPILE(
232 [#include <netinet/in.h>],
233 [struct in6_addr s; s.s6_addr[0] = 0;],
234 [
235 AC_DEFINE(HAVE_STRUCT_IN6_ADDR)
236 AC_MSG_RESULT(yes)
237 ],
238 [AC_MSG_RESULT(no)]
239)
240
241AC_MSG_CHECKING([for struct addrinfo])
242AC_TRY_COMPILE(
243 [
244 #include <sys/socket.h>
245 #include <netdb.h>
246 ],
247 [struct addrinfo s; s.ai_flags = AI_PASSIVE;],
248 [
249 AC_DEFINE(HAVE_STRUCT_ADDRINFO)
250 AC_MSG_RESULT(yes)
251 ],
252 [AC_MSG_RESULT(no)]
253)
254
208AC_ARG_WITH(pam, 255AC_ARG_WITH(pam,
209 [ --without-pam Disable PAM support ], 256 [ --without-pam Disable PAM support ],
210 [ 257 [
@@ -330,7 +377,38 @@ AC_EGREP_HEADER(ut_addr, utmp.h,
330) 377)
331AC_MSG_CHECKING([whether utmpx.h has ut_addr field]) 378AC_MSG_CHECKING([whether utmpx.h has ut_addr field])
332AC_EGREP_HEADER(ut_addr, utmpx.h, 379AC_EGREP_HEADER(ut_addr, utmpx.h,
333 [AC_DEFINE(HAVE_ADDR_IN_UTMP) AC_MSG_RESULT(yes); ], 380 [AC_DEFINE(HAVE_ADDR_IN_UTMPX) AC_MSG_RESULT(yes); ],
381 [AC_MSG_RESULT(no)]
382)
383AC_MSG_CHECKING([whether utmp.h has ut_addr_v6 field])
384AC_EGREP_HEADER(ut_addr_v6, utmp.h,
385 [AC_DEFINE(HAVE_ADDR_V6_IN_UTMP) AC_MSG_RESULT(yes); ],
386 [AC_MSG_RESULT(no)]
387)
388AC_MSG_CHECKING([whether utmpx.h has ut_addr_v6 field])
389AC_EGREP_HEADER(ut_addr_v6, utmpx.h,
390 [AC_DEFINE(HAVE_ADDR_V6_IN_UTMPX) AC_MSG_RESULT(yes); ],
391 [AC_MSG_RESULT(no)]
392)
393
394AC_MSG_CHECKING([whether struct sockaddr_storage has ss_family field])
395AC_TRY_COMPILE(
396 [#include <sys/socket.h>],
397 [struct sockaddr_storage s; s.ss_family = 1;],
398 [
399 AC_DEFINE(HAVE_SS_FAMILY_IN_SS)
400 AC_MSG_RESULT(yes)
401 ],
402 [AC_MSG_RESULT(no)]
403)
404AC_MSG_CHECKING([whether struct sockaddr_storage has __ss_family field])
405AC_TRY_COMPILE(
406 [#include <sys/socket.h>],
407 [struct sockaddr_storage s; s.__ss_family = 1;],
408 [
409 AC_DEFINE(HAVE___SS_FAMILY_IN_SS)
410 AC_MSG_RESULT(yes)
411 ],
334 [AC_MSG_RESULT(no)] 412 [AC_MSG_RESULT(no)]
335) 413)
336 414
diff --git a/defines.h b/defines.h
index 40c1a3ead..d2f61e269 100644
--- a/defines.h
+++ b/defines.h
@@ -112,6 +112,10 @@ typedef unsigned int size_t;
112# define HAVE_SIZE_T 112# define HAVE_SIZE_T
113#endif /* HAVE_SIZE_T */ 113#endif /* HAVE_SIZE_T */
114 114
115#if !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE___SS_FAMILY_IN_SS)
116# define ss_family __ss_family
117#endif /* !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE_SA_FAMILY_IN_SS) */
118
115/* Paths */ 119/* Paths */
116 120
117/* If _PATH_LASTLOG is not defined by system headers, set it to the */ 121/* If _PATH_LASTLOG is not defined by system headers, set it to the */
diff --git a/fake-gai-errnos.h b/fake-gai-errnos.h
new file mode 100644
index 000000000..27f6089e9
--- /dev/null
+++ b/fake-gai-errnos.h
@@ -0,0 +1,12 @@
1/*
2 * fake library for ssh
3 *
4 * This file is included in getaddrinfo.c and getnameinfo.c.
5 * See getaddrinfo.c and getnameinfo.c.
6 */
7
8/* for old netdb.h */
9#ifndef EAI_NODATA
10#define EAI_NODATA 1
11#define EAI_MEMORY 2
12#endif
diff --git a/fake-getaddrinfo.c b/fake-getaddrinfo.c
new file mode 100644
index 000000000..b918798c4
--- /dev/null
+++ b/fake-getaddrinfo.c
@@ -0,0 +1,119 @@
1/*
2 * fake library for ssh
3 *
4 * This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
5 * These funtions are defined in rfc2133.
6 *
7 * But these functions are not implemented correctly. The minimum subset
8 * is implemented for ssh use only. For exapmle, this routine assumes
9 * that ai_family is AF_INET. Don't use it for another purpose.
10 *
11 * In the case not using 'configure --enable-ipv6', this getaddrinfo.c
12 * will be used if you have broken getaddrinfo or no getaddrinfo.
13 */
14
15#include "includes.h"
16#include "ssh.h"
17
18#ifndef HAVE_GAI_STRERROR
19char *
20gai_strerror(ecode)
21int ecode;
22{
23 switch (ecode) {
24 case EAI_NODATA:
25 return "no address associated with hostname.";
26 case EAI_MEMORY:
27 return "memory allocation failure.";
28 default:
29 return "unknown error.";
30 }
31}
32#endif /* !HAVE_GAI_STRERROR */
33
34#ifndef HAVE_FREEADDRINFO
35void
36freeaddrinfo(ai)
37struct addrinfo *ai;
38{
39 struct addrinfo *next;
40
41 do {
42 next = ai->ai_next;
43 free(ai);
44 } while (ai = next);
45}
46#endif /* !HAVE_FREEADDRINFO */
47
48#ifndef HAVE_GETADDRINFO
49static struct addrinfo *
50malloc_ai(port, addr)
51int port;
52u_long addr;
53{
54 struct addrinfo *ai;
55
56 if (ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) +
57 sizeof(struct sockaddr_in))) {
58 memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
59 ai->ai_addr = (struct sockaddr *)(ai + 1);
60 /* XXX -- ssh doesn't use sa_len */
61 ai->ai_addrlen = sizeof(struct sockaddr_in);
62 ai->ai_addr->sa_family = ai->ai_family = AF_INET;
63 ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
64 ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
65 return ai;
66 } else {
67 return NULL;
68 }
69}
70
71int
72getaddrinfo(hostname, servname, hints, res)
73const char *hostname, *servname;
74const struct addrinfo *hints;
75struct addrinfo **res;
76{
77 struct addrinfo *cur, *prev = NULL;
78 struct hostent *hp;
79 int i, port;
80
81 if (servname)
82 port = htons(atoi(servname));
83 else
84 port = 0;
85 if (hints && hints->ai_flags & AI_PASSIVE)
86 if (*res = malloc_ai(port, htonl(0x00000000)))
87 return 0;
88 else
89 return EAI_MEMORY;
90 if (!hostname)
91 if (*res = malloc_ai(port, htonl(0x7f000001)))
92 return 0;
93 else
94 return EAI_MEMORY;
95 if (inet_addr(hostname) != -1)
96 if (*res = malloc_ai(port, inet_addr(hostname)))
97 return 0;
98 else
99 return EAI_MEMORY;
100 if ((hp = gethostbyname(hostname)) &&
101 hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
102 for (i = 0; hp->h_addr_list[i]; i++)
103 if (cur = malloc_ai(port,
104 ((struct in_addr *)hp->h_addr_list[i])->s_addr)) {
105 if (prev)
106 prev->ai_next = cur;
107 else
108 *res = cur;
109 prev = cur;
110 } else {
111 if (*res)
112 freeaddrinfo(*res);
113 return EAI_MEMORY;
114 }
115 return 0;
116 }
117 return EAI_NODATA;
118}
119#endif /* !HAVE_GETADDRINFO */
diff --git a/fake-getaddrinfo.h b/fake-getaddrinfo.h
new file mode 100644
index 000000000..de1748f6f
--- /dev/null
+++ b/fake-getaddrinfo.h
@@ -0,0 +1,44 @@
1#ifndef _FAKE_GETADDRINFO_H
2#define _FAKE_GETADDRINFO_H
3
4#include "config.h"
5
6#include "fake-gai-errnos.h"
7
8#ifndef AI_PASSIVE
9# define AI_PASSIVE 1
10#endif
11
12#ifndef NI_NUMERICHOST
13# define NI_NUMERICHOST 2
14# define NI_NAMEREQD 4
15# define NI_NUMERICSERV 8
16#endif
17
18#ifndef HAVE_STRUCT_ADDRINFO
19struct addrinfo {
20 int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
21 int ai_family; /* PF_xxx */
22 int ai_socktype; /* SOCK_xxx */
23 int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
24 size_t ai_addrlen; /* length of ai_addr */
25 char *ai_canonname; /* canonical name for hostname */
26 struct sockaddr *ai_addr; /* binary address */
27 struct addrinfo *ai_next; /* next structure in linked list */
28}
29#endif /* !HAVE_STRUCT_ADDRINFO */
30
31#ifndef HAVE_GETADDRINFO
32int getaddrinfo(const char *hostname, const char *servname,
33 const struct addrinfo *hints, struct addrinfo **res);
34#endif /* !HAVE_GETADDRINFO */
35
36#ifndef HAVE_GAI_STRERROR
37char *gai_strerror(int ecode);
38#endif /* !HAVE_GAI_STRERROR */
39
40#ifndef HAVE_FREEADDRINFO
41void freeaddrinfo(struct addrinfo *ai);
42#endif /* !HAVE_FREEADDRINFO */
43
44#endif /* _FAKE_GETADDRINFO_H */
diff --git a/fake-getnameinfo.c b/fake-getnameinfo.c
new file mode 100644
index 000000000..bf1184e24
--- /dev/null
+++ b/fake-getnameinfo.c
@@ -0,0 +1,61 @@
1/*
2 * fake library for ssh
3 *
4 * This file includes getnameinfo().
5 * These funtions are defined in rfc2133.
6 *
7 * But these functions are not implemented correctly. The minimum subset
8 * is implemented for ssh use only. For exapmle, this routine assumes
9 * that ai_family is AF_INET. Don't use it for another purpose.
10 *
11 * In the case not using 'configure --enable-ipv6', this getnameinfo.c
12 * will be used if you have broken getnameinfo or no getnameinfo.
13 */
14
15#include "includes.h"
16#include "ssh.h"
17
18#ifndef HAVE_GETNAMEINFO
19int
20getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
21const struct sockaddr *sa;
22size_t salen;
23char *host;
24size_t hostlen;
25char *serv;
26size_t servlen;
27int flags;
28{
29 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
30 struct hostent *hp;
31 char tmpserv[16];
32
33 if (serv) {
34 sprintf(tmpserv, "%d", ntohs(sin->sin_port));
35 if (strlen(tmpserv) > servlen)
36 return EAI_MEMORY;
37 else
38 strcpy(serv, tmpserv);
39 }
40 if (host)
41 if (flags & NI_NUMERICHOST)
42 if (strlen(inet_ntoa(sin->sin_addr)) > hostlen)
43 return EAI_MEMORY;
44 else {
45 strcpy(host, inet_ntoa(sin->sin_addr));
46 return 0;
47 }
48 else
49 if (hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr),
50 AF_INET))
51 if (strlen(hp->h_name) > hostlen)
52 return EAI_MEMORY;
53 else {
54 strcpy(host, hp->h_name);
55 return 0;
56 }
57 else
58 return EAI_NODATA;
59 return 0;
60}
61#endif /* !HAVE_GETNAMEINFO */
diff --git a/fake-getnameinfo.h b/fake-getnameinfo.h
new file mode 100644
index 000000000..ecf0df2cf
--- /dev/null
+++ b/fake-getnameinfo.h
@@ -0,0 +1,17 @@
1#ifndef _FAKE_GETNAMEINFO_H
2#define _FAKE_GETNAMEINFO_H
3
4#include "config.h"
5#ifndef HAVE_GETNAMEINFO
6int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
7 size_t hostlen, char *serv, size_t servlen, int flags);
8#endif /* !HAVE_GETNAMEINFO */
9
10#ifndef NI_MAXSERV
11# define NI_MAXSERV 32
12#endif /* !NI_MAXSERV */
13#ifndef NI_MAXHOST
14# define NI_MAXHOST 1025
15#endif /* !NI_MAXHOST */
16
17#endif /* _FAKE_GETNAMEINFO_H */
diff --git a/fake-socket.h b/fake-socket.h
new file mode 100644
index 000000000..e11ad44e0
--- /dev/null
+++ b/fake-socket.h
@@ -0,0 +1,49 @@
1#ifndef _FAKE_SOCKET_H
2#define _FAKE_SOCKET_H
3
4#include "config.h"
5#include "sys/types.h"
6
7#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
8#define _SS_MAXSIZE 128 /* Implementation specific max size */
9#define _SS_ALIGNSIZE (sizeof(int))
10#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_short))
11#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof(u_short) + \
12 _SS_PAD1SIZE + _SS_ALIGNSIZE))
13
14struct sockaddr_storage {
15 u_short ss_family;
16 char __ss_pad1[_SS_PAD1SIZE];
17 int __ss_align;
18 char __ss_pad2[_SS_PAD2SIZE];
19};
20#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
21
22#ifndef IN6_IS_ADDR_LOOPBACK
23#define IN6_IS_ADDR_LOOPBACK(a) \
24 (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \
25 ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1))
26#endif /* !IN6_IS_ADDR_LOOPBACK */
27
28#ifndef HAVE_STRUCT_IN6_ADDR
29struct in6_addr {
30 u_int8_t s6_addr[16];
31};
32#endif /* !HAVE_STRUCT_IN6_ADDR */
33
34#ifndef HAVE_STRUCT_SOCKADDR_IN6
35struct sockaddr_in6 {
36 unsigned short sin6_family;
37 u_int16_t sin6_port;
38 u_int32_t sin6_flowinfo;
39 struct in6_addr sin6_addr;
40};
41#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
42
43#ifndef AF_INET6
44/* Define it to something that should never appear */
45#define AF_INET6 AF_MAX
46#endif
47
48#endif /* !_FAKE_SOCKET_H */
49
diff --git a/fixpaths b/fixpaths
index 6a2a3a0b3..8a6740649 100755
--- a/fixpaths
+++ b/fixpaths
@@ -31,8 +31,6 @@ for $f (@ARGV) {
31 $f =~ /(.*\/)*(.*)$/; 31 $f =~ /(.*\/)*(.*)$/;
32 $of = $2; $of =~ s/.in$//; 32 $of = $2; $of =~ s/.in$//;
33 33
34 print("Making substitutions for $of\n");
35
36 open(IN, "<$f") || die ("$0: input file $f missing!\n"); 34 open(IN, "<$f") || die ("$0: input file $f missing!\n");
37 if (open(OUT, ">$of")) { 35 if (open(OUT, ">$of")) {
38 while (<IN>) { 36 while (<IN>) {
diff --git a/hostfile.c b/hostfile.c
index 7060a899e..831ac592f 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -14,7 +14,7 @@
14 */ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$OpenBSD: hostfile.c,v 1.10 1999/12/02 20:18:59 markus Exp $"); 17RCSID("$OpenBSD: hostfile.c,v 1.11 2000/01/04 00:07:59 markus Exp $");
18 18
19#include "packet.h" 19#include "packet.h"
20#include "ssh.h" 20#include "ssh.h"
diff --git a/includes.h b/includes.h
index bc7db419a..b4af0c220 100644
--- a/includes.h
+++ b/includes.h
@@ -88,6 +88,10 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
88#endif 88#endif
89 89
90#include "version.h" 90#include "version.h"
91
92/* BSD function replacements */
93#include "bsd-bindresvport.h"
94#include "bsd-rresvport.h"
91#include "bsd-misc.h" 95#include "bsd-misc.h"
92#include "bsd-strlcpy.h" 96#include "bsd-strlcpy.h"
93#include "bsd-strlcat.h" 97#include "bsd-strlcat.h"
@@ -96,6 +100,11 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
96#include "bsd-daemon.h" 100#include "bsd-daemon.h"
97#include "bsd-login.h" 101#include "bsd-login.h"
98 102
103/* rfc2553 socket API replacements */
104#include "fake-getaddrinfo.h"
105#include "fake-getnameinfo.h"
106#include "fake-socket.h"
107
99/* Define this to be the path of the xauth program. */ 108/* Define this to be the path of the xauth program. */
100#ifndef XAUTH_PATH 109#ifndef XAUTH_PATH
101#define XAUTH_PATH "/usr/X11R6/bin/xauth" 110#define XAUTH_PATH "/usr/X11R6/bin/xauth"
diff --git a/log.c b/log.c
index 837a670de..03038b2fb 100644
--- a/log.c
+++ b/log.c
@@ -3,7 +3,7 @@
3 */ 3 */
4 4
5#include "includes.h" 5#include "includes.h"
6RCSID("$OpenBSD: log.c,v 1.6 1999/11/24 19:53:47 markus Exp $"); 6RCSID("$OpenBSD: log.c,v 1.7 2000/01/04 00:07:59 markus Exp $");
7 7
8#include "ssh.h" 8#include "ssh.h"
9#include "xmalloc.h" 9#include "xmalloc.h"
diff --git a/login.c b/login.c
index 7adc4f22c..f95cbcee8 100644
--- a/login.c
+++ b/login.c
@@ -18,7 +18,7 @@
18 */ 18 */
19 19
20#include "includes.h" 20#include "includes.h"
21RCSID("$Id: login.c,v 1.17 2000/01/02 00:45:33 damien Exp $"); 21RCSID("$Id: login.c,v 1.18 2000/01/14 04:45:50 damien Exp $");
22 22
23#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX) 23#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
24# include <utmpx.h> 24# include <utmpx.h>
@@ -137,7 +137,7 @@ get_last_login_time(uid_t uid, const char *logname,
137 137
138void 138void
139record_login(int pid, const char *ttyname, const char *user, uid_t uid, 139record_login(int pid, const char *ttyname, const char *user, uid_t uid,
140 const char *host, struct sockaddr_in * addr) 140 const char *host, struct sockaddr * addr)
141{ 141{
142#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) 142#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
143 struct lastlog ll; 143 struct lastlog ll;
@@ -173,7 +173,22 @@ record_login(int pid, const char *ttyname, const char *user, uid_t uid,
173 strncpy(u.ut_host, host, sizeof(u.ut_host)); 173 strncpy(u.ut_host, host, sizeof(u.ut_host));
174#endif 174#endif
175#if defined(HAVE_ADDR_IN_UTMP) 175#if defined(HAVE_ADDR_IN_UTMP)
176 u.ut_addr = addr->sin_addr.s_addr; 176 switch (addr->sa_family) {
177 case AF_INET: {
178 struct sockaddr_in *in = (struct sockaddr_in*)addr;
179 memcpy(&(u.ut_addr), &(in->sin_addr), sizeof(&(in->sin_addr)));
180 break;
181 }
182#if defined(HAVE_ADDR_V6_IN_UTMP)
183 case AF_INET6: {
184 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
185 memcpy(u.ut_addr_v6, &(in6->sin6_addr), sizeof(&(in6->sin6_addr)));
186 break;
187 }
188#endif
189 default:
190 break;
191 }
177#endif 192#endif
178 193
179#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX) 194#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
@@ -192,9 +207,24 @@ record_login(int pid, const char *ttyname, const char *user, uid_t uid,
192 strncpy(utx.ut_host, host, sizeof(utx.ut_host)); 207 strncpy(utx.ut_host, host, sizeof(utx.ut_host));
193# endif /* HAVE_SYSLEN_IN_UTMPX */ 208# endif /* HAVE_SYSLEN_IN_UTMPX */
194# endif 209# endif
195# if defined(HAVE_ADDR_IN_UTMPX) 210#if defined(HAVE_ADDR_IN_UTMPX)
196 utx.ut_addr = addr->sin_addr.s_addr; 211 switch (addr->sa_family) {
197# endif 212 case AF_INET: {
213 struct sockaddr_in *in = (struct sockaddr_in*)addr;
214 memcpy(&(utx.ut_addr), &(in->sin_addr), sizeof(&(in->sin_addr)));
215 break;
216 }
217#if defined(HAVE_ADDR_V6_IN_UTMPX)
218 case AF_INET6: {
219 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
220 memcpy(utx.ut_addr_v6, &(in6->sin6_addr), sizeof(&(in6->sin6_addr)));
221 break;
222 }
223#endif
224 default:
225 break;
226 }
227#endif
198#endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */ 228#endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
199 229
200/*#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX) && !defined(HAVE_LOGIN)*/ 230/*#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX) && !defined(HAVE_LOGIN)*/
diff --git a/nchan.c b/nchan.c
index 23d180c4d..0c8066f87 100644
--- a/nchan.c
+++ b/nchan.c
@@ -28,7 +28,7 @@
28 */ 28 */
29 29
30#include "includes.h" 30#include "includes.h"
31RCSID("$Id: nchan.c,v 1.4 1999/12/06 00:47:29 damien Exp $"); 31RCSID("$Id: nchan.c,v 1.5 2000/01/14 04:45:50 damien Exp $");
32 32
33#include "ssh.h" 33#include "ssh.h"
34 34
@@ -41,7 +41,7 @@ static void chan_send_ieof(Channel *c);
41static void chan_send_oclose(Channel *c); 41static void chan_send_oclose(Channel *c);
42static void chan_shutdown_write(Channel *c); 42static void chan_shutdown_write(Channel *c);
43static void chan_shutdown_read(Channel *c); 43static void chan_shutdown_read(Channel *c);
44static void chan_delele_if_full_closed(Channel *c); 44static void chan_delete_if_full_closed(Channel *c);
45 45
46/* 46/*
47 * EVENTS update channel input/output states execute ACTIONS 47 * EVENTS update channel input/output states execute ACTIONS
@@ -55,19 +55,25 @@ chan_rcvd_oclose(Channel *c)
55 case CHAN_INPUT_WAIT_OCLOSE: 55 case CHAN_INPUT_WAIT_OCLOSE:
56 debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self); 56 debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
57 c->istate = CHAN_INPUT_CLOSED; 57 c->istate = CHAN_INPUT_CLOSED;
58 chan_delele_if_full_closed(c);
59 break; 58 break;
60 case CHAN_INPUT_OPEN: 59 case CHAN_INPUT_OPEN:
61 debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); 60 debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
62 chan_shutdown_read(c); 61 chan_shutdown_read(c);
63 chan_send_ieof(c); 62 chan_send_ieof(c);
64 c->istate = CHAN_INPUT_CLOSED; 63 c->istate = CHAN_INPUT_CLOSED;
65 chan_delele_if_full_closed(c); 64 break;
65 case CHAN_INPUT_WAIT_DRAIN:
66 /* both local read_failed and remote write_failed */
67 log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
68 debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
69 chan_send_ieof(c);
70 c->istate = CHAN_INPUT_CLOSED;
66 break; 71 break;
67 default: 72 default:
68 error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate); 73 error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
69 break; 74 return;
70 } 75 }
76 chan_delete_if_full_closed(c);
71} 77}
72void 78void
73chan_read_failed(Channel *c) 79chan_read_failed(Channel *c)
@@ -115,7 +121,7 @@ chan_rcvd_ieof(Channel *c)
115 case CHAN_OUTPUT_WAIT_IEOF: 121 case CHAN_OUTPUT_WAIT_IEOF:
116 debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self); 122 debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
117 c->ostate = CHAN_OUTPUT_CLOSED; 123 c->ostate = CHAN_OUTPUT_CLOSED;
118 chan_delele_if_full_closed(c); 124 chan_delete_if_full_closed(c);
119 break; 125 break;
120 default: 126 default:
121 error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate); 127 error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
@@ -135,7 +141,7 @@ chan_write_failed(Channel *c)
135 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self); 141 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
136 chan_send_oclose(c); 142 chan_send_oclose(c);
137 c->ostate = CHAN_OUTPUT_CLOSED; 143 c->ostate = CHAN_OUTPUT_CLOSED;
138 chan_delele_if_full_closed(c); 144 chan_delete_if_full_closed(c);
139 break; 145 break;
140 default: 146 default:
141 error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate); 147 error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
@@ -154,7 +160,7 @@ chan_obuf_empty(Channel *c)
154 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self); 160 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
155 chan_send_oclose(c); 161 chan_send_oclose(c);
156 c->ostate = CHAN_OUTPUT_CLOSED; 162 c->ostate = CHAN_OUTPUT_CLOSED;
157 chan_delele_if_full_closed(c); 163 chan_delete_if_full_closed(c);
158 break; 164 break;
159 default: 165 default:
160 error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate); 166 error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
@@ -213,14 +219,14 @@ chan_shutdown_read(Channel *c)
213{ 219{
214 debug("channel %d: shutdown_read", c->self); 220 debug("channel %d: shutdown_read", c->self);
215 if (shutdown(c->sock, SHUT_RD) < 0) 221 if (shutdown(c->sock, SHUT_RD) < 0)
216 error("chan_shutdown_read failed for #%d/fd%d: %.100s", 222 error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
217 c->self, c->sock, strerror(errno)); 223 c->self, c->sock, c->istate, c->ostate, strerror(errno));
218} 224}
219static void 225static void
220chan_delele_if_full_closed(Channel *c) 226chan_delete_if_full_closed(Channel *c)
221{ 227{
222 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { 228 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
223 debug("channel %d: closing", c->self); 229 debug("channel %d: full closed", c->self);
224 channel_free(c->self); 230 channel_free(c->self);
225 } 231 }
226} 232}
diff --git a/nchan.ms b/nchan.ms
index 7b6c1617e..eb49cd3b4 100644
--- a/nchan.ms
+++ b/nchan.ms
@@ -52,6 +52,9 @@ arrow from S3.n to S4.s
52box invis "rcvd OCLOSE/" "-" with .w at last arrow.c 52box invis "rcvd OCLOSE/" "-" with .w at last arrow.c
53ellipse wid .9*ellipsewid ht .9*ellipseht at S4 53ellipse wid .9*ellipsewid ht .9*ellipseht at S4
54arrow "start" "" from S1.w+(-0.5,0) to S1.w 54arrow "start" "" from S1.w+(-0.5,0) to S1.w
55arrow from S2.ne to S4.sw
56box invis "rcvd OCLOSE/ " with .e at last arrow.c
57box invis " send IEOF" with .w at last arrow.c
55.PE 58.PE
56.SH 59.SH
57Channel Output State Diagram 60Channel Output State Diagram
@@ -76,7 +79,7 @@ arrow "start" "" from S1.w+(-0.5,0) to S1.w
76Notes 79Notes
77.PP 80.PP
78The input buffer is filled with data from the socket 81The input buffer is filled with data from the socket
79(the socket represents the local comsumer/producer of the 82(the socket represents the local consumer/producer of the
80forwarded channel). 83forwarded channel).
81The data is then sent over the INPUT-end (transmit-end) of the channel to the 84The data is then sent over the INPUT-end (transmit-end) of the channel to the
82remote peer. 85remote peer.
@@ -85,7 +88,7 @@ saved in the output buffer and written to the socket.
85.PP 88.PP
86If the local protocol instance has forwarded all data on the 89If the local protocol instance has forwarded all data on the
87INPUT-end of the channel, it sends an IEOF message to the peer. 90INPUT-end of the channel, it sends an IEOF message to the peer.
88If the peer receives the IEOF and has comsumed all 91If the peer receives the IEOF and has consumed all
89data he replies with an OCLOSE. 92data he replies with an OCLOSE.
90When the local instance receives the OCLOSE 93When the local instance receives the OCLOSE
91he considers the INPUT-half of the channel closed. 94he considers the INPUT-half of the channel closed.
@@ -94,6 +97,6 @@ The peer has his OUTOUT-half closed.
94A channel can be deallocated by a protocol instance 97A channel can be deallocated by a protocol instance
95if both the INPUT- and the OUTOUT-half on his 98if both the INPUT- and the OUTOUT-half on his
96side of the channel are closed. 99side of the channel are closed.
97Note that when an instance is unable to comsume the 100Note that when an instance is unable to consume the
98received data, he is permitted to send an OCLOSE 101received data, he is permitted to send an OCLOSE
99before the matching IEOF is received. 102before the matching IEOF is received.
diff --git a/packet.c b/packet.c
index 17f6f6e3d..bcd25834e 100644
--- a/packet.c
+++ b/packet.c
@@ -15,7 +15,7 @@
15 */ 15 */
16 16
17#include "includes.h" 17#include "includes.h"
18RCSID("$Id: packet.c,v 1.8 1999/12/16 02:18:04 damien Exp $"); 18RCSID("$Id: packet.c,v 1.9 2000/01/14 04:45:50 damien Exp $");
19 19
20#include "xmalloc.h" 20#include "xmalloc.h"
21#include "buffer.h" 21#include "buffer.h"
@@ -104,6 +104,48 @@ packet_set_connection(int fd_in, int fd_out)
104 fatal_add_cleanup((void (*) (void *)) packet_close, NULL); 104 fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
105} 105}
106 106
107/* Returns 1 if remote host is connected via socket, 0 if not. */
108
109int
110packet_connection_is_on_socket()
111{
112 struct sockaddr_storage from, to;
113 socklen_t fromlen, tolen;
114
115 /* filedescriptors in and out are the same, so it's a socket */
116 if (connection_in == connection_out)
117 return 1;
118 fromlen = sizeof(from);
119 memset(&from, 0, sizeof(from));
120 if (getpeername(connection_in, (struct sockaddr *) & from, &fromlen) < 0)
121 return 0;
122 tolen = sizeof(to);
123 memset(&to, 0, sizeof(to));
124 if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
125 return 0;
126 if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0)
127 return 0;
128 if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
129 return 0;
130 return 1;
131}
132
133/* returns 1 if connection is via ipv4 */
134
135int
136packet_connection_is_ipv4()
137{
138 struct sockaddr_storage to;
139 socklen_t tolen;
140
141 memset(&to, 0, sizeof(to));
142 if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0)
143 return 0;
144 if (to.ss_family != AF_INET)
145 return 0;
146 return 1;
147}
148
107/* Sets the connection into non-blocking mode. */ 149/* Sets the connection into non-blocking mode. */
108 150
109void 151void
@@ -735,19 +777,20 @@ packet_set_interactive(int interactive, int keepalives)
735 /* Record that we are in interactive mode. */ 777 /* Record that we are in interactive mode. */
736 interactive_mode = interactive; 778 interactive_mode = interactive;
737 779
738 /* 780 /* Only set socket options if using a socket. */
739 * Only set socket options if using a socket (as indicated by the 781 if (!packet_connection_is_on_socket())
740 * descriptors being the same).
741 */
742 if (connection_in != connection_out)
743 return; 782 return;
744
745 if (keepalives) { 783 if (keepalives) {
746 /* Set keepalives if requested. */ 784 /* Set keepalives if requested. */
747 if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *) &on, 785 if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *) &on,
748 sizeof(on)) < 0) 786 sizeof(on)) < 0)
749 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 787 error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
750 } 788 }
789 /*
790 * IPTOS_LOWDELAY, TCP_NODELAY and IPTOS_THROUGHPUT are IPv4 only
791 */
792 if (!packet_connection_is_ipv4())
793 return;
751 if (interactive) { 794 if (interactive) {
752 /* 795 /*
753 * Set IP options for an interactive connection. Use 796 * Set IP options for an interactive connection. Use
@@ -755,10 +798,10 @@ packet_set_interactive(int interactive, int keepalives)
755 */ 798 */
756 int lowdelay = IPTOS_LOWDELAY; 799 int lowdelay = IPTOS_LOWDELAY;
757 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay, 800 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &lowdelay,
758 sizeof(lowdelay)) < 0) 801 sizeof(lowdelay)) < 0)
759 error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); 802 error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno));
760 if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on, 803 if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *) &on,
761 sizeof(on)) < 0) 804 sizeof(on)) < 0)
762 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 805 error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
763 } else { 806 } else {
764 /* 807 /*
@@ -767,7 +810,7 @@ packet_set_interactive(int interactive, int keepalives)
767 */ 810 */
768 int throughput = IPTOS_THROUGHPUT; 811 int throughput = IPTOS_THROUGHPUT;
769 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput, 812 if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *) &throughput,
770 sizeof(throughput)) < 0) 813 sizeof(throughput)) < 0)
771 error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno)); 814 error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
772 } 815 }
773} 816}
diff --git a/packet.h b/packet.h
index 84c8ee756..6368f2cd1 100644
--- a/packet.h
+++ b/packet.h
@@ -13,7 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16/* RCSID("$Id: packet.h,v 1.8 1999/12/27 12:54:55 damien Exp $"); */ 16/* RCSID("$Id: packet.h,v 1.9 2000/01/14 04:45:51 damien Exp $"); */
17 17
18#ifndef PACKET_H 18#ifndef PACKET_H
19#define PACKET_H 19#define PACKET_H
@@ -198,4 +198,8 @@ do { \
198 } \ 198 } \
199} while (0) 199} while (0)
200 200
201/* remote host is connected via a socket/ipv4 */
202int packet_connection_is_on_socket(void);
203int packet_connection_is_ipv4(void);
204
201#endif /* PACKET_H */ 205#endif /* PACKET_H */
diff --git a/scp.1.in b/scp.1.in
index 641c8f4f2..a0e699ba7 100644
--- a/scp.1.in
+++ b/scp.1.in
@@ -9,7 +9,7 @@
9.\" 9.\"
10.\" Created: Sun May 7 00:14:37 1995 ylo 10.\" Created: Sun May 7 00:14:37 1995 ylo
11.\" 11.\"
12.\" $Id: scp.1.in,v 1.1 1999/12/26 22:23:58 damien Exp $ 12.\" $Id: scp.1.in,v 1.2 2000/01/14 04:45:51 damien Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SCP 1 15.Dt SCP 1
@@ -19,7 +19,7 @@
19.Nd secure copy (remote file copy program) 19.Nd secure copy (remote file copy program)
20.Sh SYNOPSIS 20.Sh SYNOPSIS
21.Nm scp 21.Nm scp
22.Op Fl pqrvC 22.Op Fl pqrvC46
23.Op Fl P Ar port 23.Op Fl P Ar port
24.Op Fl c Ar cipher 24.Op Fl c Ar cipher
25.Op Fl i Ar identity_file 25.Op Fl i Ar identity_file
@@ -93,6 +93,14 @@ because
93.Fl p 93.Fl p
94is already reserved for preserving the times and modes of the file in 94is already reserved for preserving the times and modes of the file in
95.Xr rcp 1 . 95.Xr rcp 1 .
96.It Fl 4
97Forces
98.Nm
99to use IPv4 addresses only.
100.It Fl 6
101Forces
102.Nm
103to use IPv6 addresses only.
96.Sh AUTHORS 104.Sh AUTHORS
97Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi> 105Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi>
98.Sh HISTORY 106.Sh HISTORY
diff --git a/scp.c b/scp.c
index d54a7c854..3074ccdaa 100644
--- a/scp.c
+++ b/scp.c
@@ -45,7 +45,7 @@
45 */ 45 */
46 46
47#include "includes.h" 47#include "includes.h"
48RCSID("$Id: scp.c,v 1.15 1999/12/30 22:16:40 damien Exp $"); 48RCSID("$Id: scp.c,v 1.16 2000/01/14 04:45:51 damien Exp $");
49 49
50#include "ssh.h" 50#include "ssh.h"
51#include "xmalloc.h" 51#include "xmalloc.h"
@@ -74,6 +74,12 @@ off_t totalbytes = 0;
74/* Name of current file being transferred. */ 74/* Name of current file being transferred. */
75char *curfile; 75char *curfile;
76 76
77/* This is set to non-zero if IPv4 is desired. */
78int IPv4 = 0;
79
80/* This is set to non-zero if IPv6 is desired. */
81int IPv6 = 0;
82
77/* This is set to non-zero to enable verbose mode. */ 83/* This is set to non-zero to enable verbose mode. */
78int verbose_mode = 0; 84int verbose_mode = 0;
79 85
@@ -145,6 +151,11 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
145 args[i++] = SSH_PROGRAM; 151 args[i++] = SSH_PROGRAM;
146 args[i++] = "-x"; 152 args[i++] = "-x";
147 args[i++] = "-oFallBackToRsh no"; 153 args[i++] = "-oFallBackToRsh no";
154 if (IPv4)
155 args[i++] = "-4";
156 if (IPv6)
157 args[i++] = "-6";
158 args[i++] = "-oFallBackToRsh no";
148 if (verbose_mode) 159 if (verbose_mode)
149 args[i++] = "-v"; 160 args[i++] = "-v";
150 if (compress_flag) 161 if (compress_flag)
@@ -242,9 +253,15 @@ main(argc, argv)
242 extern int optind; 253 extern int optind;
243 254
244 fflag = tflag = 0; 255 fflag = tflag = 0;
245 while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q")) != EOF) 256 while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46")) != EOF)
246 switch (ch) { 257 switch (ch) {
247 /* User-visible flags. */ 258 /* User-visible flags. */
259 case '4':
260 IPv4 = 1;
261 break;
262 case '6':
263 IPv6 = 1;
264 break;
248 case 'p': 265 case 'p':
249 pflag = 1; 266 pflag = 1;
250 break; 267 break;
@@ -334,6 +351,17 @@ main(argc, argv)
334 exit(errs != 0); 351 exit(errs != 0);
335} 352}
336 353
354char *
355cleanhostname(host)
356 char *host;
357{
358 if (*host == '[' && host[strlen(host) - 1] == ']') {
359 host[strlen(host) - 1] = '\0';
360 return (host + 1);
361 } else
362 return host;
363}
364
337void 365void
338toremote(targ, argc, argv) 366toremote(targ, argc, argv)
339 char *targ, *argv[]; 367 char *targ, *argv[];
@@ -372,6 +400,7 @@ toremote(targ, argc, argv)
372 bp = xmalloc(len); 400 bp = xmalloc(len);
373 if (host) { 401 if (host) {
374 *host++ = 0; 402 *host++ = 0;
403 host = cleanhostname(host);
375 suser = argv[i]; 404 suser = argv[i];
376 if (*suser == '\0') 405 if (*suser == '\0')
377 suser = pwd->pw_name; 406 suser = pwd->pw_name;
@@ -383,13 +412,15 @@ toremote(targ, argc, argv)
383 suser, host, cmd, src, 412 suser, host, cmd, src,
384 tuser ? tuser : "", tuser ? "@" : "", 413 tuser ? tuser : "", tuser ? "@" : "",
385 thost, targ); 414 thost, targ);
386 } else 415 } else {
416 host = cleanhostname(argv[i]);
387 (void) sprintf(bp, 417 (void) sprintf(bp,
388 "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'", 418 "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'",
389 SSH_PROGRAM, verbose_mode ? " -v" : "", 419 SSH_PROGRAM, verbose_mode ? " -v" : "",
390 argv[i], cmd, src, 420 host, cmd, src,
391 tuser ? tuser : "", tuser ? "@" : "", 421 tuser ? tuser : "", tuser ? "@" : "",
392 thost, targ); 422 thost, targ);
423 }
393 if (verbose_mode) 424 if (verbose_mode)
394 fprintf(stderr, "Executing: %s\n", bp); 425 fprintf(stderr, "Executing: %s\n", bp);
395 (void) system(bp); 426 (void) system(bp);
@@ -399,7 +430,7 @@ toremote(targ, argc, argv)
399 len = strlen(targ) + CMDNEEDS + 20; 430 len = strlen(targ) + CMDNEEDS + 20;
400 bp = xmalloc(len); 431 bp = xmalloc(len);
401 (void) sprintf(bp, "%s -t %s", cmd, targ); 432 (void) sprintf(bp, "%s -t %s", cmd, targ);
402 host = thost; 433 host = cleanhostname(thost);
403 if (do_cmd(host, tuser, 434 if (do_cmd(host, tuser,
404 bp, &remin, &remout) < 0) 435 bp, &remin, &remout) < 0)
405 exit(1); 436 exit(1);
@@ -449,6 +480,7 @@ tolocal(argc, argv)
449 else if (!okname(suser)) 480 else if (!okname(suser))
450 continue; 481 continue;
451 } 482 }
483 host = cleanhostname(host);
452 len = strlen(src) + CMDNEEDS + 20; 484 len = strlen(src) + CMDNEEDS + 20;
453 bp = xmalloc(len); 485 bp = xmalloc(len);
454 (void) sprintf(bp, "%s -f %s", cmd, src); 486 (void) sprintf(bp, "%s -f %s", cmd, src);
@@ -913,7 +945,7 @@ void
913usage() 945usage()
914{ 946{
915 (void) fprintf(stderr, 947 (void) fprintf(stderr,
916 "usage: scp [-pqrvC] [-P port] [-c cipher] [-i identity] f1 f2; or:\n scp [options] f1 ... fn directory\n"); 948 "usage: scp [-pqrvC46] [-P port] [-c cipher] [-i identity] f1 f2; or:\n scp [options] f1 ... fn directory\n");
917 exit(1); 949 exit(1);
918} 950}
919 951
@@ -976,18 +1008,26 @@ run_err(const char *fmt,...)
976 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1008 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
977 * SUCH DAMAGE. 1009 * SUCH DAMAGE.
978 * 1010 *
979 * $Id: scp.c,v 1.15 1999/12/30 22:16:40 damien Exp $ 1011 * $Id: scp.c,v 1.16 2000/01/14 04:45:51 damien Exp $
980 */ 1012 */
981 1013
982char * 1014char *
983colon(cp) 1015colon(cp)
984 char *cp; 1016 char *cp;
985{ 1017{
1018 int flag = 0;
1019
986 if (*cp == ':') /* Leading colon is part of file name. */ 1020 if (*cp == ':') /* Leading colon is part of file name. */
987 return (0); 1021 return (0);
1022 if (*cp == '[')
1023 flag = 1;
988 1024
989 for (; *cp; ++cp) { 1025 for (; *cp; ++cp) {
990 if (*cp == ':') 1026 if (*cp == '@' && *(cp+1) == '[')
1027 flag = 1;
1028 if (*cp == ']' && *(cp+1) == ':' && flag)
1029 return (cp+1);
1030 if (*cp == ':' && !flag)
991 return (cp); 1031 return (cp);
992 if (*cp == '/') 1032 if (*cp == '/')
993 return (0); 1033 return (0);
diff --git a/servconf.c b/servconf.c
index 99cccbf21..3425fe0ee 100644
--- a/servconf.c
+++ b/servconf.c
@@ -12,20 +12,24 @@
12 */ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$Id: servconf.c,v 1.7 1999/11/25 00:54:59 damien Exp $"); 15RCSID("$Id: servconf.c,v 1.8 2000/01/14 04:45:51 damien Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "servconf.h" 18#include "servconf.h"
19#include "xmalloc.h" 19#include "xmalloc.h"
20 20
21/* add listen address */
22void add_listen_addr(ServerOptions *options, char *addr);
23
21/* Initializes the server options to their default values. */ 24/* Initializes the server options to their default values. */
22 25
23void 26void
24initialize_server_options(ServerOptions *options) 27initialize_server_options(ServerOptions *options)
25{ 28{
26 memset(options, 0, sizeof(*options)); 29 memset(options, 0, sizeof(*options));
27 options->port = -1; 30 options->num_ports = 0;
28 options->listen_addr.s_addr = htonl(INADDR_ANY); 31 options->ports_from_cmdline = 0;
32 options->listen_addrs = NULL;
29 options->host_key_file = NULL; 33 options->host_key_file = NULL;
30 options->server_key_bits = -1; 34 options->server_key_bits = -1;
31 options->login_grace_time = -1; 35 options->login_grace_time = -1;
@@ -68,16 +72,10 @@ initialize_server_options(ServerOptions *options)
68void 72void
69fill_default_server_options(ServerOptions *options) 73fill_default_server_options(ServerOptions *options)
70{ 74{
71 if (options->port == -1) { 75 if (options->num_ports == 0)
72 struct servent *sp; 76 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
73 77 if (options->listen_addrs == NULL)
74 sp = getservbyname(SSH_SERVICE_NAME, "tcp"); 78 add_listen_addr(options, NULL);
75 if (sp)
76 options->port = ntohs(sp->s_port);
77 else
78 options->port = SSH_DEFAULT_PORT;
79 endservent();
80 }
81 if (options->host_key_file == NULL) 79 if (options->host_key_file == NULL)
82 options->host_key_file = HOST_KEY_FILE; 80 options->host_key_file = HOST_KEY_FILE;
83 if (options->server_key_bits == -1) 81 if (options->server_key_bits == -1)
@@ -232,6 +230,37 @@ parse_token(const char *cp, const char *filename,
232 return sBadOption; 230 return sBadOption;
233} 231}
234 232
233/*
234 * add listen address
235 */
236void
237add_listen_addr(ServerOptions *options, char *addr)
238{
239 extern int IPv4or6;
240 struct addrinfo hints, *ai, *aitop;
241 char strport[NI_MAXSERV];
242 int gaierr;
243 int i;
244
245 if (options->num_ports == 0)
246 options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
247 for (i = 0; i < options->num_ports; i++) {
248 memset(&hints, 0, sizeof(hints));
249 hints.ai_family = IPv4or6;
250 hints.ai_socktype = SOCK_STREAM;
251 hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0;
252 snprintf(strport, sizeof strport, "%d", options->ports[i]);
253 if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0)
254 fatal("bad addr or host: %s (%s)\n",
255 addr ? addr : "<NULL>",
256 gai_strerror(gaierr));
257 for (ai = aitop; ai->ai_next; ai = ai->ai_next)
258 ;
259 ai->ai_next = options->listen_addrs;
260 options->listen_addrs = aitop;
261 }
262}
263
235/* Reads the server configuration file. */ 264/* Reads the server configuration file. */
236 265
237void 266void
@@ -262,7 +291,24 @@ read_server_config(ServerOptions *options, const char *filename)
262 bad_options++; 291 bad_options++;
263 continue; 292 continue;
264 case sPort: 293 case sPort:
265 intptr = &options->port; 294 /* ignore ports from configfile if cmdline specifies ports */
295 if (options->ports_from_cmdline)
296 continue;
297 if (options->listen_addrs != NULL)
298 fatal("%s line %d: ports must be specified before "
299 "ListenAdress.\n", filename, linenum);
300 if (options->num_ports >= MAX_PORTS)
301 fatal("%s line %d: too many ports.\n",
302 filename, linenum);
303 cp = strtok(NULL, WHITESPACE);
304 if (!cp)
305 fatal("%s line %d: missing port number.\n",
306 filename, linenum);
307 options->ports[options->num_ports++] = atoi(cp);
308 break;
309
310 case sServerKeyBits:
311 intptr = &options->server_key_bits;
266parse_int: 312parse_int:
267 cp = strtok(NULL, WHITESPACE); 313 cp = strtok(NULL, WHITESPACE);
268 if (!cp) { 314 if (!cp) {
@@ -275,10 +321,6 @@ parse_int:
275 *intptr = value; 321 *intptr = value;
276 break; 322 break;
277 323
278 case sServerKeyBits:
279 intptr = &options->server_key_bits;
280 goto parse_int;
281
282 case sLoginGraceTime: 324 case sLoginGraceTime:
283 intptr = &options->login_grace_time; 325 intptr = &options->login_grace_time;
284 goto parse_int; 326 goto parse_int;
@@ -289,12 +331,10 @@ parse_int:
289 331
290 case sListenAddress: 332 case sListenAddress:
291 cp = strtok(NULL, WHITESPACE); 333 cp = strtok(NULL, WHITESPACE);
292 if (!cp) { 334 if (!cp)
293 fprintf(stderr, "%s line %d: missing inet addr.\n", 335 fatal("%s line %d: missing inet addr.\n",
294 filename, linenum); 336 filename, linenum);
295 exit(1); 337 add_listen_addr(options, cp);
296 }
297 options->listen_addr.s_addr = inet_addr(cp);
298 break; 338 break;
299 339
300 case sHostKeyFile: 340 case sHostKeyFile:
diff --git a/servconf.h b/servconf.h
index e3ac5bdee..ab5c22c7d 100644
--- a/servconf.h
+++ b/servconf.h
@@ -13,20 +13,24 @@
13 * 13 *
14 */ 14 */
15 15
16/* RCSID("$Id: servconf.h,v 1.5 1999/11/25 00:54:59 damien Exp $"); */ 16/* RCSID("$Id: servconf.h,v 1.6 2000/01/14 04:45:51 damien Exp $"); */
17 17
18#ifndef SERVCONF_H 18#ifndef SERVCONF_H
19#define SERVCONF_H 19#define SERVCONF_H
20 20
21#define MAX_PORTS 256 /* Max # ports. */
22
21#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */ 23#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */
22#define MAX_DENY_USERS 256 /* Max # users on deny list. */ 24#define MAX_DENY_USERS 256 /* Max # users on deny list. */
23#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ 25#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */
24#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ 26#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
25 27
26typedef struct { 28typedef struct {
27 int port; /* Port number to listen on. */ 29 unsigned int num_ports;
28 struct in_addr listen_addr; /* Address on which the server 30 unsigned int ports_from_cmdline;
29 * listens. */ 31 u_short ports[MAX_PORTS]; /* Port number to listen on. */
32 char *listen_addr; /* Address on which the server listens. */
33 struct addrinfo *listen_addrs; /* Addresses on which the server listens. */
30 char *host_key_file; /* File containing host key. */ 34 char *host_key_file; /* File containing host key. */
31 int server_key_bits;/* Size of the server key. */ 35 int server_key_bits;/* Size of the server key. */
32 int login_grace_time; /* Disconnect if no auth in this time 36 int login_grace_time; /* Disconnect if no auth in this time
diff --git a/ssh.1.in b/ssh.1.in
index e19f87e13..d2ac0f2c2 100644
--- a/ssh.1.in
+++ b/ssh.1.in
@@ -9,7 +9,7 @@
9.\" 9.\"
10.\" Created: Sat Apr 22 21:55:14 1995 ylo 10.\" Created: Sat Apr 22 21:55:14 1995 ylo
11.\" 11.\"
12.\" $Id: ssh.1.in,v 1.1 1999/12/26 22:23:58 damien Exp $ 12.\" $Id: ssh.1.in,v 1.2 2000/01/14 04:45:51 damien Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SSH 1 15.Dt SSH 1
@@ -24,7 +24,7 @@
24.Op Ar command 24.Op Ar command
25.Pp 25.Pp
26.Nm ssh 26.Nm ssh
27.Op Fl afgknqtvxCPX 27.Op Fl afgknqtvxCPX46
28.Op Fl c Ar blowfish | 3des 28.Op Fl c Ar blowfish | 3des
29.Op Fl e Ar escape_char 29.Op Fl e Ar escape_char
30.Op Fl i Ar identity_file 30.Op Fl i Ar identity_file
@@ -396,9 +396,13 @@ by allocating a socket to listen to
396on the local side, and whenever a connection is made to this port, the 396on the local side, and whenever a connection is made to this port, the
397connection is forwarded over the secure channel, and a connection is 397connection is forwarded over the secure channel, and a connection is
398made to 398made to
399.Ar host:hostport 399.Ar host
400port
401.Ar hostport
400from the remote machine. Port forwardings can also be specified in the 402from the remote machine. Port forwardings can also be specified in the
401configuration file. Only root can forward privileged ports. 403configuration file. Only root can forward privileged ports.
404IPv6 addresses can be specified with an alternative syntax:
405.Ar port/host/hostport
402.It Fl R Ar port:host:hostport 406.It Fl R Ar port:host:hostport
403Specifies that the given port on the remote (server) host is to be 407Specifies that the given port on the remote (server) host is to be
404forwarded to the given host and port on the local side. This works 408forwarded to the given host and port on the local side. This works
@@ -407,10 +411,20 @@ by allocating a socket to listen to
407on the remote side, and whenever a connection is made to this port, the 411on the remote side, and whenever a connection is made to this port, the
408connection is forwarded over the secure channel, and a connection is 412connection is forwarded over the secure channel, and a connection is
409made to 413made to
410.Ar host:hostport 414.Ar host
415port
416.Ar hostport
411from the local machine. Port forwardings can also be specified in the 417from the local machine. Port forwardings can also be specified in the
412configuration file. Privileged ports can be forwarded only when 418configuration file. Privileged ports can be forwarded only when
413logging in as root on the remote machine. 419logging in as root on the remote machine.
420.It Fl 4
421Forces
422.Nm
423to use IPv4 addresses only.
424.It Fl 6
425Forces
426.Nm
427to use IPv6 addresses only.
414.El 428.El
415.Sh CONFIGURATION FILES 429.Sh CONFIGURATION FILES
416.Nm 430.Nm
diff --git a/ssh.c b/ssh.c
index f9e77220c..962aa2d43 100644
--- a/ssh.c
+++ b/ssh.c
@@ -11,7 +11,7 @@
11 */ 11 */
12 12
13#include "includes.h" 13#include "includes.h"
14RCSID("$Id: ssh.c,v 1.15 1999/12/28 23:17:09 damien Exp $"); 14RCSID("$Id: ssh.c,v 1.16 2000/01/14 04:45:51 damien Exp $");
15 15
16#include "xmalloc.h" 16#include "xmalloc.h"
17#include "ssh.h" 17#include "ssh.h"
@@ -27,6 +27,10 @@ extern char *__progname;
27const char *__progname = "ssh"; 27const char *__progname = "ssh";
28#endif /* HAVE___PROGNAME */ 28#endif /* HAVE___PROGNAME */
29 29
30/* Flag indicating whether IPv4 or IPv6. This can be set on the command line.
31 Default value is AF_UNSPEC means both IPv4 and IPv6. */
32int IPv4or6 = AF_UNSPEC;
33
30/* Flag indicating whether debug mode is on. This can be set on the command line. */ 34/* Flag indicating whether debug mode is on. This can be set on the command line. */
31int debug_flag = 0; 35int debug_flag = 0;
32 36
@@ -59,7 +63,7 @@ Options options;
59char *host; 63char *host;
60 64
61/* socket address the host resolves to */ 65/* socket address the host resolves to */
62struct sockaddr_in hostaddr; 66struct sockaddr_storage hostaddr;
63 67
64/* 68/*
65 * Flag to indicate that we have received a window change signal which has 69 * Flag to indicate that we have received a window change signal which has
@@ -114,6 +118,8 @@ usage()
114 fprintf(stderr, " forward them to the other side by connecting to host:port.\n"); 118 fprintf(stderr, " forward them to the other side by connecting to host:port.\n");
115 fprintf(stderr, " -C Enable compression.\n"); 119 fprintf(stderr, " -C Enable compression.\n");
116 fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n"); 120 fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n");
121 fprintf(stderr, " -4 Use IPv4 only.\n");
122 fprintf(stderr, " -6 Use IPv6 only.\n");
117 fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n"); 123 fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n");
118 exit(1); 124 exit(1);
119} 125}
@@ -227,6 +233,8 @@ main(int ac, char **av)
227 if (host) 233 if (host)
228 break; 234 break;
229 if ((cp = strchr(av[optind], '@'))) { 235 if ((cp = strchr(av[optind], '@'))) {
236 if(cp == av[optind])
237 usage();
230 options.user = av[optind]; 238 options.user = av[optind];
231 *cp = '\0'; 239 *cp = '\0';
232 host = ++cp; 240 host = ++cp;
@@ -250,6 +258,14 @@ main(int ac, char **av)
250 optarg = NULL; 258 optarg = NULL;
251 } 259 }
252 switch (opt) { 260 switch (opt) {
261 case '4':
262 IPv4or6 = AF_INET;
263 break;
264
265 case '6':
266 IPv4or6 = AF_INET6;
267 break;
268
253 case 'n': 269 case 'n':
254 stdin_null_flag = 1; 270 stdin_null_flag = 1;
255 break; 271 break;
@@ -351,8 +367,10 @@ main(int ac, char **av)
351 break; 367 break;
352 368
353 case 'R': 369 case 'R':
354 if (sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf, 370 if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
355 &fwd_host_port) != 3) { 371 &fwd_host_port) != 3 &&
372 sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
373 &fwd_host_port) != 3) {
356 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg); 374 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
357 usage(); 375 usage();
358 /* NOTREACHED */ 376 /* NOTREACHED */
@@ -361,8 +379,10 @@ main(int ac, char **av)
361 break; 379 break;
362 380
363 case 'L': 381 case 'L':
364 if (sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf, 382 if (sscanf(optarg, "%hu/%255[^/]/%hu", &fwd_port, buf,
365 &fwd_host_port) != 3) { 383 &fwd_host_port) != 3 &&
384 sscanf(optarg, "%hu:%255[^:]:%hu", &fwd_port, buf,
385 &fwd_host_port) != 3) {
366 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg); 386 fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
367 usage(); 387 usage();
368 /* NOTREACHED */ 388 /* NOTREACHED */
@@ -473,14 +493,18 @@ main(int ac, char **av)
473 493
474 /* Find canonic host name. */ 494 /* Find canonic host name. */
475 if (strchr(host, '.') == 0) { 495 if (strchr(host, '.') == 0) {
476 struct hostent *hp = gethostbyname(host); 496 struct addrinfo hints;
477 if (hp != 0) { 497 struct addrinfo *ai = NULL;
478 if (strchr(hp->h_name, '.') != 0) 498 int errgai;
479 host = xstrdup(hp->h_name); 499 memset(&hints, 0, sizeof(hints));
480 else if (hp->h_aliases != 0 500 hints.ai_family = AF_UNSPEC;
481 && hp->h_aliases[0] != 0 501 hints.ai_flags = AI_CANONNAME;
482 && strchr(hp->h_aliases[0], '.') != 0) 502 hints.ai_socktype = SOCK_STREAM;
483 host = xstrdup(hp->h_aliases[0]); 503 errgai = getaddrinfo(host, NULL, &hints, &ai);
504 if (errgai == 0) {
505 if (ai->ai_canonname != NULL)
506 host = xstrdup(ai->ai_canonname);
507 freeaddrinfo(ai);
484 } 508 }
485 } 509 }
486 /* Disable rhosts authentication if not running as root. */ 510 /* Disable rhosts authentication if not running as root. */
@@ -587,7 +611,7 @@ main(int ac, char **av)
587 611
588 /* Log into the remote system. This never returns if the login fails. */ 612 /* Log into the remote system. This never returns if the login fails. */
589 ssh_login(host_private_key_loaded, host_private_key, 613 ssh_login(host_private_key_loaded, host_private_key,
590 host, &hostaddr, original_real_uid); 614 host, (struct sockaddr *)&hostaddr, original_real_uid);
591 615
592 /* We no longer need the host private key. Clear it now. */ 616 /* We no longer need the host private key. Clear it now. */
593 if (host_private_key_loaded) 617 if (host_private_key_loaded)
diff --git a/ssh.h b/ssh.h
index ddc6fe073..0f3302a69 100644
--- a/ssh.h
+++ b/ssh.h
@@ -13,7 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16/* RCSID("$Id: ssh.h,v 1.23 1999/12/30 04:50:55 damien Exp $"); */ 16/* RCSID("$Id: ssh.h,v 1.24 2000/01/14 04:45:52 damien Exp $"); */
17 17
18#ifndef SSH_H 18#ifndef SSH_H
19#define SSH_H 19#define SSH_H
@@ -21,6 +21,8 @@
21#include <netinet/in.h> /* For struct sockaddr_in */ 21#include <netinet/in.h> /* For struct sockaddr_in */
22#include <pwd.h> /* For struct pw */ 22#include <pwd.h> /* For struct pw */
23#include <stdarg.h> /* For va_list */ 23#include <stdarg.h> /* For va_list */
24#include <sys/socket.h> /* For struct sockaddr_storage */
25#include "fake-socket.h" /* For struct sockaddr_storage */
24#ifdef HAVE_SYS_SELECT_H 26#ifdef HAVE_SYS_SELECT_H
25# include <sys/select.h> 27# include <sys/select.h>
26#endif 28#endif
@@ -284,7 +286,7 @@ get_last_login_time(uid_t uid, const char *logname,
284 */ 286 */
285void 287void
286record_login(int pid, const char *ttyname, const char *user, uid_t uid, 288record_login(int pid, const char *ttyname, const char *user, uid_t uid,
287 const char *host, struct sockaddr_in * addr); 289 const char *host, struct sockaddr *addr);
288 290
289/* 291/*
290 * Records that the user has logged out. This does many thigs normally done 292 * Records that the user has logged out. This does many thigs normally done
@@ -304,7 +306,7 @@ void record_logout(int pid, const char *ttyname);
304 * packet_set_connection for the connection. 306 * packet_set_connection for the connection.
305 */ 307 */
306int 308int
307ssh_connect(const char *host, struct sockaddr_in * hostaddr, 309ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
308 u_short port, int connection_attempts, 310 u_short port, int connection_attempts,
309 int anonymous, uid_t original_real_uid, 311 int anonymous, uid_t original_real_uid,
310 const char *proxy_command); 312 const char *proxy_command);
@@ -320,7 +322,7 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
320 322
321void 323void
322ssh_login(int host_key_valid, RSA * host_key, const char *host, 324ssh_login(int host_key_valid, RSA * host_key, const char *host,
323 struct sockaddr_in * hostaddr, uid_t original_real_uid); 325 struct sockaddr * hostaddr, uid_t original_real_uid);
324 326
325/*------------ Definitions for various authentication methods. -------*/ 327/*------------ Definitions for various authentication methods. -------*/
326 328
@@ -380,8 +382,10 @@ const char *get_remote_ipaddr(void);
380/* Returns the port number of the peer of the socket. */ 382/* Returns the port number of the peer of the socket. */
381int get_peer_port(int sock); 383int get_peer_port(int sock);
382 384
383/* Returns the port number of the remote host. */ 385/* Returns the port number of the remote/local host. */
384int get_remote_port(void); 386int get_remote_port(void);
387int get_local_port(void);
388
385 389
386/* 390/*
387 * Tries to match the host name (which must be in all lowercase) against the 391 * Tries to match the host name (which must be in all lowercase) against the
@@ -741,6 +745,9 @@ char *skey_fake_keyinfo(char *username);
741int auth_skey_password(struct passwd * pw, const char *password); 745int auth_skey_password(struct passwd * pw, const char *password);
742#endif /* SKEY */ 746#endif /* SKEY */
743 747
748/* AF_UNSPEC or AF_INET or AF_INET6 */
749extern int IPv4or6;
750
744#ifdef USE_PAM 751#ifdef USE_PAM
745#include "auth-pam.h" 752#include "auth-pam.h"
746#endif /* USE_PAM */ 753#endif /* USE_PAM */
diff --git a/sshconnect.c b/sshconnect.c
index e19392acf..fb6af67df 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -8,7 +8,7 @@
8 */ 8 */
9 9
10#include "includes.h" 10#include "includes.h"
11RCSID("$Id: sshconnect.c,v 1.20 2000/01/03 12:41:05 damien Exp $"); 11RCSID("$Id: sshconnect.c,v 1.21 2000/01/14 04:45:52 damien Exp $");
12 12
13#ifdef HAVE_OPENSSL 13#ifdef HAVE_OPENSSL
14#include <openssl/bn.h> 14#include <openssl/bn.h>
@@ -35,6 +35,7 @@ RCSID("$Id: sshconnect.c,v 1.20 2000/01/03 12:41:05 damien Exp $");
35unsigned char session_id[16]; 35unsigned char session_id[16];
36 36
37extern Options options; 37extern Options options;
38extern char *__progname;
38 39
39/* 40/*
40 * Connect to the given ssh server using a proxy command. 41 * Connect to the given ssh server using a proxy command.
@@ -48,10 +49,10 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
48 char *command_string; 49 char *command_string;
49 int pin[2], pout[2]; 50 int pin[2], pout[2];
50 int pid; 51 int pid;
51 char portstring[100]; 52 char strport[NI_MAXSERV];
52 53
53 /* Convert the port number into a string. */ 54 /* Convert the port number into a string. */
54 snprintf(portstring, sizeof portstring, "%hu", port); 55 snprintf(strport, sizeof strport, "%hu", port);
55 56
56 /* Build the final command string in the buffer by making the 57 /* Build the final command string in the buffer by making the
57 appropriate substitutions to the given proxy command. */ 58 appropriate substitutions to the given proxy command. */
@@ -68,7 +69,7 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
68 continue; 69 continue;
69 } 70 }
70 if (cp[0] == '%' && cp[1] == 'p') { 71 if (cp[0] == '%' && cp[1] == 'p') {
71 buffer_append(&command, portstring, strlen(portstring)); 72 buffer_append(&command, strport, strlen(strport));
72 cp++; 73 cp++;
73 continue; 74 continue;
74 } 75 }
@@ -140,7 +141,7 @@ ssh_proxy_connect(const char *host, u_short port, uid_t original_real_uid,
140 * Creates a (possibly privileged) socket for use as the ssh connection. 141 * Creates a (possibly privileged) socket for use as the ssh connection.
141 */ 142 */
142int 143int
143ssh_create_socket(uid_t original_real_uid, int privileged) 144ssh_create_socket(uid_t original_real_uid, int privileged, int family)
144{ 145{
145 int sock; 146 int sock;
146 147
@@ -150,10 +151,9 @@ ssh_create_socket(uid_t original_real_uid, int privileged)
150 */ 151 */
151 if (privileged) { 152 if (privileged) {
152 int p = IPPORT_RESERVED - 1; 153 int p = IPPORT_RESERVED - 1;
153 154 sock = rresvport_af(&p, family);
154 sock = rresvport(&p);
155 if (sock < 0) 155 if (sock < 0)
156 fatal("rresvport: %.100s", strerror(errno)); 156 fatal("rresvport: af=%d %.100s", family, strerror(errno));
157 debug("Allocated local port %d.", p); 157 debug("Allocated local port %d.", p);
158 } else { 158 } else {
159 /* 159 /*
@@ -161,17 +161,18 @@ ssh_create_socket(uid_t original_real_uid, int privileged)
161 * the user's uid to create the socket. 161 * the user's uid to create the socket.
162 */ 162 */
163 temporarily_use_uid(original_real_uid); 163 temporarily_use_uid(original_real_uid);
164 sock = socket(AF_INET, SOCK_STREAM, 0); 164 sock = socket(family, SOCK_STREAM, 0);
165 if (sock < 0) 165 if (sock < 0)
166 fatal("socket: %.100s", strerror(errno)); 166 error("socket: %.100s", strerror(errno));
167 restore_uid(); 167 restore_uid();
168 } 168 }
169 return sock; 169 return sock;
170} 170}
171 171
172/* 172/*
173 * Opens a TCP/IP connection to the remote server on the given host. If 173 * Opens a TCP/IP connection to the remote server on the given host.
174 * port is 0, the default port will be used. If anonymous is zero, 174 * The address of the remote host will be returned in hostaddr.
175 * If port is 0, the default port will be used. If anonymous is zero,
175 * a privileged port will be allocated to make the connection. 176 * a privileged port will be allocated to make the connection.
176 * This requires super-user privileges if anonymous is false. 177 * This requires super-user privileges if anonymous is false.
177 * Connection_attempts specifies the maximum number of tries (one per 178 * Connection_attempts specifies the maximum number of tries (one per
@@ -180,15 +181,16 @@ ssh_create_socket(uid_t original_real_uid, int privileged)
180 * the daemon. 181 * the daemon.
181 */ 182 */
182int 183int
183ssh_connect(const char *host, struct sockaddr_in * hostaddr, 184ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
184 u_short port, int connection_attempts, 185 u_short port, int connection_attempts,
185 int anonymous, uid_t original_real_uid, 186 int anonymous, uid_t original_real_uid,
186 const char *proxy_command) 187 const char *proxy_command)
187{ 188{
188 int sock = -1, attempt, i; 189 int sock = -1, attempt;
189 int on = 1;
190 struct servent *sp; 190 struct servent *sp;
191 struct hostent *hp; 191 struct addrinfo hints, *ai, *aitop;
192 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
193 int gaierr;
192 struct linger linger; 194 struct linger linger;
193 195
194 debug("ssh_connect: getuid %d geteuid %d anon %d", 196 debug("ssh_connect: getuid %d geteuid %d anon %d",
@@ -208,8 +210,13 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
208 210
209 /* No proxy command. */ 211 /* No proxy command. */
210 212
211 /* No host lookup made yet. */ 213 memset(&hints, 0, sizeof(hints));
212 hp = NULL; 214 hints.ai_family = IPv4or6;
215 hints.ai_socktype = SOCK_STREAM;
216 snprintf(strport, sizeof strport, "%d", port);
217 if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
218 fatal("%s: %.100s: %s", __progname, host,
219 gai_strerror(gaierr));
213 220
214 /* 221 /*
215 * Try to connect several times. On some machines, the first time 222 * Try to connect several times. On some machines, the first time
@@ -220,82 +227,40 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
220 if (attempt > 0) 227 if (attempt > 0)
221 debug("Trying again..."); 228 debug("Trying again...");
222 229
223 /* Try to parse the host name as a numeric inet address. */ 230 /* Loop through addresses for this host, and try each one in
224 memset(hostaddr, 0, sizeof(hostaddr)); 231 sequence until the connection succeeds. */
225 hostaddr->sin_family = AF_INET; 232 for (ai = aitop; ai; ai = ai->ai_next) {
226 hostaddr->sin_port = htons(port); 233 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
227 hostaddr->sin_addr.s_addr = inet_addr(host); 234 continue;
228 if ((hostaddr->sin_addr.s_addr & 0xffffffff) != 0xffffffff) { 235 if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
229 /* Valid numeric IP address */ 236 ntop, sizeof(ntop), strport, sizeof(strport),
230 debug("Connecting to %.100s port %d.", 237 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
231 inet_ntoa(hostaddr->sin_addr), port); 238 error("ssh_connect: getnameinfo failed");
232 239 continue;
233 /* Create a socket. */ 240 }
234 sock = ssh_create_socket(original_real_uid, 241 debug("Connecting to %.200s [%.100s] port %s.",
235 !anonymous && geteuid() == 0 && 242 host, ntop, strport);
236 port < IPPORT_RESERVED); 243
237 244 /* Create a socket for connecting. */
238 /* 245 sock = ssh_create_socket(original_real_uid,
239 * Connect to the host. We use the user's uid in the 246 !anonymous && geteuid() == 0 && port < IPPORT_RESERVED,
240 * hope that it will help with the problems of 247 ai->ai_family);
241 * tcp_wrappers showing the remote uid as root. 248 if (sock < 0)
249 continue;
250
251 /* Connect to the host. We use the user's uid in the
252 * hope that it will help with tcp_wrappers showing
253 * the remote uid as root.
242 */ 254 */
243 temporarily_use_uid(original_real_uid); 255 temporarily_use_uid(original_real_uid);
244 if (connect(sock, (struct sockaddr *) hostaddr, sizeof(*hostaddr)) 256 if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) {
245 >= 0) { 257 /* Successful connection. */
246 /* Successful connect. */ 258 memcpy(hostaddr, ai->ai_addr, sizeof(*(ai->ai_addr)));
247 restore_uid(); 259 restore_uid();
248 break; 260 break;
249 } 261 } else {
250 debug("connect: %.100s", strerror(errno));
251 restore_uid();
252
253 /* Destroy the failed socket. */
254 shutdown(sock, SHUT_RDWR);
255 close(sock);
256 } else {
257 /* Not a valid numeric inet address. */
258 /* Map host name to an address. */
259 if (!hp)
260 hp = gethostbyname(host);
261 if (!hp)
262 fatal("Bad host name: %.100s", host);
263 if (!hp->h_addr_list[0])
264 fatal("Host does not have an IP address: %.100s", host);
265
266 /* Loop through addresses for this host, and try
267 each one in sequence until the connection
268 succeeds. */
269 for (i = 0; hp->h_addr_list[i]; i++) {
270 /* Set the address to connect to. */
271 hostaddr->sin_family = hp->h_addrtype;
272 memcpy(&hostaddr->sin_addr, hp->h_addr_list[i],
273 sizeof(hostaddr->sin_addr));
274
275 debug("Connecting to %.200s [%.100s] port %d.",
276 host, inet_ntoa(hostaddr->sin_addr), port);
277
278 /* Create a socket for connecting. */
279 sock = ssh_create_socket(original_real_uid,
280 !anonymous && geteuid() == 0 &&
281 port < IPPORT_RESERVED);
282
283 /*
284 * Connect to the host. We use the user's
285 * uid in the hope that it will help with
286 * tcp_wrappers showing the remote uid as
287 * root.
288 */
289 temporarily_use_uid(original_real_uid);
290 if (connect(sock, (struct sockaddr *) hostaddr,
291 sizeof(*hostaddr)) >= 0) {
292 /* Successful connection. */
293 restore_uid();
294 break;
295 }
296 debug("connect: %.100s", strerror(errno)); 262 debug("connect: %.100s", strerror(errno));
297 restore_uid(); 263 restore_uid();
298
299 /* 264 /*
300 * Close the failed socket; there appear to 265 * Close the failed socket; there appear to
301 * be some problems when reusing a socket for 266 * be some problems when reusing a socket for
@@ -305,13 +270,16 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
305 shutdown(sock, SHUT_RDWR); 270 shutdown(sock, SHUT_RDWR);
306 close(sock); 271 close(sock);
307 } 272 }
308 if (hp->h_addr_list[i])
309 break; /* Successful connection. */
310 } 273 }
274 if (ai)
275 break; /* Successful connection. */
311 276
312 /* Sleep a moment before retrying. */ 277 /* Sleep a moment before retrying. */
313 sleep(1); 278 sleep(1);
314 } 279 }
280
281 freeaddrinfo(aitop);
282
315 /* Return failure if we didn't get a successful connection. */ 283 /* Return failure if we didn't get a successful connection. */
316 if (attempt >= connection_attempts) 284 if (attempt >= connection_attempts)
317 return 0; 285 return 0;
@@ -323,7 +291,6 @@ ssh_connect(const char *host, struct sockaddr_in * hostaddr,
323 * as it has been closed for whatever reason. 291 * as it has been closed for whatever reason.
324 */ 292 */
325 /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ 293 /* setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */
326 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
327 linger.l_onoff = 1; 294 linger.l_onoff = 1;
328 linger.l_linger = 5; 295 linger.l_linger = 5;
329 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); 296 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
@@ -1095,17 +1062,43 @@ read_yes_or_no(const char *prompt, int defval)
1095 */ 1062 */
1096 1063
1097void 1064void
1098check_host_key(char *host, 1065check_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key)
1099 struct sockaddr_in *hostaddr,
1100 RSA *host_key)
1101{ 1066{
1102 RSA *file_key; 1067 RSA *file_key;
1103 char *ip = NULL; 1068 char *ip = NULL;
1104 char hostline[1000], *hostp; 1069 char hostline[1000], *hostp;
1105 HostStatus host_status; 1070 HostStatus host_status;
1106 HostStatus ip_status; 1071 HostStatus ip_status;
1107 int host_ip_differ = 0; 1072 int local = 0, host_ip_differ = 0;
1108 int local = (ntohl(hostaddr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; 1073 int sa_len;
1074 char ntop[NI_MAXHOST];
1075
1076 /*
1077 * Force accepting of the host key for loopback/localhost. The
1078 * problem is that if the home directory is NFS-mounted to multiple
1079 * machines, localhost will refer to a different machine in each of
1080 * them, and the user will get bogus HOST_CHANGED warnings. This
1081 * essentially disables host authentication for localhost; however,
1082 * this is probably not a real problem.
1083 */
1084 switch (hostaddr->sa_family) {
1085 case AF_INET:
1086 local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
1087 sa_len = sizeof(struct sockaddr_in);
1088 break;
1089 case AF_INET6:
1090 local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
1091 sa_len = sizeof(struct sockaddr_in6);
1092 break;
1093 default:
1094 local = 0;
1095 sa_len = sizeof(struct sockaddr_storage);
1096 break;
1097 }
1098 if (local) {
1099 debug("Forcing accepting of host key for loopback/localhost.");
1100 return;
1101 }
1109 1102
1110 /* 1103 /*
1111 * Turn off check_host_ip for proxy connects, since 1104 * Turn off check_host_ip for proxy connects, since
@@ -1114,8 +1107,12 @@ check_host_key(char *host,
1114 if (options.proxy_command != NULL && options.check_host_ip) 1107 if (options.proxy_command != NULL && options.check_host_ip)
1115 options.check_host_ip = 0; 1108 options.check_host_ip = 0;
1116 1109
1117 if (options.check_host_ip) 1110 if (options.check_host_ip) {
1118 ip = xstrdup(inet_ntoa(hostaddr->sin_addr)); 1111 if (getnameinfo(hostaddr, sa_len, ntop, sizeof(ntop),
1112 NULL, 0, NI_NUMERICHOST) != 0)
1113 fatal("check_host_key: getnameinfo failed");
1114 ip = xstrdup(ntop);
1115 }
1119 1116
1120 /* 1117 /*
1121 * Store the host key from the known host file in here so that we can 1118 * Store the host key from the known host file in here so that we can
@@ -1137,18 +1134,6 @@ check_host_key(char *host,
1137 host_key->e, host_key->n, 1134 host_key->e, host_key->n,
1138 file_key->e, file_key->n); 1135 file_key->e, file_key->n);
1139 /* 1136 /*
1140 * Force accepting of the host key for localhost and 127.0.0.1. The
1141 * problem is that if the home directory is NFS-mounted to multiple
1142 * machines, localhost will refer to a different machine in each of
1143 * them, and the user will get bogus HOST_CHANGED warnings. This
1144 * essentially disables host authentication for localhost; however,
1145 * this is probably not a real problem.
1146 */
1147 if (local) {
1148 debug("Forcing accepting of host key for localhost.");
1149 host_status = HOST_OK;
1150 }
1151 /*
1152 * Also perform check for the ip address, skip the check if we are 1137 * Also perform check for the ip address, skip the check if we are
1153 * localhost or the hostname was an ip address to begin with 1138 * localhost or the hostname was an ip address to begin with
1154 */ 1139 */
@@ -1301,7 +1286,7 @@ void
1301ssh_login(int host_key_valid, 1286ssh_login(int host_key_valid,
1302 RSA *own_host_key, 1287 RSA *own_host_key,
1303 const char *orighost, 1288 const char *orighost,
1304 struct sockaddr_in *hostaddr, 1289 struct sockaddr *hostaddr,
1305 uid_t original_real_uid) 1290 uid_t original_real_uid)
1306{ 1291{
1307 int i, type; 1292 int i, type;
diff --git a/sshd.8.in b/sshd.8.in
index 871e79ed9..b5d925b87 100644
--- a/sshd.8.in
+++ b/sshd.8.in
@@ -9,7 +9,7 @@
9.\" 9.\"
10.\" Created: Sat Apr 22 21:55:14 1995 ylo 10.\" Created: Sat Apr 22 21:55:14 1995 ylo
11.\" 11.\"
12.\" $Id: sshd.8.in,v 1.1 1999/12/26 22:23:59 damien Exp $ 12.\" $Id: sshd.8.in,v 1.2 2000/01/14 04:45:52 damien Exp $
13.\" 13.\"
14.Dd September 25, 1999 14.Dd September 25, 1999
15.Dt SSHD 8 15.Dt SSHD 8
@@ -19,7 +19,7 @@
19.Nd secure shell daemon 19.Nd secure shell daemon
20.Sh SYNOPSIS 20.Sh SYNOPSIS
21.Nm sshd 21.Nm sshd
22.Op Fl diqQ 22.Op Fl diqQ46
23.Op Fl b Ar bits 23.Op Fl b Ar bits
24.Op Fl f Ar config_file 24.Op Fl f Ar config_file
25.Op Fl g Ar login_grace_time 25.Op Fl g Ar login_grace_time
@@ -173,6 +173,14 @@ When this options is specified
173assumes the client has sent the given version string 173assumes the client has sent the given version string
174and skips the 174and skips the
175Protocol Version Identification Exchange. 175Protocol Version Identification Exchange.
176.It Fl 4
177Forces
178.Nm
179to use IPv4 addresses only.
180.It Fl 6
181Forces
182.Nm
183to use IPv6 addresses only.
176.El 184.El
177.Sh CONFIGURATION FILE 185.Sh CONFIGURATION FILE
178.Nm 186.Nm
@@ -320,6 +328,10 @@ Specifies what local address
320.Nm 328.Nm
321should listen on. 329should listen on.
322The default is to listen to all local addresses. 330The default is to listen to all local addresses.
331Multiple options of this type are permitted.
332Additionally, the
333.Cm Ports
334options must precede this option.
323.It Cm LoginGraceTime 335.It Cm LoginGraceTime
324The server disconnects after this time if the user has not 336The server disconnects after this time if the user has not
325successfully logged in. If the value is 0, there is no time limit. 337successfully logged in. If the value is 0, there is no time limit.
@@ -365,6 +377,7 @@ normally not allowed).
365Specifies the port number that 377Specifies the port number that
366.Nm 378.Nm
367listens on. The default is 22. 379listens on. The default is 22.
380Multiple options of this type are permitted.
368.It Cm PrintMotd 381.It Cm PrintMotd
369Specifies whether 382Specifies whether
370.Nm 383.Nm
diff --git a/sshd.c b/sshd.c
index 0cf664087..316723a83 100644
--- a/sshd.c
+++ b/sshd.c
@@ -11,7 +11,7 @@
11 */ 11 */
12 12
13#include "includes.h" 13#include "includes.h"
14RCSID("$Id: sshd.c,v 1.49 1999/12/30 04:08:44 damien Exp $"); 14RCSID("$Id: sshd.c,v 1.50 2000/01/14 04:45:52 damien Exp $");
15 15
16#include "xmalloc.h" 16#include "xmalloc.h"
17#include "rsa.h" 17#include "rsa.h"
@@ -45,6 +45,12 @@ ServerOptions options;
45/* Name of the server configuration file. */ 45/* Name of the server configuration file. */
46char *config_file_name = SERVER_CONFIG_FILE; 46char *config_file_name = SERVER_CONFIG_FILE;
47 47
48/*
49 * Flag indicating whether IPv4 or IPv6. This can be set on the command line.
50 * Default value is AF_UNSPEC means both IPv4 and IPv6.
51 */
52int IPv4or6 = AF_UNSPEC;
53
48/* 54/*
49 * Debug mode flag. This can be set on the command line. If debug 55 * Debug mode flag. This can be set on the command line. If debug
50 * mode is enabled, extra debugging output will be sent to the system 56 * mode is enabled, extra debugging output will be sent to the system
@@ -66,10 +72,12 @@ char *av0;
66char **saved_argv; 72char **saved_argv;
67 73
68/* 74/*
69 * This is set to the socket that the server is listening; this is used in 75 * The sockets that the server is listening; this is used in the SIGHUP
70 * the SIGHUP signal handler. 76 * signal handler.
71 */ 77 */
72int listen_sock; 78#define MAX_LISTEN_SOCKS 16
79int listen_socks[MAX_LISTEN_SOCKS];
80int num_listen_socks = 0;
73 81
74/* 82/*
75 * the client's version string, passed by sshd2 in compat mode. if != NULL, 83 * the client's version string, passed by sshd2 in compat mode. if != NULL,
@@ -136,6 +144,18 @@ void do_child(const char *command, struct passwd * pw, const char *term,
136 const char *auth_data, const char *ttyname); 144 const char *auth_data, const char *ttyname);
137 145
138/* 146/*
147 * Close all listening sockets
148 */
149void
150close_listen_socks(void)
151{
152 int i;
153 for (i = 0; i < num_listen_socks; i++)
154 close(listen_socks[i]);
155 num_listen_socks = -1;
156}
157
158/*
139 * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP; 159 * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP;
140 * the effect is to reread the configuration file (and to regenerate 160 * the effect is to reread the configuration file (and to regenerate
141 * the server key). 161 * the server key).
@@ -155,7 +175,7 @@ void
155sighup_restart() 175sighup_restart()
156{ 176{
157 log("Received SIGHUP; restarting."); 177 log("Received SIGHUP; restarting.");
158 close(listen_sock); 178 close_listen_socks();
159 execv(saved_argv[0], saved_argv); 179 execv(saved_argv[0], saved_argv);
160 log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno)); 180 log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno));
161 exit(1); 181 exit(1);
@@ -170,7 +190,7 @@ void
170sigterm_handler(int sig) 190sigterm_handler(int sig)
171{ 191{
172 log("Received signal %d; terminating.", sig); 192 log("Received signal %d; terminating.", sig);
173 close(listen_sock); 193 close_listen_socks();
174 exit(255); 194 exit(255);
175} 195}
176 196
@@ -277,11 +297,12 @@ main(int ac, char **av)
277{ 297{
278 extern char *optarg; 298 extern char *optarg;
279 extern int optind; 299 extern int optind;
280 int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1; 300 int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, pid, on = 1;
301 socklen_t fromlen;
281 int remote_major, remote_minor; 302 int remote_major, remote_minor;
282 int silentrsa = 0; 303 int silentrsa = 0;
283 struct pollfd fds; 304 fd_set *fdset;
284 struct sockaddr_in sin; 305 struct sockaddr_storage from;
285 char buf[100]; /* Must not be larger than remote_version. */ 306 char buf[100]; /* Must not be larger than remote_version. */
286 char remote_version[100]; /* Must be at least as big as buf. */ 307 char remote_version[100]; /* Must be at least as big as buf. */
287 const char *remote_ip; 308 const char *remote_ip;
@@ -289,6 +310,9 @@ main(int ac, char **av)
289 char *comment; 310 char *comment;
290 FILE *f; 311 FILE *f;
291 struct linger linger; 312 struct linger linger;
313 struct addrinfo *ai;
314 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
315 int listen_sock, maxfd;
292 316
293 /* Save argv[0]. */ 317 /* Save argv[0]. */
294 saved_argv = av; 318 saved_argv = av;
@@ -301,8 +325,14 @@ main(int ac, char **av)
301 initialize_server_options(&options); 325 initialize_server_options(&options);
302 326
303 /* Parse command-line arguments. */ 327 /* Parse command-line arguments. */
304 while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ")) != EOF) { 328 while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) {
305 switch (opt) { 329 switch (opt) {
330 case '4':
331 IPv4or6 = AF_INET;
332 break;
333 case '6':
334 IPv4or6 = AF_INET6;
335 break;
306 case 'f': 336 case 'f':
307 config_file_name = optarg; 337 config_file_name = optarg;
308 break; 338 break;
@@ -323,7 +353,10 @@ main(int ac, char **av)
323 options.server_key_bits = atoi(optarg); 353 options.server_key_bits = atoi(optarg);
324 break; 354 break;
325 case 'p': 355 case 'p':
326 options.port = atoi(optarg); 356 options.ports_from_cmdline = 1;
357 if (options.num_ports >= MAX_PORTS)
358 fatal("too many ports.\n");
359 options.ports[options.num_ports++] = atoi(optarg);
327 break; 360 break;
328 case 'g': 361 case 'g':
329 options.login_grace_time = atoi(optarg); 362 options.login_grace_time = atoi(optarg);
@@ -356,11 +389,22 @@ main(int ac, char **av)
356 fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n"); 389 fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n");
357 fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n"); 390 fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n");
358 fprintf(stderr, " -h file File from which to read host key (default: %s)\n", 391 fprintf(stderr, " -h file File from which to read host key (default: %s)\n",
359 HOST_KEY_FILE); 392 HOST_KEY_FILE);
393 fprintf(stderr, " -4 Use IPv4 only\n");
394 fprintf(stderr, " -6 Use IPv6 only\n");
360 exit(1); 395 exit(1);
361 } 396 }
362 } 397 }
363 398
399 /*
400 * Force logging to stderr until we have loaded the private host
401 * key (unless started from inetd)
402 */
403 log_init(av0,
404 options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
405 options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,
406 !inetd_flag);
407
364 /* check if RSA support exists */ 408 /* check if RSA support exists */
365 if (rsa_alive() == 0) { 409 if (rsa_alive() == 0) {
366 if (silentrsa == 0) 410 if (silentrsa == 0)
@@ -380,18 +424,11 @@ main(int ac, char **av)
380 fprintf(stderr, "Bad server key size.\n"); 424 fprintf(stderr, "Bad server key size.\n");
381 exit(1); 425 exit(1);
382 } 426 }
383 if (options.port < 1 || options.port > 65535) {
384 fprintf(stderr, "Bad port number.\n");
385 exit(1);
386 }
387 /* Check that there are no remaining arguments. */ 427 /* Check that there are no remaining arguments. */
388 if (optind < ac) { 428 if (optind < ac) {
389 fprintf(stderr, "Extra argument %s.\n", av[optind]); 429 fprintf(stderr, "Extra argument %s.\n", av[optind]);
390 exit(1); 430 exit(1);
391 } 431 }
392 /* Force logging to stderr while loading the private host key
393 unless started from inetd */
394 log_init(av0, options.log_level, options.log_facility, !inetd_flag);
395 432
396 debug("sshd version %.100s", SSH_VERSION); 433 debug("sshd version %.100s", SSH_VERSION);
397 434
@@ -480,32 +517,66 @@ main(int ac, char **av)
480 arc4random_stir(); 517 arc4random_stir();
481 log("RSA key generation complete."); 518 log("RSA key generation complete.");
482 } else { 519 } else {
483 /* Create socket for listening. */ 520 for (ai = options.listen_addrs; ai; ai = ai->ai_next) {
484 listen_sock = socket(AF_INET, SOCK_STREAM, 0); 521 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
485 if (listen_sock < 0) 522 continue;
486 fatal("socket: %.100s", strerror(errno)); 523 if (num_listen_socks >= MAX_LISTEN_SOCKS)
487 524 fatal("Too many listen sockets. "
488 /* Set socket options. We try to make the port reusable 525 "Enlarge MAX_LISTEN_SOCKS");
489 and have it close as fast as possible without waiting 526 if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
490 in unnecessary wait states on close. */ 527 ntop, sizeof(ntop), strport, sizeof(strport),
491 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, 528 NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
492 sizeof(on)); 529 error("getnameinfo failed");
493 linger.l_onoff = 1; 530 continue;
494 linger.l_linger = 5; 531 }
495 setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *) &linger, 532 /* Create socket for listening. */
496 sizeof(linger)); 533 listen_sock = socket(ai->ai_family, SOCK_STREAM, 0);
497 534 if (listen_sock < 0) {
498 memset(&sin, 0, sizeof(sin)); 535 /* kernel may not support ipv6 */
499 sin.sin_family = AF_INET; 536 verbose("socket: %.100s", strerror(errno));
500 sin.sin_addr = options.listen_addr; 537 continue;
501 sin.sin_port = htons(options.port); 538 }
502 539 if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) {
503 if (bind(listen_sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { 540 error("listen_sock O_NONBLOCK: %s", strerror(errno));
504 error("bind: %.100s", strerror(errno)); 541 close(listen_sock);
505 shutdown(listen_sock, SHUT_RDWR); 542 continue;
506 close(listen_sock); 543 }
507 fatal("Bind to port %d failed.", options.port); 544 /*
545 * Set socket options. We try to make the port
546 * reusable and have it close as fast as possible
547 * without waiting in unnecessary wait states on
548 * close.
549 */
550 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
551 (void *) &on, sizeof(on));
552 linger.l_onoff = 1;
553 linger.l_linger = 5;
554 setsockopt(listen_sock, SOL_SOCKET, SO_LINGER,
555 (void *) &linger, sizeof(linger));
556
557 debug("Bind to port %s on %s.", strport, ntop);
558
559 /* Bind the socket to the desired port. */
560 if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {
561 error("Bind to port %s on %s failed: %.200s.",
562 strport, ntop, strerror(errno));
563 close(listen_sock);
564 continue;
565 }
566 listen_socks[num_listen_socks] = listen_sock;
567 num_listen_socks++;
568
569 /* Start listening on the port. */
570 log("Server listening on %s port %s.", ntop, strport);
571 if (listen(listen_sock, 5) < 0)
572 fatal("listen: %.100s", strerror(errno));
573
508 } 574 }
575 freeaddrinfo(options.listen_addrs);
576
577 if (!num_listen_socks)
578 fatal("Cannot bind any address.");
579
509 if (!debug_flag) { 580 if (!debug_flag) {
510 /* 581 /*
511 * Record our pid in /etc/sshd_pid to make it easier 582 * Record our pid in /etc/sshd_pid to make it easier
@@ -521,10 +592,6 @@ main(int ac, char **av)
521 } 592 }
522 } 593 }
523 594
524 log("Server listening on port %d.", options.port);
525 if (listen(listen_sock, 5) < 0)
526 fatal("listen: %.100s", strerror(errno));
527
528 public_key = RSA_new(); 595 public_key = RSA_new();
529 sensitive_data.private_key = RSA_new(); 596 sensitive_data.private_key = RSA_new();
530 597
@@ -546,6 +613,14 @@ main(int ac, char **av)
546 /* Arrange SIGCHLD to be caught. */ 613 /* Arrange SIGCHLD to be caught. */
547 signal(SIGCHLD, main_sigchld_handler); 614 signal(SIGCHLD, main_sigchld_handler);
548 615
616 /* setup fd set for listen */
617 maxfd = 0;
618 for (i = 0; i < num_listen_socks; i++)
619 if (listen_socks[i] > maxfd)
620 maxfd = listen_socks[i];
621 fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);
622 fdset = (fd_set *)xmalloc(fdsetsz);
623
549 /* 624 /*
550 * Stay listening for connections until the system crashes or 625 * Stay listening for connections until the system crashes or
551 * the daemon is killed with a signal. 626 * the daemon is killed with a signal.
@@ -553,26 +628,28 @@ main(int ac, char **av)
553 for (;;) { 628 for (;;) {
554 if (received_sighup) 629 if (received_sighup)
555 sighup_restart(); 630 sighup_restart();
556 /* Wait in poll until there is a connection. */ 631 /* Wait in select until there is a connection. */
557 memset(&fds, 0, sizeof(fds)); 632 memset(fdset, 0, fdsetsz);
558 fds.fd = listen_sock; 633 for (i = 0; i < num_listen_socks; i++)
559 fds.events = POLLIN; 634 FD_SET(listen_socks[i], fdset);
560 if (poll(&fds, 1, -1) == -1) { 635 if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {
561 if (errno == EINTR) 636 if (errno != EINTR)
562 continue; 637 error("select: %.100s", strerror(errno));
563 fatal("poll: %.100s", strerror(errno));
564 /*NOTREACHED*/
565 }
566 if (fds.revents == 0)
567 continue; 638 continue;
568 aux = sizeof(sin); 639 }
569 newsock = accept(listen_sock, (struct sockaddr *) & sin, &aux); 640 for (i = 0; i < num_listen_socks; i++) {
570 if (received_sighup) 641 if (!FD_ISSET(listen_socks[i], fdset))
571 sighup_restart();
572 if (newsock < 0) {
573 if (errno == EINTR)
574 continue; 642 continue;
575 error("accept: %.100s", strerror(errno)); 643 fromlen = sizeof(from);
644 newsock = accept(listen_socks[i], (struct sockaddr *)&from,
645 &fromlen);
646 if (newsock < 0) {
647 if (errno != EINTR && errno != EWOULDBLOCK)
648 error("accept: %.100s", strerror(errno));
649 continue;
650 }
651 if (fcntl(newsock, F_SETFL, 0) < 0) {
652 error("newsock del O_NONBLOCK: %s", strerror(errno));
576 continue; 653 continue;
577 } 654 }
578 /* 655 /*
@@ -586,7 +663,7 @@ main(int ac, char **av)
586 * connection without forking. 663 * connection without forking.
587 */ 664 */
588 debug("Server will not fork when running in debugging mode."); 665 debug("Server will not fork when running in debugging mode.");
589 close(listen_sock); 666 close_listen_socks();
590 sock_in = newsock; 667 sock_in = newsock;
591 sock_out = newsock; 668 sock_out = newsock;
592 pid = getpid(); 669 pid = getpid();
@@ -603,7 +680,7 @@ main(int ac, char **av)
603 * accepted socket. Reinitialize logging (since our pid has 680 * accepted socket. Reinitialize logging (since our pid has
604 * changed). We break out of the loop to handle the connection. 681 * changed). We break out of the loop to handle the connection.
605 */ 682 */
606 close(listen_sock); 683 close_listen_socks();
607 sock_in = newsock; 684 sock_in = newsock;
608 sock_out = newsock; 685 sock_out = newsock;
609 log_init(av0, options.log_level, options.log_facility, log_stderr); 686 log_init(av0, options.log_level, options.log_facility, log_stderr);
@@ -624,6 +701,10 @@ main(int ac, char **av)
624 701
625 /* Close the new socket (the child is now taking care of it). */ 702 /* Close the new socket (the child is now taking care of it). */
626 close(newsock); 703 close(newsock);
704 } /* for (i = 0; i < num_listen_socks; i++) */
705 /* child process check (or debug mode) */
706 if (num_listen_socks < 0)
707 break;
627 } 708 }
628 } 709 }
629 710
@@ -662,6 +743,7 @@ main(int ac, char **av)
662 743
663 /* Check whether logins are denied from this host. */ 744 /* Check whether logins are denied from this host. */
664#ifdef LIBWRAP 745#ifdef LIBWRAP
746 /* XXX LIBWRAP noes not know about IPv6 */
665 { 747 {
666 struct request_info req; 748 struct request_info req;
667 749
@@ -673,12 +755,11 @@ main(int ac, char **av)
673 close(sock_out); 755 close(sock_out);
674 refuse(&req); 756 refuse(&req);
675 } 757 }
676 verbose("Connection from %.500s port %d", eval_client(&req), remote_port); 758/*XXX IPv6 verbose("Connection from %.500s port %d", eval_client(&req), remote_port); */
677 } 759 }
678#else 760#endif /* LIBWRAP */
679 /* Log the connection. */ 761 /* Log the connection. */
680 verbose("Connection from %.500s port %d", remote_ip, remote_port); 762 verbose("Connection from %.500s port %d", remote_ip, remote_port);
681#endif /* LIBWRAP */
682 763
683 /* 764 /*
684 * We don\'t want to listen forever unless the other side 765 * We don\'t want to listen forever unless the other side
@@ -700,12 +781,12 @@ main(int ac, char **av)
700 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", 781 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
701 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); 782 PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION);
702 if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf)) 783 if (atomicio(write, sock_out, buf, strlen(buf)) != strlen(buf))
703 fatal("Could not write ident string to %s.", get_remote_ipaddr()); 784 fatal("Could not write ident string to %s.", remote_ip);
704 785
705 /* Read other side\'s version identification. */ 786 /* Read other side\'s version identification. */
706 for (i = 0; i < sizeof(buf) - 1; i++) { 787 for (i = 0; i < sizeof(buf) - 1; i++) {
707 if (read(sock_in, &buf[i], 1) != 1) 788 if (read(sock_in, &buf[i], 1) != 1)
708 fatal("Did not receive ident string from %s.", get_remote_ipaddr()); 789 fatal("Did not receive ident string from %s.", remote_ip);
709 if (buf[i] == '\r') { 790 if (buf[i] == '\r') {
710 buf[i] = '\n'; 791 buf[i] = '\n';
711 buf[i + 1] = 0; 792 buf[i + 1] = 0;
@@ -732,7 +813,7 @@ main(int ac, char **av)
732 close(sock_in); 813 close(sock_in);
733 close(sock_out); 814 close(sock_out);
734 fatal("Bad protocol version identification '%.100s' from %s", 815 fatal("Bad protocol version identification '%.100s' from %s",
735 buf, get_remote_ipaddr()); 816 buf, remote_ip);
736 } 817 }
737 debug("Client protocol version %d.%d; client software version %.100s", 818 debug("Client protocol version %d.%d; client software version %.100s",
738 remote_major, remote_minor, remote_version); 819 remote_major, remote_minor, remote_version);
@@ -743,8 +824,7 @@ main(int ac, char **av)
743 close(sock_in); 824 close(sock_in);
744 close(sock_out); 825 close(sock_out);
745 fatal("Protocol major versions differ for %s: %d vs. %d", 826 fatal("Protocol major versions differ for %s: %d vs. %d",
746 get_remote_ipaddr(), 827 remote_ip, PROTOCOL_MAJOR, remote_major);
747 PROTOCOL_MAJOR, remote_major);
748 } 828 }
749 /* Check that the client has sufficiently high software version. */ 829 /* Check that the client has sufficiently high software version. */
750 if (remote_major == 1 && remote_minor < 3) 830 if (remote_major == 1 && remote_minor < 3)
@@ -769,6 +849,14 @@ main(int ac, char **av)
769 options.rhosts_authentication = 0; 849 options.rhosts_authentication = 0;
770 options.rhosts_rsa_authentication = 0; 850 options.rhosts_rsa_authentication = 0;
771 } 851 }
852#ifdef KRB4
853 if (!packet_connection_is_ipv4() &&
854 options.kerberos_authentication) {
855 debug("Kerberos Authentication disabled, only available for IPv4.");
856 options.kerberos_authentication = 0;
857 }
858#endif /* KRB4 */
859
772 packet_set_nonblocking(); 860 packet_set_nonblocking();
773 861
774 /* Handle the connection. */ 862 /* Handle the connection. */
@@ -1935,8 +2023,8 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
1935 char line[256]; 2023 char line[256];
1936 struct stat st; 2024 struct stat st;
1937 int quiet_login; 2025 int quiet_login;
1938 struct sockaddr_in from; 2026 struct sockaddr_storage from;
1939 int fromlen; 2027 socklen_t fromlen;
1940 struct pty_cleanup_context cleanup_context; 2028 struct pty_cleanup_context cleanup_context;
1941 2029
1942 /* Get remote host name. */ 2030 /* Get remote host name. */
@@ -1997,7 +2085,7 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd,
1997 } 2085 }
1998 /* Record that there was a login on that terminal. */ 2086 /* Record that there was a login on that terminal. */
1999 record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname, 2087 record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname,
2000 &from); 2088 (struct sockaddr *)&from);
2001 2089
2002 /* Check if .hushlogin exists. */ 2090 /* Check if .hushlogin exists. */
2003 snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir); 2091 snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
@@ -2318,7 +2406,7 @@ do_child(const char *command, struct passwd * pw, const char *term,
2318 } 2406 }
2319 2407
2320 snprintf(buf, sizeof buf, "%.50s %d %d", 2408 snprintf(buf, sizeof buf, "%.50s %d %d",
2321 get_remote_ipaddr(), get_remote_port(), options.port); 2409 get_remote_ipaddr(), get_remote_port(), get_local_port());
2322 child_set_env(&env, &envsize, "SSH_CLIENT", buf); 2410 child_set_env(&env, &envsize, "SSH_CLIENT", buf);
2323 2411
2324 if (ttyname) 2412 if (ttyname)
@@ -2385,7 +2473,6 @@ do_child(const char *command, struct passwd * pw, const char *term,
2385 * descriptors left by system functions. They will be closed later. 2473 * descriptors left by system functions. They will be closed later.
2386 */ 2474 */
2387 endpwent(); 2475 endpwent();
2388 endhostent();
2389 2476
2390 /* 2477 /*
2391 * Close any extra open file descriptors so that we don\'t have them 2478 * Close any extra open file descriptors so that we don\'t have them
diff --git a/sshd_config.in b/sshd_config.in
index 63e3d9829..cb2c56e05 100644
--- a/sshd_config.in
+++ b/sshd_config.in
@@ -2,6 +2,7 @@
2 2
3Port 22 3Port 22
4ListenAddress 0.0.0.0 4ListenAddress 0.0.0.0
5#ListenAddress ::
5HostKey @sysconfdir@/ssh_host_key 6HostKey @sysconfdir@/ssh_host_key
6ServerKeyBits 768 7ServerKeyBits 768
7LoginGraceTime 600 8LoginGraceTime 600