diff options
author | Damien Miller <djm@mindrot.org> | 2000-01-14 15:45:46 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2000-01-14 15:45:46 +1100 |
commit | 34132e54cbd221d17d373fc54f4e3f7b85727f7f (patch) | |
tree | 7c73917b1082ff91786f9e02d25b853bedd1d472 | |
parent | 25e4256ad4f453d8a7c1866243ec1984f859b1de (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-- | ChangeLog | 33 | ||||
-rw-r--r-- | Makefile.in | 62 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | acconfig.h | 28 | ||||
-rw-r--r-- | bsd-bindresvport.c | 116 | ||||
-rw-r--r-- | bsd-bindresvport.h | 10 | ||||
-rw-r--r-- | bsd-rresvport.c | 107 | ||||
-rw-r--r-- | bsd-rresvport.h | 10 | ||||
-rw-r--r-- | canohost.c | 184 | ||||
-rw-r--r-- | channels.c | 388 | ||||
-rw-r--r-- | configure.in | 88 | ||||
-rw-r--r-- | defines.h | 4 | ||||
-rw-r--r-- | fake-gai-errnos.h | 12 | ||||
-rw-r--r-- | fake-getaddrinfo.c | 119 | ||||
-rw-r--r-- | fake-getaddrinfo.h | 44 | ||||
-rw-r--r-- | fake-getnameinfo.c | 61 | ||||
-rw-r--r-- | fake-getnameinfo.h | 17 | ||||
-rw-r--r-- | fake-socket.h | 49 | ||||
-rwxr-xr-x | fixpaths | 2 | ||||
-rw-r--r-- | hostfile.c | 2 | ||||
-rw-r--r-- | includes.h | 9 | ||||
-rw-r--r-- | log.c | 2 | ||||
-rw-r--r-- | login.c | 42 | ||||
-rw-r--r-- | nchan.c | 30 | ||||
-rw-r--r-- | nchan.ms | 9 | ||||
-rw-r--r-- | packet.c | 65 | ||||
-rw-r--r-- | packet.h | 6 | ||||
-rw-r--r-- | scp.1.in | 12 | ||||
-rw-r--r-- | scp.c | 56 | ||||
-rw-r--r-- | servconf.c | 88 | ||||
-rw-r--r-- | servconf.h | 12 | ||||
-rw-r--r-- | ssh.1.in | 22 | ||||
-rw-r--r-- | ssh.c | 54 | ||||
-rw-r--r-- | ssh.h | 17 | ||||
-rw-r--r-- | sshconnect.c | 207 | ||||
-rw-r--r-- | sshd.8.in | 17 | ||||
-rw-r--r-- | sshd.c | 249 | ||||
-rw-r--r-- | sshd_config.in | 1 |
38 files changed, 1633 insertions, 603 deletions
@@ -1,3 +1,36 @@ | |||
1 | 20000114 | ||
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 | |||
1 | 20000110 | 34 | 20000110 |
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@ | |||
19 | PATHS=-DETCDIR=\"$(sysconfdir)\" -DSSH_PROGRAM=\"$(SSH_PROGRAM)\" -DSSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" | 19 | PATHS=-DETCDIR=\"$(sysconfdir)\" -DSSH_PROGRAM=\"$(SSH_PROGRAM)\" -DSSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" |
20 | CFLAGS=@CFLAGS@ $(PATHS) @DEFS@ | 20 | CFLAGS=@CFLAGS@ $(PATHS) @DEFS@ |
21 | EXTRA_TARGETS=@GNOME_ASKPASS@ | 21 | EXTRA_TARGETS=@GNOME_ASKPASS@ |
22 | TARGETS=libssh.a ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) | ||
23 | LIBS=@LIBS@ | 22 | LIBS=@LIBS@ |
24 | AR=@AR@ | 23 | AR=@AR@ |
25 | RANLIB=@RANLIB@ | 24 | RANLIB=@RANLIB@ |
@@ -30,34 +29,19 @@ LDFLAGS=-L. @LDFLAGS@ | |||
30 | GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui` | 29 | GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui` |
31 | GNOME_LIBS=`gnome-config --libs gnome gnomeui` | 30 | GNOME_LIBS=`gnome-config --libs gnome gnomeui` |
32 | 31 | ||
33 | OBJS= atomicio.o authfd.o authfile.o auth-krb4.o auth-passwd.o auth-pam.o \ | 32 | TARGETS=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 \ | 34 | LIBOBJS= 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 | |||
43 | LIBOBJS= 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 | ||
50 | SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o | 36 | SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o |
51 | 37 | ||
52 | SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o \ | 38 | SSHDOBJS= 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 | ||
56 | MANPAGES=scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 | 40 | MANPAGES=scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 |
57 | 41 | ||
58 | CONFIGFILES=sshd_config ssh_config | 42 | CONFIGFILES=sshd_config ssh_config |
59 | 43 | ||
60 | all: $(OBJS) $(TARGETS) $(MANPAGES) $(CONFIGFILES) | 44 | all: $(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 | ||
70 | ssh: $(SSHOBJS) libssh.a | 54 | ssh: libssh.a $(SSHOBJS) |
71 | $(CC) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh $(LIBS) | 55 | $(CC) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh $(LIBS) |
72 | 56 | ||
73 | sshd: $(SSHDOBJS) libssh.a | 57 | sshd: libssh.a $(SSHDOBJS) |
74 | $(CC) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh $(LIBS) | 58 | $(CC) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh $(LIBS) |
75 | 59 | ||
76 | scp: scp.o libssh.a | 60 | scp: libssh.a scp.o |
77 | $(CC) -o $@ scp.o $(LDFLAGS) -lssh $(LIBS) | 61 | $(CC) -o $@ scp.o $(LDFLAGS) -lssh $(LIBS) |
78 | 62 | ||
79 | ssh-add: ssh-add.o log-client.o libssh.a | 63 | ssh-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 | ||
82 | ssh-agent: ssh-agent.o log-client.o libssh.a | 66 | ssh-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 | ||
85 | ssh-keygen: ssh-keygen.o log-client.o libssh.a | 69 | ssh-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 | ||
88 | gnome-ssh-askpass: gnome-ssh-askpass.c | 72 | gnome-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 | ||
91 | clean: | ||
92 | rm -f *.o $(TARGETS) config.status config.cache config.log core \ | ||
93 | *.1 *.8 sshd_config ssh_config | ||
94 | |||
95 | scp.1: scp.1.in | 75 | scp.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 | |||
116 | ssh_config: ssh_config.in | 96 | ssh_config: ssh_config.in |
117 | $(PERL) $(FIXPATHS) -Dsysconfdir=${sysconfdir} ssh_config.in | 97 | $(PERL) $(FIXPATHS) -Dsysconfdir=${sysconfdir} ssh_config.in |
118 | 98 | ||
99 | clean: | ||
100 | rm -f *.o *.a $(TARGETS) config.status config.cache config.log | ||
101 | rm -f core *.1 *.8 sshd_config ssh_config | ||
102 | |||
103 | distclean: clean | ||
104 | rm -f Makefile config.h core *~ | ||
105 | |||
106 | mrproper: distclean | ||
107 | |||
108 | veryclean: distclean | ||
109 | rm -f configure config.h.in | ||
110 | |||
119 | install: $(TARGETS) | 111 | install: $(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 | ||
183 | distclean: clean | ||
184 | rm -f Makefile config.h core *~ | ||
185 | |||
186 | mrproper: distclean | ||
187 | |||
188 | veryclean: distclean | ||
189 | rm -f configure config.h.in | ||
190 | |||
@@ -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 | ||
12 | localhost$ ssh remotehost | 14 | localhost$ 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) | ||
35 | static 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 | */ | ||
54 | int | ||
55 | bindresvport(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 | */ | ||
66 | int | ||
67 | bindresvport_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 | ||
7 | int 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) | ||
41 | static 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 | ||
47 | int | ||
48 | rresvport(alport) | ||
49 | int *alport; | ||
50 | { | ||
51 | return rresvport_af(alport, AF_INET); | ||
52 | } | ||
53 | #endif | ||
54 | |||
55 | int | ||
56 | rresvport_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 | ||
7 | int 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" |
17 | RCSID("$Id: canohost.c,v 1.6 1999/12/18 09:57:40 damien Exp $"); | 17 | RCSID("$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 $"); | |||
28 | char * | 28 | char * |
29 | get_remote_hostname(int socket) | 29 | get_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 | ||
143 | static char *canonical_host_name = NULL; | ||
144 | static char *canonical_host_ip = NULL; | ||
145 | |||
146 | /* Returns 1 if remote host is connected via socket, 0 if not. */ | ||
147 | |||
148 | int | ||
149 | peer_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() | |||
175 | const char * | 150 | const char * |
176 | get_canonical_hostname() | 151 | get_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 | ||
196 | const char * | 173 | const char * |
197 | get_remote_ipaddr() | 174 | get_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 | ||
230 | int | 214 | int |
231 | get_peer_port(int sock) | 215 | get_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 | ||
249 | int | 244 | int |
250 | get_remote_port() | 245 | get_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 | |||
258 | int | ||
259 | get_peer_port(int sock) | ||
260 | { | ||
261 | return get_sock_port(sock, 0); | ||
262 | } | ||
263 | 263 | ||
264 | /* Get and return the peer port number. */ | 264 | int |
265 | return get_peer_port(socket); | 265 | get_remote_port() |
266 | { | ||
267 | return get_port(0); | ||
268 | } | ||
269 | |||
270 | int | ||
271 | get_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" |
19 | RCSID("$Id: channels.c,v 1.14 1999/12/27 12:54:55 damien Exp $"); | 19 | RCSID("$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 | |||
374 | channel_after_select(fd_set * readset, fd_set * writeset) | 374 | channel_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() | |||
575 | void | 585 | void |
576 | channel_input_data(int payload_len) | 586 | channel_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 | |||
878 | channel_request_local_forwarding(u_short port, const char *host, | 886 | channel_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) | |||
1000 | void | 1034 | void |
1001 | channel_input_port_open(int payload_len) | 1035 | channel_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 | |||
1118 | char * | 1161 | char * |
1119 | x11_create_display_inet(int screen_number, int x11_display_offset) | 1162 | x11_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) | |||
1252 | void | 1321 | void |
1253 | x11_input_open(int payload_len) | 1322 | x11_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 | } |
1364 | success: | 1430 | success: |
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. | |||
128 | AC_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) | 128 | AC_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 | ||
130 | dnl Checks for library functions. | 130 | dnl Checks for library functions. |
131 | AC_CHECK_FUNCS(arc4random getpagesize _getpty innetgr md5_crypt mkdtemp openpty setenv seteuid setlogin setproctitle setreuid snprintf strlcat strlcpy updwtmpx vsnprintf) | 131 | AC_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 | ||
133 | AC_CHECK_FUNC(login, | 133 | AC_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 | ||
172 | AC_MSG_CHECKING([For uintXX_t types]) | 172 | AC_MSG_CHECKING([for uintXX_t types]) |
173 | AC_TRY_COMPILE( | 173 | AC_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 | ||
183 | AC_MSG_CHECKING([For socklen_t]) | 183 | AC_MSG_CHECKING([for socklen_t]) |
184 | AC_TRY_COMPILE( | 184 | AC_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 | ||
197 | AC_MSG_CHECKING([For size_t]) | 197 | AC_MSG_CHECKING([for size_t]) |
198 | AC_TRY_COMPILE( | 198 | AC_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 | ||
208 | AC_MSG_CHECKING([for struct sockaddr_storage]) | ||
209 | AC_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 | |||
219 | AC_MSG_CHECKING([for struct sockaddr_in6]) | ||
220 | AC_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 | |||
230 | AC_MSG_CHECKING([for struct in6_addr]) | ||
231 | AC_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 | |||
241 | AC_MSG_CHECKING([for struct addrinfo]) | ||
242 | AC_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 | |||
208 | AC_ARG_WITH(pam, | 255 | AC_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 | ) |
331 | AC_MSG_CHECKING([whether utmpx.h has ut_addr field]) | 378 | AC_MSG_CHECKING([whether utmpx.h has ut_addr field]) |
332 | AC_EGREP_HEADER(ut_addr, utmpx.h, | 379 | AC_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 | ) | ||
383 | AC_MSG_CHECKING([whether utmp.h has ut_addr_v6 field]) | ||
384 | AC_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 | ) | ||
388 | AC_MSG_CHECKING([whether utmpx.h has ut_addr_v6 field]) | ||
389 | AC_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 | |||
394 | AC_MSG_CHECKING([whether struct sockaddr_storage has ss_family field]) | ||
395 | AC_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 | ) | ||
404 | AC_MSG_CHECKING([whether struct sockaddr_storage has __ss_family field]) | ||
405 | AC_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 | ||
@@ -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 | ||
19 | char * | ||
20 | gai_strerror(ecode) | ||
21 | int 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 | ||
35 | void | ||
36 | freeaddrinfo(ai) | ||
37 | struct 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 | ||
49 | static struct addrinfo * | ||
50 | malloc_ai(port, addr) | ||
51 | int port; | ||
52 | u_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 | |||
71 | int | ||
72 | getaddrinfo(hostname, servname, hints, res) | ||
73 | const char *hostname, *servname; | ||
74 | const struct addrinfo *hints; | ||
75 | struct 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 | ||
19 | struct 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 | ||
32 | int 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 | ||
37 | char *gai_strerror(int ecode); | ||
38 | #endif /* !HAVE_GAI_STRERROR */ | ||
39 | |||
40 | #ifndef HAVE_FREEADDRINFO | ||
41 | void 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 | ||
19 | int | ||
20 | getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) | ||
21 | const struct sockaddr *sa; | ||
22 | size_t salen; | ||
23 | char *host; | ||
24 | size_t hostlen; | ||
25 | char *serv; | ||
26 | size_t servlen; | ||
27 | int 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 | ||
6 | int 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 | |||
14 | struct 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 | ||
29 | struct in6_addr { | ||
30 | u_int8_t s6_addr[16]; | ||
31 | }; | ||
32 | #endif /* !HAVE_STRUCT_IN6_ADDR */ | ||
33 | |||
34 | #ifndef HAVE_STRUCT_SOCKADDR_IN6 | ||
35 | struct 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 | |||
@@ -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" |
17 | RCSID("$OpenBSD: hostfile.c,v 1.10 1999/12/02 20:18:59 markus Exp $"); | 17 | RCSID("$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" |
@@ -3,7 +3,7 @@ | |||
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include "includes.h" | 5 | #include "includes.h" |
6 | RCSID("$OpenBSD: log.c,v 1.6 1999/11/24 19:53:47 markus Exp $"); | 6 | RCSID("$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" |
@@ -18,7 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include "includes.h" | 20 | #include "includes.h" |
21 | RCSID("$Id: login.c,v 1.17 2000/01/02 00:45:33 damien Exp $"); | 21 | RCSID("$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 | ||
138 | void | 138 | void |
139 | record_login(int pid, const char *ttyname, const char *user, uid_t uid, | 139 | record_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)*/ |
@@ -28,7 +28,7 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include "includes.h" | 30 | #include "includes.h" |
31 | RCSID("$Id: nchan.c,v 1.4 1999/12/06 00:47:29 damien Exp $"); | 31 | RCSID("$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); | |||
41 | static void chan_send_oclose(Channel *c); | 41 | static void chan_send_oclose(Channel *c); |
42 | static void chan_shutdown_write(Channel *c); | 42 | static void chan_shutdown_write(Channel *c); |
43 | static void chan_shutdown_read(Channel *c); | 43 | static void chan_shutdown_read(Channel *c); |
44 | static void chan_delele_if_full_closed(Channel *c); | 44 | static 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 | } |
72 | void | 78 | void |
73 | chan_read_failed(Channel *c) | 79 | chan_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 | } |
219 | static void | 225 | static void |
220 | chan_delele_if_full_closed(Channel *c) | 226 | chan_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 | } |
@@ -52,6 +52,9 @@ arrow from S3.n to S4.s | |||
52 | box invis "rcvd OCLOSE/" "-" with .w at last arrow.c | 52 | box invis "rcvd OCLOSE/" "-" with .w at last arrow.c |
53 | ellipse wid .9*ellipsewid ht .9*ellipseht at S4 | 53 | ellipse wid .9*ellipsewid ht .9*ellipseht at S4 |
54 | arrow "start" "" from S1.w+(-0.5,0) to S1.w | 54 | arrow "start" "" from S1.w+(-0.5,0) to S1.w |
55 | arrow from S2.ne to S4.sw | ||
56 | box invis "rcvd OCLOSE/ " with .e at last arrow.c | ||
57 | box invis " send IEOF" with .w at last arrow.c | ||
55 | .PE | 58 | .PE |
56 | .SH | 59 | .SH |
57 | Channel Output State Diagram | 60 | Channel Output State Diagram |
@@ -76,7 +79,7 @@ arrow "start" "" from S1.w+(-0.5,0) to S1.w | |||
76 | Notes | 79 | Notes |
77 | .PP | 80 | .PP |
78 | The input buffer is filled with data from the socket | 81 | The 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 |
80 | forwarded channel). | 83 | forwarded channel). |
81 | The data is then sent over the INPUT-end (transmit-end) of the channel to the | 84 | The data is then sent over the INPUT-end (transmit-end) of the channel to the |
82 | remote peer. | 85 | remote peer. |
@@ -85,7 +88,7 @@ saved in the output buffer and written to the socket. | |||
85 | .PP | 88 | .PP |
86 | If the local protocol instance has forwarded all data on the | 89 | If the local protocol instance has forwarded all data on the |
87 | INPUT-end of the channel, it sends an IEOF message to the peer. | 90 | INPUT-end of the channel, it sends an IEOF message to the peer. |
88 | If the peer receives the IEOF and has comsumed all | 91 | If the peer receives the IEOF and has consumed all |
89 | data he replies with an OCLOSE. | 92 | data he replies with an OCLOSE. |
90 | When the local instance receives the OCLOSE | 93 | When the local instance receives the OCLOSE |
91 | he considers the INPUT-half of the channel closed. | 94 | he considers the INPUT-half of the channel closed. |
@@ -94,6 +97,6 @@ The peer has his OUTOUT-half closed. | |||
94 | A channel can be deallocated by a protocol instance | 97 | A channel can be deallocated by a protocol instance |
95 | if both the INPUT- and the OUTOUT-half on his | 98 | if both the INPUT- and the OUTOUT-half on his |
96 | side of the channel are closed. | 99 | side of the channel are closed. |
97 | Note that when an instance is unable to comsume the | 100 | Note that when an instance is unable to consume the |
98 | received data, he is permitted to send an OCLOSE | 101 | received data, he is permitted to send an OCLOSE |
99 | before the matching IEOF is received. | 102 | before the matching IEOF is received. |
@@ -15,7 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "includes.h" | 17 | #include "includes.h" |
18 | RCSID("$Id: packet.c,v 1.8 1999/12/16 02:18:04 damien Exp $"); | 18 | RCSID("$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 | |||
109 | int | ||
110 | packet_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 | |||
135 | int | ||
136 | packet_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 | ||
109 | void | 151 | void |
@@ -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 | } |
@@ -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 */ | ||
202 | int packet_connection_is_on_socket(void); | ||
203 | int packet_connection_is_ipv4(void); | ||
204 | |||
201 | #endif /* PACKET_H */ | 205 | #endif /* PACKET_H */ |
@@ -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 |
94 | is already reserved for preserving the times and modes of the file in | 94 | is already reserved for preserving the times and modes of the file in |
95 | .Xr rcp 1 . | 95 | .Xr rcp 1 . |
96 | .It Fl 4 | ||
97 | Forces | ||
98 | .Nm | ||
99 | to use IPv4 addresses only. | ||
100 | .It Fl 6 | ||
101 | Forces | ||
102 | .Nm | ||
103 | to use IPv6 addresses only. | ||
96 | .Sh AUTHORS | 104 | .Sh AUTHORS |
97 | Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi> | 105 | Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi> |
98 | .Sh HISTORY | 106 | .Sh HISTORY |
@@ -45,7 +45,7 @@ | |||
45 | */ | 45 | */ |
46 | 46 | ||
47 | #include "includes.h" | 47 | #include "includes.h" |
48 | RCSID("$Id: scp.c,v 1.15 1999/12/30 22:16:40 damien Exp $"); | 48 | RCSID("$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. */ |
75 | char *curfile; | 75 | char *curfile; |
76 | 76 | ||
77 | /* This is set to non-zero if IPv4 is desired. */ | ||
78 | int IPv4 = 0; | ||
79 | |||
80 | /* This is set to non-zero if IPv6 is desired. */ | ||
81 | int 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. */ |
78 | int verbose_mode = 0; | 84 | int 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 | ||
354 | char * | ||
355 | cleanhostname(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 | |||
337 | void | 365 | void |
338 | toremote(targ, argc, argv) | 366 | toremote(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 | |||
913 | usage() | 945 | usage() |
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 | ||
982 | char * | 1014 | char * |
983 | colon(cp) | 1015 | colon(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" |
15 | RCSID("$Id: servconf.c,v 1.7 1999/11/25 00:54:59 damien Exp $"); | 15 | RCSID("$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 */ | ||
22 | void 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 | ||
23 | void | 26 | void |
24 | initialize_server_options(ServerOptions *options) | 27 | initialize_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) | |||
68 | void | 72 | void |
69 | fill_default_server_options(ServerOptions *options) | 73 | fill_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 | */ | ||
236 | void | ||
237 | add_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 | ||
237 | void | 266 | void |
@@ -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; | ||
266 | parse_int: | 312 | parse_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 | ||
26 | typedef struct { | 28 | typedef 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 |
@@ -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 | |||
396 | on the local side, and whenever a connection is made to this port, the | 396 | on the local side, and whenever a connection is made to this port, the |
397 | connection is forwarded over the secure channel, and a connection is | 397 | connection is forwarded over the secure channel, and a connection is |
398 | made to | 398 | made to |
399 | .Ar host:hostport | 399 | .Ar host |
400 | port | ||
401 | .Ar hostport | ||
400 | from the remote machine. Port forwardings can also be specified in the | 402 | from the remote machine. Port forwardings can also be specified in the |
401 | configuration file. Only root can forward privileged ports. | 403 | configuration file. Only root can forward privileged ports. |
404 | IPv6 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 |
403 | Specifies that the given port on the remote (server) host is to be | 407 | Specifies that the given port on the remote (server) host is to be |
404 | forwarded to the given host and port on the local side. This works | 408 | forwarded to the given host and port on the local side. This works |
@@ -407,10 +411,20 @@ by allocating a socket to listen to | |||
407 | on the remote side, and whenever a connection is made to this port, the | 411 | on the remote side, and whenever a connection is made to this port, the |
408 | connection is forwarded over the secure channel, and a connection is | 412 | connection is forwarded over the secure channel, and a connection is |
409 | made to | 413 | made to |
410 | .Ar host:hostport | 414 | .Ar host |
415 | port | ||
416 | .Ar hostport | ||
411 | from the local machine. Port forwardings can also be specified in the | 417 | from the local machine. Port forwardings can also be specified in the |
412 | configuration file. Privileged ports can be forwarded only when | 418 | configuration file. Privileged ports can be forwarded only when |
413 | logging in as root on the remote machine. | 419 | logging in as root on the remote machine. |
420 | .It Fl 4 | ||
421 | Forces | ||
422 | .Nm | ||
423 | to use IPv4 addresses only. | ||
424 | .It Fl 6 | ||
425 | Forces | ||
426 | .Nm | ||
427 | to use IPv6 addresses only. | ||
414 | .El | 428 | .El |
415 | .Sh CONFIGURATION FILES | 429 | .Sh CONFIGURATION FILES |
416 | .Nm | 430 | .Nm |
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "includes.h" | 13 | #include "includes.h" |
14 | RCSID("$Id: ssh.c,v 1.15 1999/12/28 23:17:09 damien Exp $"); | 14 | RCSID("$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; | |||
27 | const char *__progname = "ssh"; | 27 | const 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. */ | ||
32 | int 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. */ |
31 | int debug_flag = 0; | 35 | int debug_flag = 0; |
32 | 36 | ||
@@ -59,7 +63,7 @@ Options options; | |||
59 | char *host; | 63 | char *host; |
60 | 64 | ||
61 | /* socket address the host resolves to */ | 65 | /* socket address the host resolves to */ |
62 | struct sockaddr_in hostaddr; | 66 | struct 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) |
@@ -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 | */ |
285 | void | 287 | void |
286 | record_login(int pid, const char *ttyname, const char *user, uid_t uid, | 288 | record_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 | */ |
306 | int | 308 | int |
307 | ssh_connect(const char *host, struct sockaddr_in * hostaddr, | 309 | ssh_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 | ||
321 | void | 323 | void |
322 | ssh_login(int host_key_valid, RSA * host_key, const char *host, | 324 | ssh_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. */ |
381 | int get_peer_port(int sock); | 383 | int 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. */ |
384 | int get_remote_port(void); | 386 | int get_remote_port(void); |
387 | int 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); | |||
741 | int auth_skey_password(struct passwd * pw, const char *password); | 745 | int 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 */ | ||
749 | extern 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" |
11 | RCSID("$Id: sshconnect.c,v 1.20 2000/01/03 12:41:05 damien Exp $"); | 11 | RCSID("$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 $"); | |||
35 | unsigned char session_id[16]; | 35 | unsigned char session_id[16]; |
36 | 36 | ||
37 | extern Options options; | 37 | extern Options options; |
38 | extern 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 | */ |
142 | int | 143 | int |
143 | ssh_create_socket(uid_t original_real_uid, int privileged) | 144 | ssh_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 | */ |
182 | int | 183 | int |
183 | ssh_connect(const char *host, struct sockaddr_in * hostaddr, | 184 | ssh_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 | ||
1097 | void | 1064 | void |
1098 | check_host_key(char *host, | 1065 | check_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 | |||
1301 | ssh_login(int host_key_valid, | 1286 | ssh_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; |
@@ -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 | |||
173 | assumes the client has sent the given version string | 173 | assumes the client has sent the given version string |
174 | and skips the | 174 | and skips the |
175 | Protocol Version Identification Exchange. | 175 | Protocol Version Identification Exchange. |
176 | .It Fl 4 | ||
177 | Forces | ||
178 | .Nm | ||
179 | to use IPv4 addresses only. | ||
180 | .It Fl 6 | ||
181 | Forces | ||
182 | .Nm | ||
183 | to 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 |
321 | should listen on. | 329 | should listen on. |
322 | The default is to listen to all local addresses. | 330 | The default is to listen to all local addresses. |
331 | Multiple options of this type are permitted. | ||
332 | Additionally, the | ||
333 | .Cm Ports | ||
334 | options must precede this option. | ||
323 | .It Cm LoginGraceTime | 335 | .It Cm LoginGraceTime |
324 | The server disconnects after this time if the user has not | 336 | The server disconnects after this time if the user has not |
325 | successfully logged in. If the value is 0, there is no time limit. | 337 | successfully logged in. If the value is 0, there is no time limit. |
@@ -365,6 +377,7 @@ normally not allowed). | |||
365 | Specifies the port number that | 377 | Specifies the port number that |
366 | .Nm | 378 | .Nm |
367 | listens on. The default is 22. | 379 | listens on. The default is 22. |
380 | Multiple options of this type are permitted. | ||
368 | .It Cm PrintMotd | 381 | .It Cm PrintMotd |
369 | Specifies whether | 382 | Specifies whether |
370 | .Nm | 383 | .Nm |
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "includes.h" | 13 | #include "includes.h" |
14 | RCSID("$Id: sshd.c,v 1.49 1999/12/30 04:08:44 damien Exp $"); | 14 | RCSID("$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. */ |
46 | char *config_file_name = SERVER_CONFIG_FILE; | 46 | char *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 | */ | ||
52 | int 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; | |||
66 | char **saved_argv; | 72 | char **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 | */ |
72 | int listen_sock; | 78 | #define MAX_LISTEN_SOCKS 16 |
79 | int listen_socks[MAX_LISTEN_SOCKS]; | ||
80 | int 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 | */ | ||
149 | void | ||
150 | close_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 | |||
155 | sighup_restart() | 175 | sighup_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 | |||
170 | sigterm_handler(int sig) | 190 | sigterm_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 | ||
3 | Port 22 | 3 | Port 22 |
4 | ListenAddress 0.0.0.0 | 4 | ListenAddress 0.0.0.0 |
5 | #ListenAddress :: | ||
5 | HostKey @sysconfdir@/ssh_host_key | 6 | HostKey @sysconfdir@/ssh_host_key |
6 | ServerKeyBits 768 | 7 | ServerKeyBits 768 |
7 | LoginGraceTime 600 | 8 | LoginGraceTime 600 |