]> andersk Git - gssapi-openssh.git/commitdiff
Import of OpenSSH 5.1p1 OPENSSH_5_1P1
authorbasney <basney>
Sun, 27 Jul 2008 18:59:52 +0000 (18:59 +0000)
committerbasney <basney>
Sun, 27 Jul 2008 18:59:52 +0000 (18:59 +0000)
121 files changed:
openssh/ChangeLog
openssh/Makefile.in
openssh/PROTOCOL [new file with mode: 0644]
openssh/PROTOCOL.agent [new file with mode: 0644]
openssh/README
openssh/addrmatch.c [new file with mode: 0644]
openssh/atomicio.c
openssh/auth-options.c
openssh/auth-rhosts.c
openssh/auth-rsa.c
openssh/auth-sia.c
openssh/auth.c
openssh/auth.h
openssh/auth1.c
openssh/auth2-hostbased.c
openssh/auth2-none.c
openssh/auth2-pubkey.c
openssh/auth2.c
openssh/bufaux.c
openssh/buffer.h
openssh/canohost.c
openssh/channels.c
openssh/channels.h
openssh/clientloop.c
openssh/clientloop.h
openssh/configure.ac
openssh/contrib/caldera/openssh.spec
openssh/contrib/cygwin/Makefile
openssh/contrib/cygwin/ssh-host-config
openssh/contrib/cygwin/ssh-user-config
openssh/contrib/cygwin/sshd-inetd [new file with mode: 0644]
openssh/contrib/redhat/openssh.spec
openssh/contrib/suse/openssh.spec
openssh/defines.h
openssh/dh.c
openssh/dh.h
openssh/dns.c
openssh/groupaccess.c
openssh/groupaccess.h
openssh/gss-serv.c
openssh/includes.h
openssh/key.c
openssh/key.h
openssh/log.c
openssh/log.h
openssh/mac.c
openssh/match.c
openssh/match.h
openssh/misc.c
openssh/misc.h
openssh/moduli.5 [new file with mode: 0644]
openssh/moduli.c
openssh/monitor.c
openssh/monitor_mm.h
openssh/monitor_wrap.c
openssh/mux.c [new file with mode: 0644]
openssh/nchan.c
openssh/nchan2.ms
openssh/openbsd-compat/Makefile.in
openssh/openbsd-compat/bindresvport.c
openssh/openbsd-compat/bsd-arc4random.c
openssh/openbsd-compat/bsd-cygwin_util.c
openssh/openbsd-compat/bsd-poll.c
openssh/openbsd-compat/bsd-statvfs.c [new file with mode: 0644]
openssh/openbsd-compat/bsd-statvfs.h [new file with mode: 0644]
openssh/openbsd-compat/fake-rfc2553.c
openssh/openbsd-compat/fake-rfc2553.h
openssh/openbsd-compat/fmt_scaled.c [new file with mode: 0644]
openssh/openbsd-compat/openbsd-compat.h
openssh/openbsd-compat/port-tun.c
openssh/openbsd-compat/rresvport.c
openssh/openbsd-compat/setenv.c
openssh/openbsd-compat/setproctitle.c
openssh/openbsd-compat/sigact.c
openssh/packet.c
openssh/packet.h
openssh/readconf.c
openssh/readconf.h
openssh/regress/Makefile
openssh/regress/addrmatch.sh [new file with mode: 0644]
openssh/regress/conch-ciphers.sh [new file with mode: 0644]
openssh/regress/key-options.sh [new file with mode: 0644]
openssh/regress/putty-ciphers.sh
openssh/regress/putty-kex.sh
openssh/regress/putty-transfer.sh
openssh/regress/test-exec.sh
openssh/scp.1
openssh/scp.c
openssh/servconf.c
openssh/servconf.h
openssh/serverloop.c
openssh/session.c
openssh/session.h
openssh/sftp-client.c
openssh/sftp-client.h
openssh/sftp-server.8
openssh/sftp-server.c
openssh/sftp.1
openssh/sftp.c
openssh/sftp.h
openssh/ssh-agent.1
openssh/ssh-agent.c
openssh/ssh-keygen.1
openssh/ssh-keygen.c
openssh/ssh-keyscan.1
openssh/ssh-keyscan.c
openssh/ssh-keysign.8
openssh/ssh.1
openssh/ssh.c
openssh/ssh_config.5
openssh/sshconnect.c
openssh/sshconnect2.c
openssh/sshd.8
openssh/sshd.c
openssh/sshd_config
openssh/sshd_config.5
openssh/sshpty.h
openssh/sshtty.c
openssh/ttymodes.c
openssh/umac.c
openssh/version.h

index 0d266c1d2b9101e941c2ce528192fcbf7c499ee2..9f3ad84194bd9b3136f3606ece575c0b35fbd889 100644 (file)
@@ -1,3 +1,862 @@
+20080721
+ - (djm) OpenBSD CVS Sync
+   - jmc@cvs.openbsd.org 2008/07/18 22:51:01
+     [sftp-server.8]
+     no need for .Pp before or after .Sh;
+   - djm@cvs.openbsd.org 2008/07/21 08:19:07
+     [version.h]
+     openssh-5.1
+ - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+   [contrib/suse/openssh.spec] Update version number in README and RPM specs
+ - (djm) Release OpenSSH-5.1
+
+20080717
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/07/17 08:48:00
+     [sshconnect2.c]
+     strnvis preauth banner; pointed out by mpf@ ok markus@
+   - djm@cvs.openbsd.org 2008/07/17 08:51:07
+     [auth2-hostbased.c]
+     strip trailing '.' from hostname when HostbasedUsesNameFromPacketOnly=yes
+     report and patch from res AT qoxp.net (bz#1200); ok markus@
+ - (dtucker) [openbsd-compat/bsd-cygwin_util.c]  Remove long-unneeded compat
+   code, replace with equivalent cygwin library call.  Patch from vinschen
+   at redhat.com, ok djm@.
+ - (djm) [sshconnect2.c] vis.h isn't available everywhere
+
+20080716
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/07/15 02:23:14
+     [sftp.1]
+     number of pipelined requests is now 64;
+     prodded by Iain.Morgan AT nasa.gov
+   - djm@cvs.openbsd.org 2008/07/16 11:51:14
+     [clientloop.c]
+     rename variable first_gc -> last_gc (since it is actually the last
+     in the list).
+   - djm@cvs.openbsd.org 2008/07/16 11:52:19
+     [channels.c]
+     this loop index should be automatic, not static
+
+20080714
+ - (djm) OpenBSD CVS Sync
+   - sthen@cvs.openbsd.org 2008/07/13 21:22:52
+     [ssh-keygen.c]
+     Change "ssh-keygen -F [host] -l" to not display random art unless
+     -v is also specified, making it consistent with the manual and other
+     uses of -l.
+     ok grunk@
+   - djm@cvs.openbsd.org 2008/07/13 22:13:07
+     [channels.c]
+     use struct sockaddr_storage instead of struct sockaddr for accept(2)
+     address argument. from visibilis AT yahoo.com in bz#1485; ok markus@
+   - djm@cvs.openbsd.org 2008/07/13 22:16:03
+     [sftp.c]
+     increase number of piplelined requests so they properly fill the
+     (recently increased) channel window. prompted by rapier AT psc.edu;
+     ok markus@
+   - djm@cvs.openbsd.org 2008/07/14 01:55:56
+     [sftp-server.8]
+     mention requirement for /dev/log inside chroot when using sftp-server
+     with ChrootDirectory
+ - (djm) [openbsd-compat/bindresvport.c] Rename variables s/sin/in/ to
+   avoid clash with sin(3) function; reported by
+   cristian.ionescu-idbohrn AT axis.com
+ - (djm) [openbsd-compat/rresvport.c] Add unistd.h for missing close()
+   prototype; reported by cristian.ionescu-idbohrn AT axis.com
+ - (djm) [umac.c] Rename variable s/buffer_ptr/bufp/ to avoid clash;
+   reported by cristian.ionescu-idbohrn AT axis.com
+ - (djm) [contrib/cygwin/Makefile contrib/cygwin/ssh-host-config]
+   [contrib/cygwin/ssh-user-config contrib/cygwin/sshd-inetd]
+   Revamped and simplified Cygwin ssh-host-config script that uses
+   unified csih configuration tool. Requires recent Cygwin.
+   Patch from vinschen AT redhat.com
+
+20080712
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/07/12 04:52:50
+     [channels.c]
+     unbreak; move clearing of cctx struct to before first use
+     reported by dkrause@
+   - djm@cvs.openbsd.org 2008/07/12 05:33:41
+     [scp.1]
+     better description for -i flag:
+     s/RSA authentication/public key authentication/
+ - (djm) [openbsd-compat/fake-rfc2553.c openbsd-compat/fake-rfc2553.h]
+   return EAI_FAMILY when trying to lookup unsupported address family;
+   from vinschen AT redhat.com
+
+20080711
+ - (djm) OpenBSD CVS Sync
+   - stevesk@cvs.openbsd.org 2008/07/07 00:31:41
+     [ttymodes.c]
+     we don't need arg after the debug3() was removed.  from lint.
+     ok djm@
+   - stevesk@cvs.openbsd.org 2008/07/07 23:32:51
+     [key.c]
+     /*NOTREACHED*/ for lint warning:
+       warning: function key_equal falls off bottom without returning value
+     ok djm@
+   - markus@cvs.openbsd.org 2008/07/10 18:05:58
+     [channels.c]
+     missing bzero; from mickey; ok djm@
+   - markus@cvs.openbsd.org 2008/07/10 18:08:11
+     [clientloop.c monitor.c monitor_wrap.c packet.c packet.h sshd.c]
+     sync v1 and v2 traffic accounting; add it to sshd, too;
+     ok djm@, dtucker@
+
+20080709
+ - (djm) [Makefile.in] Print "all tests passed" when all regress tests pass
+ - (djm) [auth1.c] Fix format string vulnerability in protocol 1 PAM
+   account check failure path. The vulnerable format buffer is supplied
+   from PAM and should not contain attacker-supplied data.
+ - (djm) [auth.c] Missing unistd.h for close()
+ - (djm) [configure.ac] Add -Wformat-security to CFLAGS for gcc 3.x and 4.x
+
+20080705
+ - (djm) [auth.c] Fixed test for locked account on HP/UX with shadowed
+   passwords disabled. bz#1083 report & patch from senthilkumar_sen AT
+   hotpop.com, w/ dtucker@
+ - (djm) [atomicio.c configure.ac] Disable poll() fallback in atomiciov for
+   Tru64. readv doesn't seem to be a comparable object there.
+   bz#1386, patch from dtucker@ ok me
+ - (djm) [Makefile.in] Pass though pass to conch for interop tests
+ - (djm) [configure.ac] unbreak: remove extra closing brace
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/07/04 23:08:25
+     [packet.c]
+     handle EINTR in packet_write_poll()l ok dtucker@
+   - djm@cvs.openbsd.org 2008/07/04 23:30:16
+     [auth1.c auth2.c]
+     Make protocol 1 MaxAuthTries logic match protocol 2's.
+     Do not treat the first protocol 2 authentication attempt as
+     a failure IFF it is for method "none".
+     Makes MaxAuthTries' user-visible behaviour identical for
+     protocol 1 vs 2.
+     ok dtucker@
+   - djm@cvs.openbsd.org 2008/07/05 05:16:01
+     [PROTOCOL]
+     grammar
+
+20080704
+ - (dtucker) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/07/02 13:30:34
+     [auth2.c]
+     really really remove the freebie "none" auth try for protocol 2
+   - djm@cvs.openbsd.org 2008/07/02 13:47:39
+     [ssh.1 ssh.c]
+     When forking after authentication ("ssh -f") with ExitOnForwardFailure
+     enabled, delay the fork until after replies for any -R forwards have
+     been seen. Allows for robust detection of -R forward failure when
+     using -f (similar to bz#92); ok dtucker@
+   - otto@cvs.openbsd.org 2008/07/03 21:46:58
+     [auth2-pubkey.c]
+     avoid nasty double free; ok dtucker@ djm@
+   - djm@cvs.openbsd.org 2008/07/04 03:44:59
+     [servconf.c groupaccess.h groupaccess.c]
+     support negation of groups in "Match group" block (bz#1315); ok dtucker@
+   - dtucker@cvs.openbsd.org 2008/07/04 03:47:02
+     [monitor.c]
+     Make debug a little clearer.  ok djm@
+   - djm@cvs.openbsd.org 2008/06/30 08:07:34
+     [regress/key-options.sh]
+     shell portability: use "=" instead of "==" in test(1) expressions,
+     double-quote string with backslash escaped /
+   - djm@cvs.openbsd.org 2008/06/30 10:31:11
+     [regress/{putty-transfer,putty-kex,putty-ciphers}.sh]
+     remove "set -e" left over from debugging
+   - djm@cvs.openbsd.org 2008/06/30 10:43:03
+     [regress/conch-ciphers.sh]
+     explicitly disable conch options that could interfere with the test
+ - (dtucker) [sftp-server.c] Bug #1447: fall back to racy rename if link
+   returns EXDEV.  Patch from Mike Garrison, ok djm@
+ - (djm) [atomicio.c channels.c clientloop.c defines.h includes.h]
+   [packet.c scp.c serverloop.c sftp-client.c ssh-agent.c ssh-keyscan.c]
+   [sshd.c] Explicitly handle EWOULDBLOCK wherever we handle EAGAIN, on
+   some platforms (HP nonstop) it is a distinct errno;
+   bz#1467 reported by sconeu AT yahoo.com; ok dtucker@
+
+20080702
+ - (dtucker) OpenBSD CVS Sync
+    - djm@cvs.openbsd.org 2008/06/30 08:05:59
+      [PROTOCOL.agent]
+      typo: s/constraint_date/constraint_data/
+   - djm@cvs.openbsd.org 2008/06/30 12:15:39
+     [serverloop.c]
+     only pass channel requests on session channels through to the session
+     channel handler, avoiding spurious log messages; ok! markus@
+   - djm@cvs.openbsd.org 2008/06/30 12:16:02
+     [nchan.c]
+     only send eow@openssh.com notifications for session channels; ok! markus@
+   - djm@cvs.openbsd.org 2008/06/30 12:18:34
+     [PROTOCOL]
+     clarify that eow@openssh.com is only sent on session channels
+   - dtucker@cvs.openbsd.org 2008/07/01 07:20:52
+     [sshconnect.c]
+     Check ExitOnForwardFailure if forwardings are disabled due to a failed
+     host key check.  ok djm@
+   - dtucker@cvs.openbsd.org 2008/07/01 07:24:22
+     [sshconnect.c sshd.c]
+     Send CR LF during protocol banner exchanges, but only for Protocol 2 only,
+     in order to comply with RFC 4253.  bz #1443, ok djm@
+   - stevesk@cvs.openbsd.org 2008/07/01 23:12:47
+     [PROTOCOL.agent]
+     fix some typos; ok djm@
+   - djm@cvs.openbsd.org 2008/07/02 02:24:18
+     [sshd_config sshd_config.5 sshd.8 servconf.c]
+     increase default size of ssh protocol 1 ephemeral key from 768 to 1024
+     bits; prodded by & ok dtucker@ ok deraadt@
+   - dtucker@cvs.openbsd.org 2008/07/02 12:03:51
+     [auth-rsa.c auth.c auth2-pubkey.c auth.h]
+     Merge duplicate host key file checks, based in part on a patch from Rob
+     Holland via bz #1348 .  Also checks for non-regular files during protocol
+     1 RSA auth.  ok djm@
+   - djm@cvs.openbsd.org 2008/07/02 12:36:39
+     [auth2-none.c auth2.c]
+     Make protocol 2 MaxAuthTries behaviour a little more sensible:
+     Check whether client has exceeded MaxAuthTries before running
+     an authentication method and skip it if they have, previously it
+     would always allow one try (for "none" auth).
+     Preincrement failure count before post-auth test - previously this
+     checked and postincremented, also to allow one "none" try.
+     Together, these two changes always count the "none" auth method
+     which could be skipped by a malicious client (e.g. an SSH worm)
+     to get an extra attempt at a real auth method. They also make
+     MaxAuthTries=0 a useful way to block users entirely (esp. in a
+     sshd_config Match block).
+     Also, move sending of any preauth banner from "none" auth method
+     to the first call to input_userauth_request(), so worms that skip
+     the "none" method get to see it too.
+
+20080630
+ - (djm) OpenBSD CVS Sync
+   - dtucker@cvs.openbsd.org 2008/06/10 23:13:43
+     [regress/Makefile regress/key-options.sh]
+     Add regress test for key options.  ok djm@
+   - dtucker@cvs.openbsd.org 2008/06/11 23:11:40
+     [regress/Makefile]
+     Don't run cipher-speed test by default; mistakenly enabled by me
+   - djm@cvs.openbsd.org 2008/06/28 13:57:25
+     [regress/Makefile regress/test-exec.sh regress/conch-ciphers.sh]
+     very basic regress test against Twisted Conch in "make interop"
+     target (conch is available in ports/devel/py-twisted/conch);
+     ok markus@
+ - (djm) [regress/Makefile] search for conch by path, like we do putty
+
+20080629
+ - (djm) OpenBSD CVS Sync
+   - martynas@cvs.openbsd.org 2008/06/21 07:46:46
+     [sftp.c]
+     use optopt to get invalid flag, instead of return value of getopt,
+     which is always '?';  ok djm@
+   - otto@cvs.openbsd.org 2008/06/25 11:13:43
+     [key.c]
+     add key length to visual fingerprint; zap magical constants;
+     ok grunk@ djm@
+   - djm@cvs.openbsd.org 2008/06/26 06:10:09
+     [sftp-client.c sftp-server.c]
+     allow the sftp chmod(2)-equivalent operation to set set[ug]id/sticky
+     bits. Note that this only affects explicit setting of modes (e.g. via
+     sftp(1)'s chmod command) and not file transfers. (bz#1310)
+     ok deraadt@ at c2k8
+   - djm@cvs.openbsd.org 2008/06/26 09:19:40
+     [dh.c dh.h moduli.c]
+     when loading moduli from /etc/moduli in sshd(8), check that they
+     are of the expected "safe prime" structure and have had
+     appropriate primality tests performed;
+     feedback and ok dtucker@
+   - grunk@cvs.openbsd.org 2008/06/26 11:46:31
+     [readconf.c readconf.h ssh.1 ssh_config.5 sshconnect.c]
+     Move SSH Fingerprint Visualization away from sharing the config option
+     CheckHostIP to an own config option named VisualHostKey.
+     While there, fix the behaviour that ssh would draw a random art picture
+     on every newly seen host even when the option was not enabled.
+     prodded by deraadt@, discussions,
+     help and ok markus@ djm@ dtucker@
+   - jmc@cvs.openbsd.org 2008/06/26 21:11:46
+     [ssh.1]
+     add VisualHostKey to the list of options listed in -o;
+   - djm@cvs.openbsd.org 2008/06/28 07:25:07
+     [PROTOCOL]
+     spelling fixes
+   - djm@cvs.openbsd.org 2008/06/28 13:58:23
+     [ssh-agent.c]
+     refuse to add a key that has unknown constraints specified;
+     ok markus
+   - djm@cvs.openbsd.org 2008/06/28 14:05:15
+     [ssh-agent.c]
+     reset global compat flag after processing a protocol 2 signature
+     request with the legacy DSA encoding flag set; ok markus
+   - djm@cvs.openbsd.org 2008/06/28 14:08:30
+     [PROTOCOL PROTOCOL.agent]
+     document the protocol used by ssh-agent; "looks ok" markus@
+
+20080628
+ - (djm) [RFC.nroff contrib/cygwin/Makefile contrib/suse/openssh.spec]
+   RFC.nroff lacks a license, remove it (it is long gone in OpenBSD).
+
+20080626
+ - (djm) [Makefile.in moduli.5] Include moduli(5) manpage from OpenBSD.
+   (bz#1372)
+ - (djm) [ contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+   [contrib/suse/openssh.spec] Include moduli.5 in RPM spec files.
+
+20080616
+ - (dtucker) OpenBSD CVS Sync
+   - dtucker@cvs.openbsd.org 2008/06/16 13:22:53
+     [session.c channels.c]
+     Rename the isatty argument to is_tty so we don't shadow
+     isatty(3).  ok markus@
+ - (dtucker) [channels.c] isatty -> is_tty here too.
+
+20080615
+ - (dtucker) [configure.ac] Enable -fno-builtin-memset when using gcc.
+ - OpenBSD CVS Sync
+   - dtucker@cvs.openbsd.org 2008/06/14 15:49:48
+     [sshd.c]
+     wrap long line at 80 chars
+   - dtucker@cvs.openbsd.org 2008/06/14 17:07:11
+     [sshd.c]
+     ensure default umask disallows at least group and world write; ok djm@
+   - djm@cvs.openbsd.org 2008/06/14 18:33:43
+     [session.c]
+     suppress the warning message from chdir(homedir) failures
+     when chrooted (bz#1461); ok dtucker
+   - dtucker@cvs.openbsd.org 2008/06/14 19:42:10
+     [scp.1]
+     Mention that scp follows symlinks during -r.  bz #1466,
+     from nectar at apple
+   - dtucker@cvs.openbsd.org 2008/06/15 16:55:38
+     [sshd_config.5]
+     MaxSessions is allowed in a Match block too
+   - dtucker@cvs.openbsd.org 2008/06/15 16:58:40
+     [servconf.c sshd_config.5]
+     Allow MaxAuthTries within a Match block.  ok djm@
+   - djm@cvs.openbsd.org 2008/06/15 20:06:26
+     [channels.c channels.h session.c]
+     don't call isatty() on a pty master, instead pass a flag down to
+     channel_set_fds() indicating that te fds refer to a tty. Fixes a
+     hang on exit on Solaris (bz#1463) in portable but is actually
+     a generic bug; ok dtucker deraadt markus
+
+20080614
+ - (djm) [openbsd-compat/sigact.c] Avoid NULL derefs in ancient sigaction
+   replacement code; patch from ighighi AT gmail.com in bz#1240;
+   ok dtucker
+
+20080613
+ - (dtucker) OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2008/06/13 09:44:36
+     [packet.c]
+     compile on older gcc; no decl after code
+   - dtucker@cvs.openbsd.org 2008/06/13 13:56:59
+     [monitor.c]
+     Clear key options in the monitor on failed authentication, prevents
+     applying additional restrictions to non-pubkey authentications in
+     the case where pubkey fails but another method subsequently succeeds.
+     bz #1472, found by Colin Watson, ok markus@ djm@
+   - dtucker@cvs.openbsd.org 2008/06/13 14:18:51
+     [auth2-pubkey.c auth-rhosts.c]
+     Include unistd.h for close(), prevents warnings in -portable
+   - dtucker@cvs.openbsd.org 2008/06/13 17:21:20
+     [mux.c]
+     Friendlier error messages for mux fallback.  ok djm@
+   - dtucker@cvs.openbsd.org 2008/06/13 18:55:22
+     [scp.c]
+     Prevent -Wsign-compare warnings on LP64 systems.  bz #1192, ok deraadt@
+   - grunk@cvs.openbsd.org 2008/06/13 20:13:26
+     [ssh.1]
+     Explain the use of SSH fpr visualization using random art, and cite the
+     original scientific paper inspiring that technique.
+     Much help with English and nroff by jmc@, thanks.
+ - (dtucker) [configure.ac] Bug #1276: avoid linking against libgssapi, which
+   despite its name doesn't seem to implement all of GSSAPI.  Patch from
+   Jan Engelhardt, sanity checked by Simon Wilkinson.
+
+20080612
+ - (dtucker) OpenBSD CVS Sync
+   - jmc@cvs.openbsd.org 2008/06/11 07:30:37
+     [sshd.8]
+     kill trailing whitespace;
+   - grunk@cvs.openbsd.org 2008/06/11 21:01:35
+     [ssh_config.5 key.h readconf.c readconf.h ssh-keygen.1 ssh-keygen.c key.c
+      sshconnect.c]
+     Introduce SSH Fingerprint ASCII Visualization, a technique inspired by the
+     graphical hash visualization schemes known as "random art", and by
+     Dan Kaminsky's musings on the subject during a BlackOp talk at the
+     23C3 in Berlin.
+     Scientific publication (original paper):
+     "Hash Visualization: a New Technique to improve Real-World Security",
+     Perrig A. and Song D., 1999, International Workshop on Cryptographic
+     Techniques and E-Commerce (CrypTEC '99)
+     http://sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
+     The algorithm used here is a worm crawling over a discrete plane,
+     leaving a trace (augmenting the field) everywhere it goes.
+     Movement is taken from dgst_raw 2bit-wise.  Bumping into walls
+     makes the respective movement vector be ignored for this turn,
+     thus switching to the other color of the chessboard.
+     Graphs are not unambiguous for now, because circles in graphs can be
+     walked in either direction.
+     discussions with several people,
+     help, corrections and ok markus@ djm@
+   - grunk@cvs.openbsd.org 2008/06/11 21:38:25
+     [ssh-keygen.c]
+     ssh-keygen -lv -f /etc/ssh/ssh_host_rsa_key.pub
+     would not display you the random art as intended, spotted by canacar@
+   - grunk@cvs.openbsd.org 2008/06/11 22:20:46
+     [ssh-keygen.c ssh-keygen.1]
+     ssh-keygen would write fingerprints to STDOUT, and random art to STDERR,
+     that is not how it was envisioned.
+     Also correct manpage saying that -v is needed along with -l for it to work.
+     spotted by naddy@
+   - otto@cvs.openbsd.org 2008/06/11 23:02:22
+     [key.c]
+     simpler way of computing the augmentations; ok grunk@
+   - grunk@cvs.openbsd.org 2008/06/11 23:03:56
+     [ssh_config.5]
+     CheckHostIP set to ``fingerprint'' will display both hex and random art
+     spotted by naddy@
+   - grunk@cvs.openbsd.org 2008/06/11 23:51:57
+     [key.c]
+     #define statements that are not atoms need braces around them, else they
+     will cause trouble in some cases.
+     Also do a computation of -1 once, and not in a loop several times.
+     spotted by otto@
+   - dtucker@cvs.openbsd.org 2008/06/12 00:03:49
+     [dns.c canohost.c sshconnect.c]
+     Do not pass "0" strings as ports to getaddrinfo because the lookups
+     can slow things down and we never use the service info anyway. bz
+     #859, patch from YOSHIFUJI Hideaki and John Devitofranceschi.  ok
+     deraadt@ djm@
+     djm belives that the reason for the "0" strings is to ensure that
+     it's not possible to call getaddrinfo with both host and port being
+     NULL.  In the case of canohost.c host is a local array.  In the
+     case of sshconnect.c, it's checked for null immediately before use.
+     In dns.c it ultimately comes from ssh.c:main() and is guaranteed to
+     be non-null but it's not obvious, so I added a warning message in
+     case it is ever passed a null.
+   - grunk@cvs.openbsd.org 2008/06/12 00:13:55
+     [sshconnect.c]
+     Make ssh print the random art also when ssh'ing to a host using IP only.
+     spotted by naddy@, ok and help djm@ dtucker@
+   - otto@cvs.openbsd.org 2008/06/12 00:13:13
+     [key.c]
+     use an odd number of rows and columns and a separate start marker, looks
+     better; ok grunk@
+   - djm@cvs.openbsd.org 2008/06/12 03:40:52
+     [clientloop.h mux.c channels.c clientloop.c channels.h]
+     Enable ~ escapes for multiplex slave sessions; give each channel
+     its own escape state and hook the escape filters up to muxed
+     channels. bz #1331
+     Mux slaves do not currently support the ~^Z and ~& escapes.
+     NB. this change cranks the mux protocol version, so a new ssh
+     mux client will not be able to connect to a running old ssh
+     mux master.
+     ok dtucker@
+   - djm@cvs.openbsd.org 2008/06/12 04:06:00
+     [clientloop.h ssh.c clientloop.c]
+     maintain an ordered queue of outstanding global requests that we
+     expect replies to, similar to the per-channel confirmation queue.
+     Use this queue to verify success or failure for remote forward
+     establishment in a race free way.
+     ok dtucker@
+   - djm@cvs.openbsd.org 2008/06/12 04:17:47
+     [clientloop.c]
+     thall shalt not code past the eightieth column
+   - djm@cvs.openbsd.org 2008/06/12 04:24:06
+     [ssh.c]
+     thal shalt not code past the eightieth column
+   - djm@cvs.openbsd.org 2008/06/12 05:15:41
+     [PROTOCOL]
+     document tun@openssh.com forwarding method
+   - djm@cvs.openbsd.org 2008/06/12 05:32:30
+     [mux.c]
+     some more TODO for me
+   - grunk@cvs.openbsd.org 2008/06/12 05:42:46
+     [key.c]
+     supply the key type (rsa1, rsa, dsa) as a caption in the frame of the
+     random art.  while there, stress the fact that the field base should at
+     least be 8 characters for the pictures to make sense.
+     comment and ok djm@
+   - grunk@cvs.openbsd.org 2008/06/12 06:32:59
+     [key.c]
+     We already mark the start of the worm, now also mark the end of the worm
+     in our random art drawings.
+     ok djm@
+   - djm@cvs.openbsd.org 2008/06/12 15:19:17
+     [clientloop.h channels.h clientloop.c channels.c mux.c]
+     The multiplexing escape char handler commit last night introduced a
+     small memory leak per session; plug it.
+   - dtucker@cvs.openbsd.org 2008/06/12 16:35:31
+     [ssh_config.5 ssh.c]
+     keyword expansion for localcommand.  ok djm@
+   - jmc@cvs.openbsd.org 2008/06/12 19:10:09
+     [ssh_config.5 ssh-keygen.1]
+     tweak the ascii art text; ok grunk
+   - dtucker@cvs.openbsd.org 2008/06/12 20:38:28
+     [sshd.c sshconnect.c packet.h misc.c misc.h packet.c]
+     Make keepalive timeouts apply while waiting for a packet, particularly
+     during key renegotiation (bz #1363).  With djm and Matt Day, ok djm@
+   - djm@cvs.openbsd.org 2008/06/12 20:47:04
+     [sftp-client.c]
+     print extension revisions for extensions that we understand
+   - djm@cvs.openbsd.org 2008/06/12 21:06:25
+     [clientloop.c]
+     I was coalescing expected global request confirmation replies at
+     the wrong end of the queue - fix; prompted by markus@
+   - grunk@cvs.openbsd.org 2008/06/12 21:14:46
+     [ssh-keygen.c]
+     make ssh-keygen -lf show the key type just as ssh-add -l would do it
+     ok djm@ markus@
+   - grunk@cvs.openbsd.org 2008/06/12 22:03:36
+     [key.c]
+     add my copyright, ok djm@
+   - ian@cvs.openbsd.org 2008/06/12 23:24:58
+     [sshconnect.c]
+     tweak wording in message, ok deraadt@ jmc@
+   - dtucker@cvs.openbsd.org 2008/06/13 00:12:02
+     [sftp.h log.h]
+     replace __dead with __attribute__((noreturn)), makes things
+     a little easier to port.  Also, add it to sigdie().  ok djm@
+   - djm@cvs.openbsd.org 2008/06/13 00:16:49
+     [mux.c]
+     fall back to creating a new TCP connection on most multiplexing errors
+     (socket connect fail, invalid version, refused permittion, corrupted
+     messages, etc.); bz #1329 ok dtucker@
+   - dtucker@cvs.openbsd.org 2008/06/13 00:47:53
+     [mux.c]
+     upcast size_t to u_long to match format arg; ok djm@
+   - dtucker@cvs.openbsd.org 2008/06/13 00:51:47
+     [mac.c]
+     upcast another size_t to u_long to match format
+   - dtucker@cvs.openbsd.org 2008/06/13 01:38:23
+     [misc.c]
+     upcast uid to long with matching %ld, prevents warnings in portable
+   - djm@cvs.openbsd.org 2008/06/13 04:40:22
+     [auth2-pubkey.c auth-rhosts.c]
+     refuse to read ~/.shosts or ~/.ssh/authorized_keys that are not
+     regular files; report from Solar Designer via Colin Watson in bz#1471
+     ok dtucker@ deraadt
+  - (dtucker) [clientloop.c serverloop.c]  channel_register_filter now
+    takes 2 more args.  with djm@
+  - (dtucker) [defines.h] Bug #1112: __dead is, well dead. Based on a patch
+    from Todd Vierling.
+  - (dtucker) [auth-sia.c] Bug #1241: support password expiry on Tru64 SIA
+    systems.  Patch from R. Scott Bailey.
+  - (dtucker) [umac.c] STORE_UINT32_REVERSED and endian_convert are never used
+    on big endian machines, so ifdef them for little-endian only to prevent
+    unused function warnings on big-endians.
+  - (dtucker) [openbsd-compat/setenv.c] Make offsets size_t to prevent
+    compiler warnings on some platforms.  Based on a discussion with otto@
+
+20080611
+ - (djm) [channels.c configure.ac]
+   Do not set SO_REUSEADDR on wildcard X11 listeners (X11UseLocalhost=no)
+   bz#1464; ok dtucker 
+
+20080610
+ - (dtucker) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/06/10 03:57:27
+     [servconf.c match.h sshd_config.5]
+     support CIDR address matching in sshd_config "Match address" blocks, with
+     full support for negation and fall-back to classic wildcard matching.
+     For example:
+     Match address 192.0.2.0/24,3ffe:ffff::/32,!10.*
+         PasswordAuthentication yes
+     addrmatch.c code mostly lifted from flowd's addr.c
+     feedback and ok dtucker@
+   - djm@cvs.openbsd.org 2008/06/10 04:17:46
+     [sshd_config.5]
+     better reference for pattern-list
+   - dtucker@cvs.openbsd.org 2008/06/10 04:50:25
+     [sshd.c channels.h channels.c log.c servconf.c log.h servconf.h sshd.8]
+     Add extended test mode (-T) and connection parameters for test mode (-C).
+     -T causes sshd to write its effective configuration to stdout and exit.
+     -C causes any relevant Match rules to be applied before output.  The
+     combination allows tesing of the parser and config files.  ok deraadt djm
+   - jmc@cvs.openbsd.org 2008/06/10 07:12:00
+     [sshd_config.5]
+     tweak previous;
+   - jmc@cvs.openbsd.org 2008/06/10 08:17:40
+     [sshd.8 sshd.c]
+     - update usage()
+     - fix SYNOPSIS, and sort options
+     - some minor additional fixes
+   - dtucker@cvs.openbsd.org 2008/06/09 18:06:32
+     [regress/test-exec.sh]
+     Don't generate putty keys if we're not going to use them.  ok djm
+   - dtucker@cvs.openbsd.org 2008/06/10 05:23:32
+     [regress/addrmatch.sh regress/Makefile]
+     Regress test for Match CIDR rules.  ok djm@
+   - dtucker@cvs.openbsd.org 2008/06/10 15:21:41
+     [test-exec.sh]
+     Use a more portable construct for checking if we're running a putty test
+   - dtucker@cvs.openbsd.org 2008/06/10 15:28:49
+     [test-exec.sh]
+     Add quotes
+   - dtucker@cvs.openbsd.org 2008/06/10 18:21:24
+     [ssh_config.5]
+     clarify that Host patterns are space-separated.  ok deraadt
+   - djm@cvs.openbsd.org 2008/06/10 22:15:23
+     [PROTOCOL ssh.c serverloop.c]
+     Add a no-more-sessions@openssh.com global request extension that the
+     client sends when it knows that it will never request another session
+     (i.e. when session multiplexing is disabled). This allows a server to
+     disallow further session requests and terminate the session.
+     Why would a non-multiplexing client ever issue additional session
+     requests? It could have been attacked with something like SSH'jack:
+     http://www.storm.net.nz/projects/7
+     feedback & ok markus
+   - djm@cvs.openbsd.org 2008/06/10 23:06:19
+     [auth-options.c match.c servconf.c addrmatch.c sshd.8]
+     support CIDR address matching in .ssh/authorized_keys from="..." stanzas
+     ok and extensive testing dtucker@
+   - dtucker@cvs.openbsd.org 2008/06/10 23:21:34
+     [bufaux.c]
+     Use '\0' for a nul byte rather than unadorned 0.  ok djm@
+   - dtucker@cvs.openbsd.org 2008/06/10 23:13:43
+     [Makefile regress/key-options.sh]
+     Add regress test for key options.  ok djm@
+ - (dtucker) [openbsd-compat/fake-rfc2553.h] Add sin6_scope_id to sockaddr_in6
+   since the new CIDR code in addmatch.c references it.
+ - (dtucker) [Makefile.in configure.ac regress/addrmatch.sh] Skip IPv6
+   specific tests on platforms that don't do IPv6.
+ - (dtucker) [Makefile.in] Define TEST_SSH_IPV6 in make's arguments as well
+   as environment.
+ - (dtucker) [Makefile.in] Move addrmatch.o to libssh.a where it's needed now.
+
+20080609
+ - (dtucker) OpenBSD CVS Sync
+   - dtucker@cvs.openbsd.org 2008/06/08 17:04:41
+     [sftp-server.c]
+     Add case for ENOSYS in errno_to_portable; ok deraadt
+   - dtucker@cvs.openbsd.org 2008/06/08 20:15:29
+     [sftp.c sftp-client.c sftp-client.h]
+     Have the sftp client store the statvfs replies in wire format,
+     which prevents problems when the server's native sizes exceed the
+     client's.
+     Also extends the sizes of the remaining 32bit wire format to 64bit,
+     they're specified as unsigned long in the standard.
+   - dtucker@cvs.openbsd.org 2008/06/09 13:02:39
+     [sftp-server.c]
+     Extend 32bit -> 64bit values for statvfs extension missed in previous
+     commit.
+   - dtucker@cvs.openbsd.org 2008/06/09 13:38:46
+     [PROTOCOL]
+     Use a $OpenBSD tag so our scripts will sync changes.
+
+20080608
+ - (dtucker) [configure.ac defines.h sftp-client.c sftp-server.c sftp.c
+   openbsd-compat/Makefile.in openbsd-compat/openbsd-compat.h
+   openbsd-compat/bsd-statvfs.{c,h}] Add a null implementation of statvfs and
+   fstatvfs and remove #defines around statvfs code.  ok djm@
+ - (dtucker) [configure.ac defines.h sftp-client.c M sftp-server.c] Add a
+   macro to convert fsid to unsigned long for platforms where fsid is a
+   2-member array.
+
+20080607
+ - (dtucker) [mux.c] Include paths.h inside ifdef HAVE_PATHS_H.
+ - (dtucker) [configure.ac defines.h sftp-client.c sftp-server.c sftp.c]
+   Do not enable statvfs extensions on platforms that do not have statvfs.
+ - (dtucker) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/05/19 06:14:02
+     [packet.c] unbreak protocol keepalive timeouts bz#1465; ok dtucker@
+   - djm@cvs.openbsd.org 2008/05/19 15:45:07
+     [sshtty.c ttymodes.c sshpty.h]
+     Fix sending tty modes when stdin is not a tty (bz#1199). Previously
+     we would send the modes corresponding to a zeroed struct termios,
+     whereas we should have been sending an empty list of modes.
+     Based on patch from daniel.ritz AT alcatel.ch; ok dtucker@ markus@
+   - djm@cvs.openbsd.org 2008/05/19 15:46:31
+     [ssh-keygen.c]
+     support -l (print fingerprint) in combination with -F (find host) to
+     search for a host in ~/.ssh/known_hosts and display its fingerprint;
+     ok markus@
+   - djm@cvs.openbsd.org 2008/05/19 20:53:52
+     [clientloop.c]
+     unbreak tree by committing this bit that I missed from:
+     Fix sending tty modes when stdin is not a tty (bz#1199). Previously
+     we would send the modes corresponding to a zeroed struct termios,
+     whereas we should have been sending an empty list of modes.
+     Based on patch from daniel.ritz AT alcatel.ch; ok dtucker@ markus@ 
+
+20080604
+ - (djm) [openbsd-compat/bsd-arc4random.c] Fix math bug that caused bias
+   in arc4random_uniform with upper_bound in (2^30,2*31). Note that 
+   OpenSSH did not make requests with upper bounds in this range.
+
+20080519
+ - (djm) [configure.ac mux.c sftp.c openbsd-compat/Makefile.in]
+   [openbsd-compat/fmt_scaled.c openbsd-compat/openbsd-compat.h]
+   Fix compilation on Linux, including pulling in fmt_scaled(3)
+   implementation from OpenBSD's libutil.
+
+20080518
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/04/04 05:14:38
+     [sshd_config.5]
+     ChrootDirectory is supported in Match blocks (in fact, it is most useful
+     there). Spotted by Minstrel AT minstrel.org.uk
+   - djm@cvs.openbsd.org 2008/04/04 06:44:26
+     [sshd_config.5]
+     oops, some unrelated stuff crept into that commit - backout.
+     spotted by jmc@
+   - djm@cvs.openbsd.org 2008/04/05 02:46:02
+     [sshd_config.5]
+     HostbasedAuthentication is supported under Match too
+ - (djm) [openbsd-compat/bsd-arc4random.c openbsd-compat/openbsd-compat.c]
+     [configure.ac] Implement arc4random_buf(), import implementation of
+     arc4random_uniform() from OpenBSD
+ - (djm) [openbsd-compat/bsd-arc4random.c] Warning fixes
+ - (djm) [openbsd-compat/port-tun.c] needs sys/queue.h
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2008/04/13 00:22:17
+     [dh.c sshd.c]
+     Use arc4random_buf() when requesting more than a single word of output
+     Use arc4random_uniform() when the desired random number upper bound
+     is not a power of two
+     ok deraadt@ millert@
+   - djm@cvs.openbsd.org 2008/04/18 12:32:11
+     [sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c sftp.h]
+     introduce sftp extension methods statvfs@openssh.com and
+     fstatvfs@openssh.com that implement statvfs(2)-like operations,
+     based on a patch from miklos AT szeredi.hu (bz#1399)
+     also add a "df" command to the sftp client that uses the
+     statvfs@openssh.com to produce a df(1)-like display of filesystem
+     space and inode utilisation
+     ok markus@
+   - jmc@cvs.openbsd.org 2008/04/18 17:15:47
+     [sftp.1]
+     macro fixage;
+   - djm@cvs.openbsd.org 2008/04/18 22:01:33
+     [session.c]
+     remove unneccessary parentheses
+   - otto@cvs.openbsd.org 2008/04/29 11:20:31
+     [monitor_mm.h]
+     garbage collect two unused fields in struct mm_master; ok markus@
+   - djm@cvs.openbsd.org 2008/04/30 10:14:03
+     [ssh-keyscan.1 ssh-keyscan.c]
+     default to rsa (protocol 2) keys, instead of rsa1 keys; spotted by
+     larsnooden AT openoffice.org
+   - pyr@cvs.openbsd.org 2008/05/07 05:49:37
+     [servconf.c servconf.h session.c sshd_config.5]
+     Enable the AllowAgentForwarding option in sshd_config (global and match
+     context), to specify if agents should be permitted on the server.
+     As the man page states:
+     ``Note that disabling Agent forwarding does not improve security
+     unless users are also denied shell access, as they can always install
+     their own forwarders.''
+     ok djm@, ok and a mild frown markus@
+   - pyr@cvs.openbsd.org 2008/05/07 06:43:35
+     [sshd_config]
+     push the sshd_config bits in, spotted by ajacoutot@
+   - jmc@cvs.openbsd.org 2008/05/07 08:00:14
+     [sshd_config.5]
+     sort;
+   - markus@cvs.openbsd.org 2008/05/08 06:59:01
+     [bufaux.c buffer.h channels.c packet.c packet.h]
+     avoid extra malloc/copy/free when receiving data over the net;
+     ~10% speedup for localhost-scp; ok djm@
+   - djm@cvs.openbsd.org 2008/05/08 12:02:23
+     [auth-options.c auth1.c channels.c channels.h clientloop.c gss-serv.c]
+     [monitor.c monitor_wrap.c nchan.c servconf.c serverloop.c session.c]
+     [ssh.c sshd.c]
+     Implement a channel success/failure status confirmation callback
+     mechanism. Each channel maintains a queue of callbacks, which will
+     be drained in order (RFC4253 guarantees confirm messages are not
+     reordered within an channel).
+     Also includes a abandonment callback to clean up if a channel is
+     closed without sending confirmation messages. This probably
+     shouldn't happen in compliant implementations, but it could be
+     abused to leak memory.
+     ok markus@ (as part of a larger diff)
+   - djm@cvs.openbsd.org 2008/05/08 12:21:16
+     [monitor.c monitor_wrap.c session.h servconf.c servconf.h session.c]
+     [sshd_config sshd_config.5]
+     Make the maximum number of sessions run-time controllable via
+     a sshd_config MaxSessions knob. This is useful for disabling
+     login/shell/subsystem access while leaving port-forwarding working
+     (MaxSessions 0), disabling connection multiplexing (MaxSessions 1) or
+     simply increasing the number of allows multiplexed sessions.
+     Because some bozos are sure to configure MaxSessions in excess of the
+     number of available file descriptors in sshd (which, at peak, might be
+     as many as 9*MaxSessions), audit sshd to ensure that it doesn't leak fds
+     on error paths, and make it fail gracefully on out-of-fd conditions -
+     sending channel errors instead of than exiting with fatal().
+     bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com
+     ok markus@
+   - djm@cvs.openbsd.org 2008/05/08 13:06:11
+     [clientloop.c clientloop.h ssh.c]
+     Use new channel status confirmation callback system to properly deal
+     with "important" channel requests that fail, in particular command exec,
+     shell and subsystem requests. Previously we would optimistically assume
+     that the requests would always succeed, which could cause hangs if they
+     did not (e.g. when the server runs out of fds) or were unimplemented by
+     the server (bz #1384)
+     Also, properly report failing multiplex channel requests via the mux
+     client stderr (subject to LogLevel in the mux master) - better than
+     silently failing.
+     most bits ok markus@ (as part of a larger diff)
+   - djm@cvs.openbsd.org 2008/05/09 04:55:56
+     [channels.c channels.h clientloop.c serverloop.c]
+     Try additional addresses when connecting to a port forward destination
+     whose DNS name resolves to more than one address. The previous behaviour
+     was to try the first address and give up.
+     Reported by stig AT venaas.com in bz#343
+     great feedback and ok markus@
+   - djm@cvs.openbsd.org 2008/05/09 14:18:44
+     [clientloop.c clientloop.h ssh.c mux.c]
+     tidy up session multiplexing code, moving it into its own file and
+     making the function names more consistent - making ssh.c and
+     clientloop.c a fair bit more readable.
+     ok markus@
+   - djm@cvs.openbsd.org 2008/05/09 14:26:08
+     [ssh.c]
+     dingo stole my diff hunk
+   - markus@cvs.openbsd.org 2008/05/09 16:16:06
+     [session.c]
+     re-add the USE_PIPES code and enable it.
+     without pipes shutdown-read from the sshd does not trigger
+     a SIGPIPE when the forked program does a write.
+     ok djm@
+     (Id sync only, USE_PIPES never left portable OpenSSH)
+   - markus@cvs.openbsd.org 2008/05/09 16:17:51
+     [channels.c]
+     error-fd race: don't enable the error fd in the select bitmask
+     for channels with both in- and output closed, since the channel
+     will go away before we call select();
+     report, lots of debugging help and ok djm@
+   - markus@cvs.openbsd.org 2008/05/09 16:21:13
+     [channels.h clientloop.c nchan.c serverloop.c]
+     unbreak
+        ssh -2 localhost od /bin/ls | true
+     ignoring SIGPIPE by adding a new channel message (EOW) that signals
+     the peer that we're not interested in any data it might send.
+     fixes bz #85; discussion, debugging and ok djm@
+   - pvalchev@cvs.openbsd.org 2008/05/12 20:52:20
+     [umac.c]
+     Ensure nh_result lies on a 64-bit boundary (fixes warnings observed
+     on Itanium on Linux); from Dale Talcott (bug #1462); ok djm@
+   - djm@cvs.openbsd.org 2008/05/15 23:52:24
+     [nchan2.ms]
+     document eow message in ssh protocol 2 channel state machine;
+     feedback and ok markus@
+   - djm@cvs.openbsd.org 2008/05/18 21:29:05
+     [sftp-server.c]
+     comment extension announcement
+   - djm@cvs.openbsd.org 2008/05/16 08:30:42
+     [PROTOCOL]
+     document our protocol extensions and deviations; ok markus@
+   - djm@cvs.openbsd.org 2008/05/17 01:31:56
+     [PROTOCOL]
+     grammar and correctness fixes from stevesk@
+
+20080403
+ - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
+   time warnings on LynxOS. Patch from ops AT iki.fi
+ - (djm) Force string arguments to replacement setproctitle() though
+   strnvis first. Ok dtucker@
+
 20080403
  - (djm) OpenBSD CVS sync:
    - markus@cvs.openbsd.org 2008/04/02 15:36:51
index d61764338d1c376baaa5dbdf68ca023236cd4e66..22172e25f11ddc93f0741d9b3695ebe6b71d0591 100644 (file)
@@ -67,14 +67,14 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
        cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
        compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
        log.o match.o md-sha256.o moduli.o nchan.o packet.o \
-       readpass.o rsa.o ttymodes.o xmalloc.o \
+       readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
        atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
        monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
        kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
        entropy.o scard-opensc.o gss-genr.o umac.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
-       sshconnect.o sshconnect1.o sshconnect2.o
+       sshconnect.o sshconnect1.o sshconnect2.o mux.o
 
 SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
        sshpty.o sshlogin.o servconf.o serverloop.o \
@@ -88,8 +88,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
        loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
        audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o
 
-MANPAGES       = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
-MANPAGES_IN    = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
+MANPAGES       = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
+MANPAGES_IN    = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
 MANTYPE                = @MANTYPE@
 
 CONFIGFILES=sshd_config.out ssh_config.out moduli.out
@@ -106,6 +106,7 @@ PATHSUBS    = \
        -e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \
        -e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \
        -e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \
+       -e 's|/etc/moduli|$(sysconfdir)/moduli|g' \
        -e 's|/etc/ssh/moduli|$(sysconfdir)/moduli|g' \
        -e 's|/etc/ssh/sshrc|$(sysconfdir)/sshrc|g' \
        -e 's|/usr/X11R6/bin/xauth|$(XAUTH_PATH)|g' \
@@ -270,6 +271,7 @@ install-files: scard-install
        $(INSTALL) -m 644 ssh-agent.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
        $(INSTALL) -m 644 ssh-keygen.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
        $(INSTALL) -m 644 ssh-keyscan.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
+       $(INSTALL) -m 644 moduli.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/moduli.5
        $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5
        $(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5
        $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
@@ -394,6 +396,8 @@ tests interop-tests:        $(TARGETS)
        TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server"; \
        TEST_SSH_PLINK="plink"; \
        TEST_SSH_PUTTYGEN="puttygen"; \
+       TEST_SSH_CONCH="conch"; \
+       TEST_SSH_IPV6="@TEST_SSH_IPV6@" ; \
        cd $(srcdir)/regress || exit $$?; \
        $(MAKE) \
                .OBJDIR="$${BUILDDIR}/regress" \
@@ -412,8 +416,10 @@ tests interop-tests:       $(TARGETS)
                TEST_SSH_SFTPSERVER="$${TEST_SSH_SFTPSERVER}" \
                TEST_SSH_PLINK="$${TEST_SSH_PLINK}" \
                TEST_SSH_PUTTYGEN="$${TEST_SSH_PUTTYGEN}" \
+               TEST_SSH_CONCH="$${TEST_SSH_CONCH}" \
+               TEST_SSH_IPV6="@TEST_SSH_IPV6@" \
                EXEEXT="$(EXEEXT)" \
-               $@
+               $@ && echo all tests passed
 
 compat-tests: $(LIBCOMPAT)
        (cd openbsd-compat/regress && $(MAKE))
diff --git a/openssh/PROTOCOL b/openssh/PROTOCOL
new file mode 100644 (file)
index 0000000..37fd536
--- /dev/null
@@ -0,0 +1,243 @@
+This documents OpenSSH's deviations and extensions to the published SSH
+protocol.
+
+Note that OpenSSH's sftp and sftp-server implement revision 3 of the SSH
+filexfer protocol described in:
+
+http://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt
+
+Features from newer versions of the draft are not supported, unless
+explicitly implemented as extensions described below.
+
+The protocol used by OpenSSH's ssh-agent is described in the file
+PROTOCOL.agent
+
+1. transport: Protocol 2 MAC algorithm "umac-64@openssh.com"
+
+This is a new transport-layer MAC method using the UMAC algorithm
+(rfc4418). This method is identical to the "umac-64" method documented
+in:
+
+http://www.openssh.com/txt/draft-miller-secsh-umac-01.txt
+
+2. transport: Protocol 2 compression algorithm "zlib@openssh.com"
+
+This transport-layer compression method uses the zlib compression
+algorithm (identical to the "zlib" method in rfc4253), but delays the
+start of compression until after authentication has completed. This
+avoids exposing compression code to attacks from unauthenticated users.
+
+The method is documented in:
+
+http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
+
+3. connection: Channel write close extension "eow@openssh.com"
+
+The SSH connection protocol (rfc4254) provides the SSH_MSG_CHANNEL_EOF
+message to allow an endpoint to signal its peer that it will send no
+more data over a channel. Unfortunately, there is no symmetric way for
+an endpoint to request that its peer should cease sending data to it
+while still keeping the channel open for the endpoint to send data to
+the peer.
+
+This is desirable, since it saves the transmission of data that would
+otherwise need to be discarded and it allows an endpoint to signal local
+processes of the condition, e.g. by closing the corresponding file
+descriptor.
+
+OpenSSH implements a channel extension message to perform this
+signalling: "eow@openssh.com" (End Of Write). This message is sent by
+an endpoint when the local output of a session channel is closed or
+experiences a write error. The message is formatted as follows:
+
+       byte            SSH_MSG_CHANNEL_REQUEST
+       uint32          recipient channel
+       string          "eow@openssh.com"
+       boolean         FALSE
+
+On receiving this message, the peer SHOULD cease sending data of
+the channel and MAY signal the process from which the channel data
+originates (e.g. by closing its read file descriptor).
+
+As with the symmetric SSH_MSG_CHANNEL_EOF message, the channel does
+remain open after a "eow@openssh.com" has been sent and more data may
+still be sent in the other direction. This message does not consume
+window space and may be sent even if no window space is available.
+
+4. connection: disallow additional sessions extension
+   "no-more-sessions@openssh.com"
+
+Most SSH connections will only ever request a single session, but a
+attacker may abuse a running ssh client to surreptitiously open
+additional sessions under their control. OpenSSH provides a global
+request "no-more-sessions@openssh.com" to mitigate this attack.
+
+When an OpenSSH client expects that it will never open another session
+(i.e. it has been started with connection multiplexing disabled), it
+will send the following global request:
+
+       byte            SSH_MSG_GLOBAL_REQUEST
+       string          "no-more-sessions@openssh.com"
+       char            want-reply
+
+On receipt of such a message, an OpenSSH server will refuse to open
+future channels of type "session" and instead immediately abort the
+connection.
+
+Note that this is not a general defence against compromised clients
+(that is impossible), but it thwarts a simple attack.
+
+5. connection: Tunnel forward extension "tun@openssh.com"
+
+OpenSSH supports layer 2 and layer 3 tunnelling via the "tun@openssh.com"
+channel type. This channel type supports forwarding of network packets
+with datagram boundaries intact between endpoints equipped with 
+interfaces like the BSD tun(4) device. Tunnel forwarding channels are
+requested by the client with the following packet:
+
+       byte            SSH_MSG_CHANNEL_OPEN
+       string          "tun@openssh.com"
+       uint32          sender channel
+       uint32          initial window size
+       uint32          maximum packet size
+       uint32          tunnel mode
+       uint32          remote unit number
+
+The "tunnel mode" parameter specifies whether the tunnel should forward
+layer 2 frames or layer 3 packets. It may take one of the following values:
+
+       SSH_TUNMODE_POINTOPOINT  1              /* layer 3 packets */
+       SSH_TUNMODE_ETHERNET     2              /* layer 2 frames */
+
+The "tunnel unit number" specifies the remote interface number, or may
+be zero to allow the server to automatically chose an interface. A server
+that is not willing to open a client-specified unit should refuse the
+request with a SSH_MSG_CHANNEL_OPEN_FAILURE error. On successful open,
+the server should reply with SSH_MSG_CHANNEL_OPEN_SUCCESS.
+
+Once established the client and server may exchange packet or frames
+over the tunnel channel by encapsulating them in SSH protocol strings
+and sending them as channel data. This ensures that packet boundaries
+are kept intact. Specifically, packets are transmitted using normal
+SSH_MSG_CHANNEL_DATA packets:
+
+       byte            SSH_MSG_CHANNEL_DATA
+       uint32          recipient channel
+       string          data
+
+The contents of the "data" field for layer 3 packets is:
+
+       uint32                  packet length
+       uint32                  address family
+       byte[packet length - 4] packet data
+
+The "address family" field identifies the type of packet in the message.
+It may be one of:
+
+       SSH_TUN_AF_INET         2               /* IPv4 */
+       SSH_TUN_AF_INET6        24              /* IPv6 */
+
+The "packet data" field consists of the IPv4/IPv6 datagram itself
+without any link layer header.
+
+The contents of the "data" field for layer 3 packets is:
+
+       uint32                  packet length
+       byte[packet length]     frame
+
+The "frame" field contains an IEEE 802.3 Ethernet frame, including
+header.
+
+6. sftp: Reversal of arguments to SSH_FXP_SYMLINK
+
+When OpenSSH's sftp-server was implemented, the order of the arguments
+to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately,
+the reversal was not noticed until the server was widely deployed. Since
+fixing this to follow the specification would cause incompatibility, the
+current order was retained. For correct operation, clients should send
+SSH_FXP_SYMLINK as follows:
+
+       uint32          id
+       string          targetpath
+       string          linkpath
+
+7. sftp: Server extension announcement in SSH_FXP_VERSION
+
+OpenSSH's sftp-server lists the extensions it supports using the
+standard extension announcement mechanism in the SSH_FXP_VERSION server
+hello packet:
+
+       uint32          3               /* protocol version */
+       string          ext1-name
+       string          ext1-version
+       string          ext2-name
+       string          ext2-version
+       ...
+       string          extN-name
+       string          extN-version
+
+Each extension reports its integer version number as an ASCII encoded
+string, e.g. "1". The version will be incremented if the extension is
+ever changed in an incompatible way. The server MAY advertise the same
+extension with multiple versions (though this is unlikely). Clients MUST
+check the version number before attempting to use the extension.
+
+8. sftp: Extension request "posix-rename@openssh.com"
+
+This operation provides a rename operation with POSIX semantics, which
+are different to those provided by the standard SSH_FXP_RENAME in
+draft-ietf-secsh-filexfer-02.txt. This request is implemented as a
+SSH_FXP_EXTENDED request with the following format:
+
+       uint32          id
+       string          "posix-rename@openssh.com"
+       string          oldpath
+       string          newpath
+
+On receiving this request the server will perform the POSIX operation
+rename(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
+9. sftp: Extension requests "statvfs@openssh.com" and
+         "fstatvfs@openssh.com"
+
+These requests correspond to the statvfs and fstatvfs POSIX system
+interfaces. The "statvfs@openssh.com" request operates on an explicit
+pathname, and is formatted as follows:
+
+       uint32          id
+       string          "statvfs@openssh.com"
+       string          path
+
+The "fstatvfs@openssh.com" operates on an open file handle:
+
+       uint32          id
+       string          "fstatvfs@openssh.com"
+       string          handle
+
+These requests return a SSH_FXP_STATUS reply on failure. On success they
+return the following SSH_FXP_EXTENDED_REPLY reply:
+
+       uint32          id
+       uint64          f_bsize         /* file system block size */
+       uint64          f_frsize        /* fundamental fs block size */
+       uint64          f_blocks        /* number of blocks (unit f_frsize) */
+       uint64          f_bfree         /* free blocks in file system */
+       uint64          f_bavail        /* free blocks for non-root */
+       uint64          f_files         /* total file inodes */
+       uint64          f_ffree         /* free file inodes */
+       uint64          f_favail        /* free file inodes for to non-root */
+       uint64          f_fsid          /* file system id */
+       uint64          f_flag          /* bit mask of f_flag values */
+       uint64          f_namemax       /* maximum filename length */
+
+The values of the f_flag bitmask are as follows:
+
+       #define SSH_FXE_STATVFS_ST_RDONLY       0x1     /* read-only */
+       #define SSH_FXE_STATVFS_ST_NOSUID       0x2     /* no setuid */
+
+Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
+advertised in the SSH_FXP_VERSION hello with version "2".
+
+$OpenBSD: PROTOCOL,v 1.11 2008/07/05 05:16:01 djm Exp $
diff --git a/openssh/PROTOCOL.agent b/openssh/PROTOCOL.agent
new file mode 100644 (file)
index 0000000..49adbdd
--- /dev/null
@@ -0,0 +1,516 @@
+This describes the protocol used by OpenSSH's ssh-agent.
+
+OpenSSH's agent supports managing keys for the standard SSH protocol
+2 as well as the legacy SSH protocol 1. Support for these key types
+is almost completely disjoint - in all but a few cases, operations on
+protocol 2 keys cannot see or affect protocol 1 keys and vice-versa.
+
+Protocol 1 and protocol 2 keys are separated because of the differing
+cryptographic usage: protocol 1 private RSA keys are used to decrypt
+challenges that were encrypted with the corresponding public key,
+whereas protocol 2 RSA private keys are used to sign challenges with
+a private key for verification with the corresponding public key. It
+is considered unsound practice to use the same key for signing and
+encryption.
+
+With a couple of exceptions, the protocol message names used in this
+document indicate which type of key the message relates to. SSH_*
+messages refer to protocol 1 keys only. SSH2_* messages refer to
+protocol 2 keys. Furthermore, the names also indicate whether the
+message is a request to the agent (*_AGENTC_*) or a reply from the
+agent (*_AGENT_*). Section 3 below contains the mapping of the
+protocol message names to their integer values.
+
+1. Data types
+
+Because of support for legacy SSH protocol 1 keys, OpenSSH's agent
+protocol makes use of some data types not defined in RFC 4251.
+
+1.1 uint16
+
+The "uint16" data type is a simple MSB-first 16 bit unsigned integer
+encoded in two bytes.
+
+1.2 mpint1
+
+The "mpint1" type represents an arbitrary precision integer (bignum).
+Its format is as follows:
+
+       uint16                  bits
+       byte[(bits + 7) / 8]    bignum
+
+"bignum" contains an unsigned arbitrary precision integer encoded as
+eight bits per byte in big-endian (MSB first) format.
+
+Note the difference between the "mpint1" encoding and the "mpint"
+encoding defined in RFC 4251. Also note that the length of the encoded
+integer is specified in bits, not bytes and that the byte length of
+the integer must be calculated by rounding up the number of bits to the
+nearest eight.
+
+2. Protocol Messages
+
+All protocol messages are prefixed with their length in bytes, encoded
+as a 32 bit unsigned integer. Specifically:
+
+       uint32                  message_length
+       byte[message_length]    message
+
+The following message descriptions refer only to the content the
+"message" field.
+
+2.1 Generic server responses
+
+The following generic messages may be sent by the server in response to
+requests from the client. On success the agent may reply either with:
+
+       byte                    SSH_AGENT_SUCCESS
+
+or a request-specific success message.
+
+On failure, the agent may reply with:
+
+       byte                    SSH_AGENT_FAILURE
+
+SSH_AGENT_FAILURE messages are also sent in reply to unknown request
+types.
+
+2.2 Adding keys to the agent
+
+Keys are added to the agent using the SSH_AGENTC_ADD_RSA_IDENTITY and
+SSH2_AGENTC_ADD_IDENTITY requests for protocol 1 and protocol 2 keys
+respectively.
+
+Two variants of these requests are SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
+and SSH2_AGENTC_ADD_ID_CONSTRAINED - these add keys with optional
+"constraints" on their usage.
+
+OpenSSH may be built with support for keys hosted on a smartcard
+or other hardware security module. These keys may be added
+to the agent using the SSH_AGENTC_ADD_SMARTCARD_KEY and
+SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED requests.
+
+2.2.1 Key constraints
+
+The OpenSSH agent supports some basic optional constraints on key usage.
+At present there are two constraints defined.
+
+The first constraint limits the validity duration of a key. It is
+encoded as:
+
+       byte                    SSH_AGENT_CONSTRAIN_LIFETIME
+       uint32                  seconds
+
+Where "seconds" contains the number of seconds that the key shall remain
+valid measured from the moment that the agent receives it. After the
+validity period has expired, OpenSSH's agent will erase these keys from
+memory.
+
+The second constraint requires the agent to seek explicit user
+confirmation before performing private key operations with the loaded
+key. This constraint is encoded as:
+
+       byte                    SSH_AGENT_CONSTRAIN_CONFIRM
+
+Zero or more constraints may be specified when adding a key with one
+of the *_CONSTRAINED requests. Multiple constraints are appended
+consecutively to the end of the request:
+
+       byte                    constraint1_type
+       ....                    constraint1_data
+       byte                    constraint2_type
+       ....                    constraint2_data
+       ....
+       byte                    constraintN_type
+       ....                    constraintN_data
+
+Such a sequence of zero or more constraints will be referred to below
+as "constraint[]". Agents may determine whether there are constraints
+by checking whether additional data exists in the "add key" request
+after the key data itself. OpenSSH will refuse to add a key if it
+contains unknown constraints.
+
+2.2.2 Add protocol 1 key
+
+A client may add a protocol 1 key to an agent with the following
+request:
+
+       byte                    SSH_AGENTC_ADD_RSA_IDENTITY or
+                               SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
+       uint32                  ignored
+       mpint1                  rsa_n
+       mpint1                  rsa_e
+       mpint1                  rsa_d
+       mpint1                  rsa_iqmp
+       mpint1                  rsa_q
+       mpint1                  rsa_p
+       string                  key_comment
+       constraint[]            key_constraints
+
+Note that there is some redundancy in the key parameters; a key could be
+fully specified using just rsa_q, rsa_p and rsa_e at the cost of extra
+computation.
+
+"key_constraints" may only be present if the request type is
+SSH_AGENTC_ADD_RSA_IDENTITY.
+
+The agent will reply with a SSH_AGENT_SUCCESS if the key has been
+successfully added or a SSH_AGENT_FAILURE if an error occurred.
+
+2.2.3 Add protocol 2 key
+
+The OpenSSH agent supports DSA and RSA keys for protocol 2. DSA keys may
+be added using the following request
+
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ssh-dss"
+       mpint                   dsa_p
+       mpint                   dsa_q
+       mpint                   dsa_g
+       mpint                   dsa_public_key
+       mpint                   dsa_private_key
+       string                  key_comment
+       constraint[]            key_constraints
+
+RSA keys may be added with this request:
+
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ssh-rsa"
+       mpint                   rsa_n
+       mpint                   rsa_e
+       mpint                   rsa_d
+       mpint                   rsa_iqmp
+       mpint                   rsa_p
+       mpint                   rsa_q
+       string                  key_comment
+       constraint[]            key_constraints
+
+Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse
+order to the protocol 1 add keys message. As with the corresponding
+protocol 1 "add key" request, the private key is overspecified to avoid
+redundant processing.
+
+For both DSA and RSA key add requests, "key_constraints" may only be
+present if the request type is SSH2_AGENTC_ADD_ID_CONSTRAINED.
+
+The agent will reply with a SSH_AGENT_SUCCESS if the key has been
+successfully added or a SSH_AGENT_FAILURE if an error occurred.
+
+2.2.4 Loading keys from a smartcard
+
+The OpenSSH agent may have optional smartcard support built in to it. If
+so, it supports an operation to load keys from a smartcard. Technically,
+only the public components of the keys are loaded into the agent so
+this operation really arranges for future private key operations to be
+delegated to the smartcard.
+
+       byte                    SSH_AGENTC_ADD_SMARTCARD_KEY or
+                               SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED
+       string                  reader_id
+       string                  pin
+       constraint[]            key_constraints
+
+"reader_id" is an identifier to a smartcard reader and "pin"
+is a PIN or passphrase used to unlock the private key(s) on the
+device. "key_constraints" may only be present if the request type is
+SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED.
+
+This operation may load all SSH keys that are unlocked using the
+"pin" on the specified reader. The type of key loaded (protocol 1
+or protocol 2) will be specified by the smartcard itself, it is not
+client-specified.
+
+The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
+been successfully loaded or a SSH_AGENT_FAILURE if an error occurred.
+The agent will also return SSH_AGENT_FAILURE if it does not support
+smartcards.
+
+2.3 Removing multiple keys
+
+A client may request that an agent delete all protocol 1 keys using the
+following request:
+
+       byte                    SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES
+
+This message requests the deletion of all protocol 2 keys:
+
+       byte                    SSH2_AGENTC_REMOVE_ALL_IDENTITIES
+
+On success, the agent will delete all keys of the requested type and
+reply with a SSH_AGENT_SUCCESS message. If an error occurred, the agent
+will reply with SSH_AGENT_FAILURE.
+
+Note that, to delete all keys (both protocol 1 and 2), a client
+must send both a SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES and a
+SSH2_AGENTC_REMOVE_ALL_IDENTITIES request.
+
+2.4 Removing specific keys
+
+2.4.1 Removing a protocol 1 key
+
+Removal of a protocol 1 key may be requested with the following message:
+
+       byte                    SSH_AGENTC_REMOVE_RSA_IDENTITY
+       uint32                  key_bits
+       mpint1                  rsa_e
+       mpint1                  rsa_n
+
+Note that key_bits is strictly redundant, as it may be inferred by the
+length of rsa_n.
+
+The agent will delete any private key matching the specified public key
+and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
+return SSH_AGENT_FAILURE.
+
+2.4.2 Removing a protocol 2 key
+
+Protocol 2 keys may be removed with the following request:
+
+       byte                    SSH2_AGENTC_REMOVE_IDENTITY
+       string                  key_blob
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for either of the supported key types: "ssh-dss" or
+"ssh-rsa".
+
+The agent will delete any private key matching the specified public key
+and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
+return SSH_AGENT_FAILURE.
+
+2.4.3 Removing keys loaded from a smartcard
+
+A client may request that a server remove one or more smartcard-hosted
+keys using this message:
+
+       byte                    SSH_AGENTC_REMOVE_SMARTCARD_KEY
+       string                  reader_id
+       string                  pin
+
+"reader_id" the an identifier to a smartcard reader and "pin" is a PIN
+or passphrase used to unlock the private key(s) on the device.
+
+When this message is received, and if the agent supports
+smartcard-hosted keys, it will delete all keys that are hosted on the
+specified smartcard that may be accessed with the given "pin".
+
+The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
+been successfully removed or a SSH_AGENT_FAILURE if an error occurred.
+The agent will also return SSH_AGENT_FAILURE if it does not support
+smartcards.
+
+2.5 Requesting a list of known keys
+
+An agent may be requested to list which keys it holds. Different
+requests exist for protocol 1 and protocol 2 keys.
+
+2.5.1 Requesting a list of protocol 1 keys
+
+To request a list of protocol 1 keys that are held in the agent, a
+client may send the following message:
+
+       byte                    SSH_AGENTC_REQUEST_RSA_IDENTITIES
+
+The agent will reply with the following message:
+
+       byte                    SSH_AGENT_RSA_IDENTITIES_ANSWER
+       uint32                  num_keys
+
+Followed by zero or more consecutive keys, encoded as:
+
+       uint32                  bits
+       mpint1                  rsa_e
+       mpint1                  rsa_n
+       string                  key_comment
+
+2.5.2 Requesting a list of protocol 2 keys
+
+A client may send the following message to request a list of
+protocol 2 keys that are stored in the agent:
+
+       byte                    SSH2_AGENTC_REQUEST_IDENTITIES
+
+The agent will reply with the following message header:
+
+       byte                    SSH2_AGENT_IDENTITIES_ANSWER
+       uint32                  num_keys
+
+Followed by zero or more consecutive keys, encoded as:
+
+       string                  key_blob
+       string                  key_comment
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for either of the supported key types: "ssh-dss" or
+"ssh-rsa".
+
+2.6 Private key operations
+
+The purpose of the agent is to perform private key operations, such as
+signing and encryption without requiring a passphrase to unlock the
+key and without allowing the private key itself to be exposed. There
+are separate requests for the protocol 1 and protocol 2 private key
+operations.
+
+2.6.1 Protocol 1 private key challenge
+
+The private key operation used in version 1 of the SSH protocol is
+decrypting a challenge that has been encrypted with a public key.
+It may be requested using this message:
+
+       byte                    SSH_AGENTC_RSA_CHALLENGE
+       uint32                  ignored
+       mpint1                  rsa_e
+       mpint1                  rsa_n
+       mpint1                  encrypted_challenge
+       byte[16]                session_id
+       uint32                  response_type /* must be 1 */
+
+"rsa_e" and "rsa_n" are used to identify which private key to use.
+"encrypted_challenge" is a challenge blob that has (presumably)
+been encrypted with the public key and must be in the range 
+1 <= encrypted_challenge < 2^256. "session_id" is the SSH protocol 1
+session ID (computed from the server host key, the server semi-ephemeral
+key and the session cookie).
+
+"ignored" and "response_type" exist for compatibility with legacy
+implementations. "response_type" must be equal to 1; other response
+types are not supported.
+
+On receiving this request, the server decrypts the "encrypted_challenge"
+using the private key matching the supplied (rsa_e, rsa_n) values. For
+the response derivation, the decrypted challenge is represented as an
+unsigned, big-endian integer encoded in a 32 byte buffer (i.e. values
+smaller than 2^248 will have leading 0 bytes).
+
+The response value is then calculated as:
+
+       response = MD5(decrypted_challenge || session_id)
+
+and returned in the following message
+
+       byte                    SSH_AGENT_RSA_RESPONSE
+       byte[16]                response
+
+If the agent cannot find the key specified by the supplied (rsa_e,
+rsa_n) then it will return SSH_AGENT_FAILURE.
+
+2.6.2 Protocol 2 private key signature request
+
+A client may use the following message to request signing of data using
+a protocol 2 key:
+
+       byte                    SSH2_AGENTC_SIGN_REQUEST
+       string                  key_blob
+       string                  data
+       uint32                  flags
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for either of the supported key types: "ssh-dss" or
+"ssh-rsa". "flags" is a bit-mask, but at present only one possible value
+is defined (see below for its meaning):
+
+       SSH_AGENT_OLD_SIGNATURE         1
+
+Upon receiving this request, the agent will look up the private key that
+corresponds to the public key contained in key_blob. It will use this
+private key to sign the "data" and produce a signature blob using the
+key type-specific method described in RFC 4253 section 6.6 "Public Key
+Algorithms".
+
+An exception to this is for "ssh-dss" keys where the "flags" word
+contains the value SSH_AGENT_OLD_SIGNATURE. In this case, a legacy
+signature encoding is used in lieu of the standard one. In this case,
+the DSA signature blob is encoded as:
+
+       byte[40]                signature
+
+The signature will be returned in the response message:
+
+       byte                    SSH2_AGENT_SIGN_RESPONSE
+       string                  signature_blob
+
+If the agent cannot find the key specified by the supplied key_blob then
+it will return SSH_AGENT_FAILURE.
+
+2.7 Locking or unlocking an agent
+
+The agent supports temporary locking with a passphrase to suspend
+processing of sensitive operations until it has been unlocked with the
+same passphrase. To lock an agent, a client send the following request:
+
+       byte                    SSH_AGENTC_LOCK
+       string                  passphrase
+
+Upon receipt of this message and if the agent is not already locked,
+it will suspend processing requests and return a SSH_AGENT_SUCCESS
+reply. If the agent is already locked, it will return SSH_AGENT_FAILURE.
+
+While locked, the agent will refuse all requests except
+SSH_AGENTC_UNLOCK, SSH_AGENTC_REQUEST_RSA_IDENTITIES and
+SSH2_AGENTC_REQUEST_IDENTITIES. The "request identities" requests are
+treated specially by a locked agent: it will always return an empty list
+of keys.
+
+To unlock an agent, a client may request:
+
+       byte                    SSH_AGENTC_UNLOCK
+       string                  passphrase
+
+If the passphrase matches and the agent is locked, then it will resume
+processing all requests and return SSH_AGENT_SUCCESS. If the agent
+is not locked or the passphrase does not match then it will return
+SSH_AGENT_FAILURE.
+
+Locking and unlocking affects both protocol 1 and protocol 2 keys.
+
+3. Protocol message numbers
+
+3.1 Requests from client to agent for protocol 1 key operations
+
+       SSH_AGENTC_REQUEST_RSA_IDENTITIES               1
+       SSH_AGENTC_RSA_CHALLENGE                        3
+       SSH_AGENTC_ADD_RSA_IDENTITY                     7
+       SSH_AGENTC_REMOVE_RSA_IDENTITY                  8
+       SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES            9
+       SSH_AGENTC_ADD_RSA_ID_CONSTRAINED               24
+
+3.2 Requests from client to agent for protocol 2 key operations
+
+       SSH2_AGENTC_REQUEST_IDENTITIES                  11
+       SSH2_AGENTC_SIGN_REQUEST                        13
+       SSH2_AGENTC_ADD_IDENTITY                        17
+       SSH2_AGENTC_REMOVE_IDENTITY                     18
+       SSH2_AGENTC_REMOVE_ALL_IDENTITIES               19
+       SSH2_AGENTC_ADD_ID_CONSTRAINED                  25
+
+3.3 Key-type independent requests from client to agent
+
+       SSH_AGENTC_ADD_SMARTCARD_KEY                    20
+       SSH_AGENTC_REMOVE_SMARTCARD_KEY                 21
+       SSH_AGENTC_LOCK                                 22
+       SSH_AGENTC_UNLOCK                               23
+       SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED        26
+
+3.4 Generic replies from agent to client
+
+       SSH_AGENT_FAILURE                               5
+       SSH_AGENT_SUCCESS                               6
+
+3.5 Replies from agent to client for protocol 1 key operations
+
+       SSH_AGENT_RSA_IDENTITIES_ANSWER                 2
+       SSH_AGENT_RSA_RESPONSE                          4
+
+3.6 Replies from agent to client for protocol 2 key operations
+
+       SSH2_AGENT_IDENTITIES_ANSWER                    12
+       SSH2_AGENT_SIGN_RESPONSE                        14
+
+3.7 Key constraint identifiers
+
+       SSH_AGENT_CONSTRAIN_LIFETIME                    1
+       SSH_AGENT_CONSTRAIN_CONFIRM                     2
+
+$OpenBSD: PROTOCOL.agent,v 1.4 2008/07/01 23:12:47 stevesk Exp $
index 312fef0883d41995af2335410eea60062438de6d..7ce15e41b1c66ec65c8bb01d26e4d23401056113 100644 (file)
@@ -1,4 +1,4 @@
-See http://www.openssh.com/txt/release-5.0 for the release notes.
+See http://www.openssh.com/txt/release-5.1 for the release notes.
 
 - A Japanese translation of this document and of the OpenSSH FAQ is
 - available at http://www.unixuser.org/~haruyama/security/openssh/index.html
diff --git a/openssh/addrmatch.c b/openssh/addrmatch.c
new file mode 100644 (file)
index 0000000..2086afe
--- /dev/null
@@ -0,0 +1,421 @@
+/*     $OpenBSD: addrmatch.c,v 1.3 2008/06/10 23:06:19 djm Exp $ */
+
+/*
+ * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "match.h"
+#include "log.h"
+
+struct xaddr {
+       sa_family_t     af;
+       union {
+               struct in_addr          v4;
+               struct in6_addr         v6;
+               u_int8_t                addr8[16];
+               u_int32_t               addr32[4];
+       } xa;               /* 128-bit address */
+       u_int32_t       scope_id;       /* iface scope id for v6 */
+#define v4     xa.v4
+#define v6     xa.v6
+#define addr8  xa.addr8
+#define addr32 xa.addr32
+};
+
+static int
+addr_unicast_masklen(int af)
+{
+       switch (af) {
+       case AF_INET:
+               return 32;
+       case AF_INET6:
+               return 128;
+       default:
+               return -1;
+       }
+}
+
+static inline int
+masklen_valid(int af, u_int masklen)
+{
+       switch (af) {
+       case AF_INET:
+               return masklen <= 32 ? 0 : -1;
+       case AF_INET6:
+               return masklen <= 128 ? 0 : -1;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Convert struct sockaddr to struct xaddr
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
+{
+       struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
+       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
+
+       memset(xa, '\0', sizeof(*xa));
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               if (slen < sizeof(*in4))
+                       return -1;
+               xa->af = AF_INET;
+               memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
+               break;
+       case AF_INET6:
+               if (slen < sizeof(*in6))
+                       return -1;
+               xa->af = AF_INET6;
+               memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
+               xa->scope_id = in6->sin6_scope_id;
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Calculate a netmask of length 'l' for address family 'af' and
+ * store it in 'n'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_netmask(int af, u_int l, struct xaddr *n)
+{
+       int i;
+
+       if (masklen_valid(af, l) != 0 || n == NULL)
+               return -1;
+
+       memset(n, '\0', sizeof(*n));
+       switch (af) {
+       case AF_INET:
+               n->af = AF_INET;
+               n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
+               return 0;
+       case AF_INET6:
+               n->af = AF_INET6;
+               for (i = 0; i < 4 && l >= 32; i++, l -= 32)
+                       n->addr32[i] = 0xffffffffU;
+               if (i < 4 && l != 0)
+                       n->addr32[i] = htonl((0xffffffff << (32 - l)) &
+                           0xffffffff);
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
+{
+       int i;
+
+       if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
+               return -1;
+
+       memcpy(dst, a, sizeof(*dst));
+       switch (a->af) {
+       case AF_INET:
+               dst->v4.s_addr &= b->v4.s_addr;
+               return 0;
+       case AF_INET6:
+               dst->scope_id = a->scope_id;
+               for (i = 0; i < 4; i++)
+                       dst->addr32[i] &= b->addr32[i];
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Compare addresses 'a' and 'b'
+ * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b)
+ */
+static int
+addr_cmp(const struct xaddr *a, const struct xaddr *b)
+{
+       int i;
+
+       if (a->af != b->af)
+               return a->af == AF_INET6 ? 1 : -1;
+
+       switch (a->af) {
+       case AF_INET:
+               if (a->v4.s_addr == b->v4.s_addr)
+                       return 0;
+               return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1;
+       case AF_INET6:
+               for (i = 0; i < 16; i++)
+                       if (a->addr8[i] - b->addr8[i] != 0)
+                               return a->addr8[i] > b->addr8[i] ? 1 : -1;
+               if (a->scope_id == b->scope_id)
+                       return 0;
+               return a->scope_id > b->scope_id ? 1 : -1;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Parse string address 'p' into 'n'
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_pton(const char *p, struct xaddr *n)
+{
+       struct addrinfo hints, *ai;
+
+       memset(&hints, '\0', sizeof(hints));
+       hints.ai_flags = AI_NUMERICHOST;
+
+       if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
+               return -1;
+
+       if (ai == NULL || ai->ai_addr == NULL)
+               return -1;
+
+       if (n != NULL &&
+           addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
+               freeaddrinfo(ai);
+               return -1;
+       }
+
+       freeaddrinfo(ai);
+       return 0;
+}
+
+/*
+ * Perform bitwise negation of address
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_invert(struct xaddr *n)
+{
+       int i;
+
+       if (n == NULL)
+               return (-1);
+
+       switch (n->af) {
+       case AF_INET:
+               n->v4.s_addr = ~n->v4.s_addr;
+               return (0);
+       case AF_INET6:
+               for (i = 0; i < 4; i++)
+                       n->addr32[i] = ~n->addr32[i];
+               return (0);
+       default:
+               return (-1);
+       }
+}
+
+/*
+ * Calculate a netmask of length 'l' for address family 'af' and
+ * store it in 'n'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_hostmask(int af, u_int l, struct xaddr *n)
+{
+       if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
+               return (-1);
+       return (0);
+}
+
+/*
+ * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)
+ * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.
+ */
+static int
+addr_is_all0s(const struct xaddr *a)
+{
+       int i;
+
+       switch (a->af) {
+       case AF_INET:
+               return (a->v4.s_addr == 0 ? 0 : -1);
+       case AF_INET6:;
+               for (i = 0; i < 4; i++)
+                       if (a->addr32[i] != 0)
+                               return (-1);
+               return (0);
+       default:
+               return (-1);
+       }
+}
+
+/*
+ * Test whether host portion of address 'a', as determined by 'masklen'
+ * is all zeros.
+ * Returns 0 on if host portion of address is all-zeros,
+ * -1 if not all zeros or on failure.
+ */
+static int
+addr_host_is_all0s(const struct xaddr *a, u_int masklen)
+{
+       struct xaddr tmp_addr, tmp_mask, tmp_result;
+
+       memcpy(&tmp_addr, a, sizeof(tmp_addr));
+       if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
+               return (-1);
+       if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
+               return (-1);
+       return (addr_is_all0s(&tmp_result));
+}
+
+/*
+ * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
+ * Return -1 on parse error, -2 on inconsistency or 0 on success.
+ */
+static int
+addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
+{
+       struct xaddr tmp;
+       long unsigned int masklen = 999;
+       char addrbuf[64], *mp, *cp;
+
+       /* Don't modify argument */
+       if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) > sizeof(addrbuf))
+               return -1;
+
+       if ((mp = strchr(addrbuf, '/')) != NULL) {
+               *mp = '\0';
+               mp++;
+               masklen = strtoul(mp, &cp, 10);
+               if (*mp == '\0' || *cp != '\0' || masklen > 128)
+                       return -1;
+       }
+
+       if (addr_pton(addrbuf, &tmp) == -1)
+               return -1;
+
+       if (mp == NULL)
+               masklen = addr_unicast_masklen(tmp.af);
+       if (masklen_valid(tmp.af, masklen) == -1)
+               return -2;
+       if (addr_host_is_all0s(&tmp, masklen) != 0)
+               return -2;
+
+       if (n != NULL)
+               memcpy(n, &tmp, sizeof(*n));
+       if (l != NULL)
+               *l = masklen;
+
+       return 0;
+}
+
+static int
+addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
+{
+       struct xaddr tmp_mask, tmp_result;
+
+       if (host->af != net->af)
+               return -1;
+
+       if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
+               return -1;
+       if (addr_and(&tmp_result, host, &tmp_mask) == -1)
+               return -1;
+       return addr_cmp(&tmp_result, net);
+}
+
+/*
+ * Match "addr" against list pattern list "_list", which may contain a
+ * mix of CIDR addresses and old-school wildcards.
+ *
+ * If addr is NULL, then no matching is performed, but _list is parsed
+ * and checked for well-formedness.
+ *
+ * Returns 1 on match found (never returned when addr == NULL).
+ * Returns 0 on if no match found, or no errors found when addr == NULL.
+ * Returns -1 on negated match found (never returned when addr == NULL).
+ * Returns -2 on invalid list entry.
+ */
+int
+addr_match_list(const char *addr, const char *_list)
+{
+       char *list, *cp, *o;
+       struct xaddr try_addr, match_addr;
+       u_int masklen, neg;
+       int ret = 0, r;
+
+       if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
+               debug2("%s: couldn't parse address %.100s", __func__, addr);
+               return 0;
+       }
+       if ((o = list = strdup(_list)) == NULL)
+               return -1;
+       while ((cp = strsep(&list, ",")) != NULL) {
+               neg = *cp == '!';
+               if (neg)
+                       cp++;
+               if (*cp == '\0') {
+                       ret = -2;
+                       break;
+               }
+               /* Prefer CIDR address matching */
+               r = addr_pton_cidr(cp, &match_addr, &masklen);
+               if (r == -2) {
+                       error("Inconsistent mask length for "
+                           "network \"%.100s\"", cp);
+                       ret = -2;
+                       break;
+               } else if (r == 0) {
+                       if (addr != NULL && addr_netmatch(&try_addr,
+                           &match_addr, masklen) == 0) {
+ foundit:
+                               if (neg) {
+                                       ret = -1;
+                                       break;
+                               }
+                               ret = 1;
+                       }
+                       continue;
+               } else {
+                       /* If CIDR parse failed, try wildcard string match */
+                       if (addr != NULL && match_pattern(addr, cp) == 1)
+                               goto foundit;
+               }
+       }
+       free(o);
+
+       return ret;
+}
index 575bf8900ee39e9e3cb89061934b659bd87b52d6..a6b2d127a9b803a8e4e1c85359d351eaaabecaf9 100644 (file)
@@ -63,11 +63,7 @@ atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
                case -1:
                        if (errno == EINTR)
                                continue;
-#ifdef EWOULDBLOCK
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
-#else
-                       if (errno == EAGAIN) {
-#endif
                                (void)poll(&pfd, 1, -1);
                                continue;
                        }
@@ -101,20 +97,20 @@ atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
        /* Make a copy of the iov array because we may modify it below */
        memcpy(iov, _iov, iovcnt * sizeof(*_iov));
 
+#ifndef BROKEN_READV_COMPARISON
        pfd.fd = fd;
        pfd.events = f == readv ? POLLIN : POLLOUT;
+#endif
        for (; iovcnt > 0 && iov[0].iov_len > 0;) {
                res = (f) (fd, iov, iovcnt);
                switch (res) {
                case -1:
                        if (errno == EINTR)
                                continue;
-#ifdef EWOULDBLOCK
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
-#else
-                       if (errno == EAGAIN) {
-#endif
+#ifndef BROKEN_READV_COMPARISON
                                (void)poll(&pfd, 1, -1);
+#endif
                                continue;
                        }
                        return 0;
index 6e2256961005562349addbf3b165ec2cd0fe02f9..25361455e5ace833cafb5fbd407964875ea8417d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.41 2008/03/26 21:28:14 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.43 2008/06/10 23:06:19 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdarg.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "match.h"
 #include "log.h"
@@ -225,8 +226,19 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                        }
                        patterns[i] = '\0';
                        opts++;
-                       if (match_host_and_ip(remote_host, remote_ip,
-                           patterns) != 1) {
+                       switch (match_host_and_ip(remote_host, remote_ip,
+                           patterns)) {
+                       case 1:
+                               xfree(patterns);
+                               /* Host name matches. */
+                               goto next_option;
+                       case -1:
+                               debug("%.100s, line %lu: invalid criteria",
+                                   file, linenum);
+                               auth_debug_add("%.100s, line %lu: "
+                                   "invalid criteria", file, linenum);
+                               /* FALLTHROUGH */
+                       case 0:
                                xfree(patterns);
                                logit("Authentication tried for %.100s with "
                                    "correct key but not from a permitted "
@@ -235,12 +247,10 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                                auth_debug_add("Your host '%.200s' is not "
                                    "permitted to use this key for login.",
                                    remote_host);
-                               /* deny access */
-                               return 0;
+                               break;
                        }
-                       xfree(patterns);
-                       /* Host name matches. */
-                       goto next_option;
+                       /* deny access */
+                       return 0;
                }
                cp = "permitopen=\"";
                if (strncasecmp(opts, cp, strlen(cp)) == 0) {
index cd0a7967a2442f0e9f4da9f658cd041a21513e72..5c12967016b4d62720e2aadfa10505c9c3f310a2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rhosts.c,v 1.41 2006/08/03 03:34:41 deraadt Exp $ */
+/* $OpenBSD: auth-rhosts.c,v 1.43 2008/06/13 14:18:51 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -26,6 +26,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include "packet.h"
 #include "buffer.h"
@@ -37,6 +39,7 @@
 #include "key.h"
 #include "hostfile.h"
 #include "auth.h"
+#include "misc.h"
 
 /* import */
 extern ServerOptions options;
@@ -55,12 +58,27 @@ check_rhosts_file(const char *filename, const char *hostname,
 {
        FILE *f;
        char buf[1024]; /* Must not be larger than host, user, dummy below. */
+       int fd;
+       struct stat st;
 
        /* Open the .rhosts file, deny if unreadable */
-       f = fopen(filename, "r");
-       if (!f)
+       if ((fd = open(filename, O_RDONLY|O_NONBLOCK)) == -1)
                return 0;
-
+       if (fstat(fd, &st) == -1) {
+               close(fd);
+               return 0;
+       }
+       if (!S_ISREG(st.st_mode)) {
+               logit("User %s hosts file %s is not a regular file",
+                   server_user, filename);
+               close(fd);
+               return 0;
+       }
+       unset_nonblock(fd);
+       if ((f = fdopen(fd, "r")) == NULL) {
+               close(fd);
+               return 0;
+       }
        while (fgets(buf, sizeof(buf), f)) {
                /* All three must be at least as big as buf to avoid overflows. */
                char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
index 69f9a5896fda25e6b0aa523dec0b1d85c0c0cf97..bf54620760ad62a8221765ec55e315bd9fa99ed9 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rsa.c,v 1.72 2006/11/06 21:25:27 markus Exp $ */
+/* $OpenBSD: auth-rsa.c,v 1.73 2008/07/02 12:03:51 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -173,7 +173,6 @@ auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
        u_int bits;
        FILE *f;
        u_long linenum = 0;
-       struct stat st;
        Key *key;
 
        /* Temporarily use the user's uid. */
@@ -182,27 +181,9 @@ auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
        /* The authorized keys. */
        file = authorized_keys_file(pw);
        debug("trying public RSA key file %s", file);
-
-       /* Fail quietly if file does not exist */
-       if (stat(file, &st) < 0) {
-               /* Restore the privileged uid. */
-               restore_uid();
-               xfree(file);
-               return (0);
-       }
-       /* Open the file containing the authorized keys. */
-       f = fopen(file, "r");
+       f = auth_openkeyfile(file, pw, options.strict_modes);
        if (!f) {
-               /* Restore the privileged uid. */
-               restore_uid();
-               xfree(file);
-               return (0);
-       }
-       if (options.strict_modes &&
-           secure_filename(f, file, pw, line, sizeof(line)) != 0) {
                xfree(file);
-               fclose(f);
-               logit("Authentication refused: %s", line);
                restore_uid();
                return (0);
        }
index a9e1c258ca61ec6c302e962aa1de2c8eda4d85dd..debf30201b73fe182419c63ae6f08735516ad9df 100644 (file)
 #include <unistd.h>
 #include <stdarg.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/security.h>
+#include <prot.h>
+#include <time.h>
 
 #include "ssh.h"
 #include "key.h"
@@ -49,6 +53,52 @@ extern ServerOptions options;
 extern int saved_argc;
 extern char **saved_argv;
 
+static int
+sia_password_change_required(const char *user)
+{
+       struct es_passwd *acct;
+       time_t pw_life;
+       time_t pw_date;
+
+       set_auth_parameters(saved_argc, saved_argv);
+
+       if ((acct = getespwnam(user)) == NULL) {
+               error("Couldn't access protected database entry for %s", user);
+               endprpwent();
+               return (0);
+       }
+
+       /* If forced password change flag is set, honor it */
+       if (acct->uflg->fg_psw_chg_reqd && acct->ufld->fd_psw_chg_reqd) {
+               endprpwent();
+               return (1);
+       }
+
+       /* Obtain password lifetime; if none, it can't have expired */
+       if (acct->uflg->fg_expire)
+               pw_life = acct->ufld->fd_expire;
+       else if (acct->sflg->fg_expire)
+               pw_life = acct->sfld->fd_expire;
+       else {
+               endprpwent();
+               return (0);
+       }
+
+       /* Offset from last change; if none, it must be expired */
+       if (acct->uflg->fg_schange)
+               pw_date = acct->ufld->fd_schange + pw_life;
+       else {
+               endprpwent();
+               return (1);
+       }
+
+       endprpwent();
+
+       /* If expiration date is prior to now, change password */
+       
+       return (pw_date <= time((time_t *) NULL));
+}
+
 int
 sys_auth_passwd(Authctxt *authctxt, const char *pass)
 {
@@ -76,6 +126,9 @@ sys_auth_passwd(Authctxt *authctxt, const char *pass)
 
        sia_ses_release(&ent);
 
+       authctxt->force_pwchange = sia_password_change_required(
+               authctxt->user);
+
        return (1);
 }
 
index f94c7d1d559e3f0de4a53c40b9a6983e4530902d..2370e5c2c714ab0d90b251eda90f8011eb71c4c0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.78 2007/09/21 08:15:29 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.79 2008/07/02 12:03:51 dtucker Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -32,6 +32,7 @@
 #include <netinet/in.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #ifdef HAVE_PATHS_H
 # include <paths.h>
 #endif
@@ -48,6 +49,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "xmalloc.h"
 #include "match.h"
@@ -113,6 +115,7 @@ allowed_user(struct passwd * pw)
 #endif /* USE_SHADOW */
 
        /* grab passwd field for locked account check */
+       passwd = pw->pw_passwd;
 #ifdef USE_SHADOW
        if (spw != NULL)
 #ifdef USE_LIBIAF
@@ -120,8 +123,6 @@ allowed_user(struct passwd * pw)
 #else
                passwd = spw->sp_pwdp;
 #endif /* USE_LIBIAF */
-#else
-       passwd = pw->pw_passwd;
 #endif
 
        /* check for locked account */
@@ -410,7 +411,7 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
  *
  * Returns 0 on success and -1 on failure
  */
-int
+static int
 secure_filename(FILE *f, const char *file, struct passwd *pw,
     char *err, size_t errlen)
 {
@@ -470,6 +471,46 @@ secure_filename(FILE *f, const char *file, struct passwd *pw,
        return 0;
 }
 
+FILE *
+auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
+{
+       char line[1024];
+       struct stat st;
+       int fd;
+       FILE *f;
+
+       /*
+        * Open the file containing the authorized keys
+        * Fail quietly if file does not exist
+        */
+       if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1)
+               return NULL;
+
+       if (fstat(fd, &st) < 0) {
+               close(fd);
+               return NULL;
+       }
+       if (!S_ISREG(st.st_mode)) {
+               logit("User %s authorized keys %s is not a regular file",
+                   pw->pw_name, file);
+               close(fd);
+               return NULL;
+       }
+       unset_nonblock(fd);
+       if ((f = fdopen(fd, "r")) == NULL) {
+               close(fd);
+               return NULL;
+       }
+       if (options.strict_modes &&
+           secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+               fclose(f);
+               logit("Authentication refused: %s", line);
+               return NULL;
+       }
+
+       return f;
+}
+
 struct passwd *
 getpwnamallow(const char *user)
 {
index f752c122089fad5d829be386bc3b6c27b239de64..6a70f0eb6a37cb1c53937e2dee8b5aad613cc2e8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.h,v 1.60 2007/09/21 08:15:29 djm Exp $ */
+/* $OpenBSD: auth.h,v 1.61 2008/07/02 12:03:51 dtucker Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -166,8 +166,7 @@ void        abandon_challenge_response(Authctxt *);
 char   *authorized_keys_file(struct passwd *);
 char   *authorized_keys_file2(struct passwd *);
 
-int
-secure_filename(FILE *, const char *, struct passwd *, char *, size_t);
+FILE   *auth_openkeyfile(const char *, struct passwd *, int);
 
 HostStatus
 check_key_in_hostfiles(struct passwd *, Key *, const char *,
index c17cc91335fb7baed4870f17270a15e011b03a45..b8a25587232781b79eba9e024388c3bafe5ac879 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth1.c,v 1.71 2007/09/21 08:15:29 djm Exp $ */
+/* $OpenBSD: auth1.c,v 1.73 2008/07/04 23:30:16 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -20,6 +20,7 @@
 #include <unistd.h>
 #include <pwd.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "rsa.h"
 #include "ssh1.h"
@@ -283,6 +284,8 @@ do_authloop(Authctxt *authctxt)
                    type != SSH_CMSG_AUTH_TIS_RESPONSE)
                        abandon_challenge_response(authctxt);
 
+               if (authctxt->failures >= options.max_authtries)
+                       goto skip;
                if ((meth = lookup_authmethod1(type)) == NULL) {
                        logit("Unknown message during authentication: "
                            "type %d", type);
@@ -351,7 +354,7 @@ do_authloop(Authctxt *authctxt)
                                        msg[len] = '\0';
                        else
                                msg = "Access denied.";
-                       packet_disconnect(msg);
+                       packet_disconnect("%s", msg);
                }
 #endif
 
@@ -367,7 +370,7 @@ do_authloop(Authctxt *authctxt)
                if (authenticated)
                        return;
 
-               if (authctxt->failures++ > options.max_authtries) {
+               if (++authctxt->failures >= options.max_authtries) {
 #ifdef SSH_AUDIT_EVENTS
                        PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
 #endif
index 663dec5d9e9574c8b9c61ccb297958f37e65aa9f..041051c53c7265af12976ca20499ee9dde6211fd 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.11 2006/08/03 03:34:41 deraadt Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.12 2008/07/17 08:51:07 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -151,15 +151,16 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
        debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
            chost, resolvedname, ipaddr);
 
+       if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
+               debug2("stripping trailing dot from chost %s", chost);
+               chost[len - 1] = '\0';
+       }
+
        if (options.hostbased_uses_name_from_packet_only) {
                if (auth_rhosts2(pw, cuser, chost, chost) == 0)
                        return 0;
                lookup = chost;
        } else {
-               if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
-                       debug2("stripping trailing dot from chost %s", chost);
-                       chost[len - 1] = '\0';
-               }
                if (strcasecmp(resolvedname, chost) != 0)
                        logit("userauth_hostbased mismatch: "
                            "client sends %s, but we resolve %s to %s",
index 28e593e6c9bdc7728a7be4b68689bb3b7def9c08..10accfe552dfb0657c5eeca5676d18097e0c07af 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-none.c,v 1.14 2007/08/23 03:22:16 djm Exp $ */
+/* $OpenBSD: auth2-none.c,v 1.15 2008/07/02 12:36:39 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
 
 #include <fcntl.h>
 #include <stdarg.h>
-#include <unistd.h>
 #include <string.h>
+#include <unistd.h>
 
+#include "atomicio.h"
 #include "xmalloc.h"
 #include "key.h"
 #include "hostfile.h"
@@ -42,7 +43,6 @@
 #include "log.h"
 #include "buffer.h"
 #include "servconf.h"
-#include "atomicio.h"
 #include "compat.h"
 #include "ssh2.h"
 #ifdef GSSAPI
@@ -56,77 +56,11 @@ extern ServerOptions options;
 /* "none" is allowed only one time */
 static int none_enabled = 1;
 
-char *
-auth2_read_banner(void)
-{
-       struct stat st;
-       char *banner = NULL;
-       size_t len, n;
-       int fd;
-
-       if ((fd = open(options.banner, O_RDONLY)) == -1)
-               return (NULL);
-       if (fstat(fd, &st) == -1) {
-               close(fd);
-               return (NULL);
-       }
-       if (st.st_size > 1*1024*1024) {
-               close(fd);
-               return (NULL);
-       }
-
-       len = (size_t)st.st_size;               /* truncate */
-       banner = xmalloc(len + 1);
-       n = atomicio(read, fd, banner, len);
-       close(fd);
-
-       if (n != len) {
-               xfree(banner);
-               return (NULL);
-       }
-       banner[n] = '\0';
-
-       return (banner);
-}
-
-void
-userauth_send_banner(const char *msg)
-{
-       if (datafellows & SSH_BUG_BANNER)
-               return;
-
-       packet_start(SSH2_MSG_USERAUTH_BANNER);
-       packet_put_cstring(msg);
-       packet_put_cstring("");         /* language, unused */
-       packet_send();
-       debug("%s: sent", __func__);
-}
-
-static void
-userauth_banner(void)
-{
-       char *banner = NULL;
-
-       if (options.banner == NULL ||
-           strcasecmp(options.banner, "none") == 0 ||
-           (datafellows & SSH_BUG_BANNER) != 0)
-               return;
-
-       if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
-               goto done;
-       userauth_send_banner(banner);
-
-done:
-       if (banner)
-               xfree(banner);
-}
-
 static int
 userauth_none(Authctxt *authctxt)
 {
        none_enabled = 0;
        packet_check_eom();
-       userauth_banner();
 #ifdef HAVE_CYGWIN
        if (check_nt_auth(1, authctxt->pw) == 0)
                return (0);
index 9863cd9e6e544aaca327495230fad44d5a18ede2..b1e38e5f586d25c59847b1ea5ed6f311a0129b35 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.15 2006/08/03 03:34:41 deraadt Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.19 2008/07/03 21:46:58 otto Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include <fcntl.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <unistd.h>
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -183,7 +185,6 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
        int found_key = 0;
        FILE *f;
        u_long linenum = 0;
-       struct stat st;
        Key *found;
        char *fp;
 
@@ -191,24 +192,9 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
        temporarily_use_uid(pw);
 
        debug("trying public key file %s", file);
+       f = auth_openkeyfile(file, pw, options.strict_modes);
 
-       /* Fail quietly if file does not exist */
-       if (stat(file, &st) < 0) {
-               /* Restore the privileged uid. */
-               restore_uid();
-               return 0;
-       }
-       /* Open the file containing the authorized keys. */
-       f = fopen(file, "r");
        if (!f) {
-               /* Restore the privileged uid. */
-               restore_uid();
-               return 0;
-       }
-       if (options.strict_modes &&
-           secure_filename(f, file, pw, line, sizeof(line)) != 0) {
-               fclose(f);
-               logit("Authentication refused: %s", line);
                restore_uid();
                return 0;
        }
index 03d7f09dc680c8720803190479300a29aacf67d3..a835abfc6c3366241e9b94fa29ada5abd22e34b5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.116 2007/09/29 00:25:51 dtucker Exp $ */
+/* $OpenBSD: auth2.c,v 1.119 2008/07/04 23:30:16 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
 #include "includes.h"
 
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
 
+#include <fcntl.h>
 #include <pwd.h>
 #include <stdarg.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "xmalloc.h"
+#include "atomicio.h"
 #include "ssh2.h"
 #include "packet.h"
 #include "log.h"
@@ -88,10 +93,74 @@ static void input_userauth_request(int, u_int32_t, void *);
 static Authmethod *authmethod_lookup(const char *);
 static char *authmethods_get(void);
 
+char *
+auth2_read_banner(void)
+{
+       struct stat st;
+       char *banner = NULL;
+       size_t len, n;
+       int fd;
+
+       if ((fd = open(options.banner, O_RDONLY)) == -1)
+               return (NULL);
+       if (fstat(fd, &st) == -1) {
+               close(fd);
+               return (NULL);
+       }
+       if (st.st_size > 1*1024*1024) {
+               close(fd);
+               return (NULL);
+       }
+
+       len = (size_t)st.st_size;               /* truncate */
+       banner = xmalloc(len + 1);
+       n = atomicio(read, fd, banner, len);
+       close(fd);
+
+       if (n != len) {
+               xfree(banner);
+               return (NULL);
+       }
+       banner[n] = '\0';
+
+       return (banner);
+}
+
+void
+userauth_send_banner(const char *msg)
+{
+       if (datafellows & SSH_BUG_BANNER)
+               return;
+
+       packet_start(SSH2_MSG_USERAUTH_BANNER);
+       packet_put_cstring(msg);
+       packet_put_cstring("");         /* language, unused */
+       packet_send();
+       debug("%s: sent", __func__);
+}
+
+static void
+userauth_banner(void)
+{
+       char *banner = NULL;
+
+       if (options.banner == NULL ||
+           strcasecmp(options.banner, "none") == 0 ||
+           (datafellows & SSH_BUG_BANNER) != 0)
+               return;
+
+       if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
+               goto done;
+       userauth_send_banner(banner);
+
+done:
+       if (banner)
+               xfree(banner);
+}
+
 /*
  * loop until authctxt->success == TRUE
  */
-
 void
 do_authentication2(Authctxt *authctxt)
 {
@@ -179,6 +248,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                authctxt->style = style ? xstrdup(style) : NULL;
                if (use_privsep)
                        mm_inform_authserv(service, style);
+               userauth_banner();
        } else if (strcmp(user, authctxt->user) != 0 ||
            strcmp(service, authctxt->service) != 0) {
                packet_disconnect("Change of username or service not allowed: "
@@ -197,7 +267,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
 
        /* try to authenticate user */
        m = authmethod_lookup(method);
-       if (m != NULL) {
+       if (m != NULL && authctxt->failures < options.max_authtries) {
                debug2("input_userauth_request: try method %s", method);
                authenticated = m->userauth(authctxt);
        }
@@ -264,7 +334,11 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
                /* now we can break out */
                authctxt->success = 1;
        } else {
-               if (authctxt->failures++ > options.max_authtries) {
+
+               /* Allow initial try of "none" auth without failure penalty */
+               if (authctxt->attempt > 1 || strcmp(method, "none") != 0)
+                       authctxt->failures++;
+               if (authctxt->failures >= options.max_authtries) {
 #ifdef SSH_AUDIT_EVENTS
                        PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
 #endif
@@ -320,3 +394,4 @@ authmethod_lookup(const char *name)
            name ? name : "NULL");
        return NULL;
 }
+
index cbdc22c64288d4c1fe24fc972490b2a4620bda62..cd9a35dedc5ebe0a040b070675da6c698447922d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: bufaux.c,v 1.44 2006/08/03 03:34:41 deraadt Exp $ */
+/* $OpenBSD: bufaux.c,v 1.46 2008/06/10 23:21:34 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -180,7 +180,7 @@ buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
                return (NULL);
        }
        /* Append a null character to make processing easier. */
-       value[len] = 0;
+       value[len] = '\0';
        /* Optionally return the length of the string. */
        if (length_ptr)
                *length_ptr = len;
@@ -197,6 +197,22 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr)
        return (ret);
 }
 
+void *
+buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
+{
+       void *ptr;
+       u_int len;
+
+       len = buffer_get_int(buffer);
+       if (len > 256 * 1024)
+               fatal("buffer_get_string_ptr: bad string length %u", len);
+       ptr = buffer_ptr(buffer);
+       buffer_consume(buffer, len);
+       if (length_ptr)
+               *length_ptr = len;
+       return (ptr);
+}
+
 /*
  * Stores and arbitrary binary string in the buffer.
  */
index ecc4aea83193405b762397c6d47918e2369eb5ae..d0f354ee7bf7e685a51f6edf44b60aef603e5837 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: buffer.h,v 1.16 2006/08/03 03:34:41 deraadt Exp $ */
+/* $OpenBSD: buffer.h,v 1.17 2008/05/08 06:59:01 markus Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -66,6 +66,7 @@ int     buffer_get_char(Buffer *);
 void    buffer_put_char(Buffer *, int);
 
 void   *buffer_get_string(Buffer *, u_int *);
+void   *buffer_get_string_ptr(Buffer *, u_int *);
 void    buffer_put_string(Buffer *, const void *, u_int);
 void   buffer_put_cstring(Buffer *, const char *);
 
index 8270500d39e55c2b38ebeaf80459ee1141b06247..42011fd0acf2996fe09c10b077444fbfe1aae68f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: canohost.c,v 1.62 2007/12/27 14:22:08 dtucker Exp $ */
+/* $OpenBSD: canohost.c,v 1.63 2008/06/12 00:03:49 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -89,7 +89,7 @@ get_remote_hostname(int sock, int use_dns)
        memset(&hints, 0, sizeof(hints));
        hints.ai_socktype = SOCK_DGRAM; /*dummy*/
        hints.ai_flags = AI_NUMERICHOST;
-       if (getaddrinfo(name, "0", &hints, &ai) == 0) {
+       if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
                logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
                    name, ntop);
                freeaddrinfo(ai);
index b6bd901f053d24a5d3bd45527c449494e065d3a2..69c99c9b2f773d05f5c29c1ff754879598899c67 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.273 2008/04/02 21:36:51 markus Exp $ */
+/* $OpenBSD: channels.c,v 1.286 2008/07/16 11:52:19 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -61,6 +61,7 @@
 #include <unistd.h>
 #include <stdarg.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
@@ -164,6 +165,10 @@ static int IPv4or6 = AF_UNSPEC;
 /* helper */
 static void port_open_helper(Channel *c, char *rtype);
 
+/* non-blocking connect helpers */
+static int connect_next(struct channel_connect *);
+static void channel_connect_ctx_free(struct channel_connect *);
+
 /* -- channel core */
 
 Channel *
@@ -216,7 +221,7 @@ channel_lookup(int id)
  */
 static void
 channel_register_fds(Channel *c, int rfd, int wfd, int efd,
-    int extusage, int nonblock)
+    int extusage, int nonblock, int is_tty)
 {
        /* Update the maximum file descriptor value. */
        channel_max_fd = MAX(channel_max_fd, rfd);
@@ -232,18 +237,9 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
        c->efd = efd;
        c->extended_usage = extusage;
 
-       /* XXX ugly hack: nonblock is only set by the server */
-       if (nonblock && isatty(c->rfd)) {
+       if ((c->isatty = is_tty) != 0)
                debug2("channel %d: rfd %d isatty", c->self, c->rfd);
-               c->isatty = 1;
-               if (!isatty(c->wfd)) {
-                       error("channel %d: wfd %d is not a tty?",
-                           c->self, c->wfd);
-               }
-       } else {
-               c->isatty = 0;
-       }
-       c->wfd_isatty = isatty(c->wfd);
+       c->wfd_isatty = is_tty || isatty(c->wfd);
 
        /* enable nonblocking mode */
        if (nonblock) {
@@ -303,7 +299,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
        c->ostate = CHAN_OUTPUT_OPEN;
        c->istate = CHAN_INPUT_OPEN;
        c->flags = 0;
-       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
+       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
        c->self = found;
        c->type = type;
        c->ctype = ctype;
@@ -319,10 +315,13 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
        c->single_connection = 0;
        c->detach_user = NULL;
        c->detach_close = 0;
-       c->confirm = NULL;
-       c->confirm_ctx = NULL;
+       c->open_confirm = NULL;
+       c->open_confirm_ctx = NULL;
        c->input_filter = NULL;
        c->output_filter = NULL;
+       c->filter_ctx = NULL;
+       c->filter_cleanup = NULL;
+       TAILQ_INIT(&c->status_confirms);
        debug("channel %d: new [%s]", found, remote_name);
        return c;
 }
@@ -379,6 +378,7 @@ channel_free(Channel *c)
 {
        char *s;
        u_int i, n;
+       struct channel_confirm *cc;
 
        for (n = 0, i = 0; i < channels_alloc; i++)
                if (channels[i])
@@ -402,6 +402,15 @@ channel_free(Channel *c)
                xfree(c->remote_name);
                c->remote_name = NULL;
        }
+       while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
+               if (cc->abandon_cb != NULL)
+                       cc->abandon_cb(c, cc->ctx);
+               TAILQ_REMOVE(&c->status_confirms, cc, entry);
+               bzero(cc, sizeof(*cc));
+               xfree(cc);
+       }
+       if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
+               c->filter_cleanup(c->self, c->filter_ctx);
        channels[c->self] = NULL;
        xfree(c);
 }
@@ -660,16 +669,33 @@ channel_request_start(int id, char *service, int wantconfirm)
 }
 
 void
-channel_register_confirm(int id, channel_callback_fn *fn, void *ctx)
+channel_register_status_confirm(int id, channel_confirm_cb *cb,
+    channel_confirm_abandon_cb *abandon_cb, void *ctx)
+{
+       struct channel_confirm *cc;
+       Channel *c;
+
+       if ((c = channel_lookup(id)) == NULL)
+               fatal("channel_register_expect: %d: bad id", id);
+
+       cc = xmalloc(sizeof(*cc));
+       cc->cb = cb;
+       cc->abandon_cb = abandon_cb;
+       cc->ctx = ctx;
+       TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry);
+}
+
+void
+channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx)
 {
        Channel *c = channel_lookup(id);
 
        if (c == NULL) {
-               logit("channel_register_comfirm: %d: bad id", id);
+               logit("channel_register_open_comfirm: %d: bad id", id);
                return;
        }
-       c->confirm = fn;
-       c->confirm_ctx = ctx;
+       c->open_confirm = fn;
+       c->open_confirm_ctx = ctx;
 }
 
 void
@@ -700,7 +726,7 @@ channel_cancel_cleanup(int id)
 
 void
 channel_register_filter(int id, channel_infilter_fn *ifn,
-    channel_outfilter_fn *ofn)
+    channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
 {
        Channel *c = channel_lookup(id);
 
@@ -710,17 +736,19 @@ channel_register_filter(int id, channel_infilter_fn *ifn,
        }
        c->input_filter = ifn;
        c->output_filter = ofn;
+       c->filter_ctx = ctx;
+       c->filter_cleanup = cfn;
 }
 
 void
 channel_set_fds(int id, int rfd, int wfd, int efd,
-    int extusage, int nonblock, u_int window_max)
+    int extusage, int nonblock, int is_tty, u_int window_max)
 {
        Channel *c = channel_lookup(id);
 
        if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
                fatal("channel_activate for non-larval channel %d.", id);
-       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock);
+       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
        c->type = SSH_CHANNEL_OPEN;
        c->local_window = c->local_window_max = window_max;
        packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
@@ -788,7 +816,8 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
                }
        }
        /** XXX check close conditions, too */
-       if (compat20 && c->efd != -1) {
+       if (compat20 && c->efd != -1 && 
+           !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
                if (c->extended_usage == CHAN_EXTENDED_WRITE &&
                    buffer_len(&c->extended) > 0)
                        FD_SET(c->efd, writeset);
@@ -1181,7 +1210,7 @@ static void
 channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {
        Channel *nc;
-       struct sockaddr addr;
+       struct sockaddr_storage addr;
        int newsock;
        socklen_t addrlen;
        char buf[16384], *remote_ipaddr;
@@ -1190,7 +1219,7 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
        if (FD_ISSET(c->sock, readset)) {
                debug("X11 connection requested.");
                addrlen = sizeof(addr);
-               newsock = accept(c->sock, &addr, &addrlen);
+               newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
                if (c->single_connection) {
                        debug2("single_connection: closing X11 listener.");
                        channel_close_fd(&c->sock);
@@ -1307,7 +1336,7 @@ static void
 channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {
        Channel *nc;
-       struct sockaddr addr;
+       struct sockaddr_storage addr;
        int newsock, nextstate;
        socklen_t addrlen;
        char *rtype;
@@ -1331,7 +1360,7 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
                }
 
                addrlen = sizeof(addr);
-               newsock = accept(c->sock, &addr, &addrlen);
+               newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
                if (newsock < 0) {
                        error("accept: %.100s", strerror(errno));
                        return;
@@ -1366,12 +1395,12 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {
        Channel *nc;
        int newsock;
-       struct sockaddr addr;
+       struct sockaddr_storage addr;
        socklen_t addrlen;
 
        if (FD_ISSET(c->sock, readset)) {
                addrlen = sizeof(addr);
-               newsock = accept(c->sock, &addr, &addrlen);
+               newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
                if (newsock < 0) {
                        error("accept from auth socket: %.100s", strerror(errno));
                        return;
@@ -1398,7 +1427,7 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
 static void
 channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
 {
-       int err = 0;
+       int err = 0, sock;
        socklen_t sz = sizeof(err);
 
        if (FD_ISSET(c->sock, writeset)) {
@@ -1407,7 +1436,9 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
                        error("getsockopt SO_ERROR failed");
                }
                if (err == 0) {
-                       debug("channel %d: connected", c->self);
+                       debug("channel %d: connected to %s port %d",
+                           c->self, c->connect_ctx.host, c->connect_ctx.port);
+                       channel_connect_ctx_free(&c->connect_ctx);
                        c->type = SSH_CHANNEL_OPEN;
                        if (compat20) {
                                packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
@@ -1421,8 +1452,19 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
                                packet_put_int(c->self);
                        }
                } else {
-                       debug("channel %d: not connected: %s",
+                       debug("channel %d: connection failed: %s",
                            c->self, strerror(err));
+                       /* Try next address, if any */
+                       if ((sock = connect_next(&c->connect_ctx)) > 0) {
+                               close(c->sock);
+                               c->sock = c->rfd = c->wfd = sock;
+                               channel_max_fd = channel_find_maxfd();
+                               return;
+                       }
+                       /* Exhausted all addresses */
+                       error("connect_to %.100s port %d: failed.",
+                           c->connect_ctx.host, c->connect_ctx.port);
+                       channel_connect_ctx_free(&c->connect_ctx);
                        if (compat20) {
                                packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
                                packet_put_int(c->remote_id);
@@ -1452,7 +1494,8 @@ channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
        if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
                errno = 0;
                len = read(c->rfd, buf, sizeof(buf));
-               if (len < 0 && (errno == EINTR || (errno == EAGAIN && !force)))
+               if (len < 0 && (errno == EINTR ||
+                   ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
                        return 1;
 #ifndef PTY_ZEROREAD
                if (len <= 0) {
@@ -1523,7 +1566,8 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
                        c->local_consumed += dlen + 4;
                        len = write(c->wfd, buf, dlen);
                        xfree(data);
-                       if (len < 0 && (errno == EINTR || errno == EAGAIN))
+                       if (len < 0 && (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK))
                                return 1;
                        if (len <= 0) {
                                if (c->type != SSH_CHANNEL_OPEN)
@@ -1541,7 +1585,8 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
 #endif
 
                len = write(c->wfd, buf, dlen);
-               if (len < 0 && (errno == EINTR || errno == EAGAIN))
+               if (len < 0 &&
+                   (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
                        return 1;
                if (len <= 0) {
                        if (c->type != SSH_CHANNEL_OPEN) {
@@ -1593,7 +1638,8 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
                            buffer_len(&c->extended));
                        debug2("channel %d: written %d to efd %d",
                            c->self, len, c->efd);
-                       if (len < 0 && (errno == EINTR || errno == EAGAIN))
+                       if (len < 0 && (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK))
                                return 1;
                        if (len <= 0) {
                                debug2("channel %d: closing write-efd %d",
@@ -1608,8 +1654,8 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
                        len = read(c->efd, buf, sizeof(buf));
                        debug2("channel %d: read %d from efd %d",
                            c->self, len, c->efd);
-                       if (len < 0 && (errno == EINTR ||
-                           (errno == EAGAIN && !c->detach_close)))
+                       if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+                           errno == EWOULDBLOCK) && !c->detach_close)))
                                return 1;
                        if (len <= 0) {
                                debug2("channel %d: closing read-efd %d",
@@ -1633,7 +1679,8 @@ channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset)
        /* Monitor control fd to detect if the slave client exits */
        if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) {
                len = read(c->ctl_fd, buf, sizeof(buf));
-               if (len < 0 && (errno == EINTR || errno == EAGAIN))
+               if (len < 0 &&
+                   (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
                        return 1;
                if (len <= 0) {
                        debug2("channel %d: ctl read<=0", c->self);
@@ -2012,7 +2059,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
                return;
 
        /* Get the data. */
-       data = packet_get_string(&data_len);
+       data = packet_get_string_ptr(&data_len);
 
        /*
         * Ignore data for protocol > 1.3 if output end is no longer open.
@@ -2026,7 +2073,6 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
                        c->local_window -= data_len;
                        c->local_consumed += data_len;
                }
-               xfree(data);
                return;
        }
 
@@ -2038,17 +2084,15 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
                if (data_len > c->local_window) {
                        logit("channel %d: rcvd too much data %d, win %d",
                            c->self, data_len, c->local_window);
-                       xfree(data);
                        return;
                }
                c->local_window -= data_len;
        }
-       packet_check_eom();
        if (c->datagram)
                buffer_put_string(&c->output, data, data_len);
        else
                buffer_append(&c->output, data, data_len);
-       xfree(data);
+       packet_check_eom();
 }
 
 /* ARGSUSED */
@@ -2212,9 +2256,9 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
        if (compat20) {
                c->remote_window = packet_get_int();
                c->remote_maxpacket = packet_get_int();
-               if (c->confirm) {
+               if (c->open_confirm) {
                        debug2("callback start");
-                       c->confirm(c->self, c->confirm_ctx);
+                       c->open_confirm(c->self, c->open_confirm_ctx);
                        debug2("callback done");
                }
                debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
@@ -2303,7 +2347,7 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
        Channel *c = NULL;
        u_short host_port;
        char *host, *originator_string;
-       int remote_id, sock = -1;
+       int remote_id;
 
        remote_id = packet_get_int();
        host = packet_get_string(NULL);
@@ -2315,22 +2359,46 @@ channel_input_port_open(int type, u_int32_t seq, void *ctxt)
                originator_string = xstrdup("unknown (remote did not supply name)");
        }
        packet_check_eom();
-       sock = channel_connect_to(host, host_port);
-       if (sock != -1) {
-               c = channel_new("connected socket",
-                   SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0,
-                   originator_string, 1);
-               c->remote_id = remote_id;
-       }
+       c = channel_connect_to(host, host_port,
+           "connected socket", originator_string);
        xfree(originator_string);
+       xfree(host);
        if (c == NULL) {
                packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
                packet_put_int(remote_id);
                packet_send();
-       }
-       xfree(host);
+       } else
+               c->remote_id = remote_id;
 }
 
+/* ARGSUSED */
+void
+channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c;
+       struct channel_confirm *cc;
+       int remote_id;
+
+       /* Reset keepalive timeout */
+       keep_alive_timeouts = 0;
+
+       remote_id = packet_get_int();
+       packet_check_eom();
+
+       debug2("channel_input_confirm: type %d id %d", type, remote_id);
+
+       if ((c = channel_lookup(remote_id)) == NULL) {
+               logit("channel_input_success_failure: %d: unknown", remote_id);
+               return;
+       }       
+       ;
+       if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
+               return;
+       cc->cb(type, c, cc->ctx);
+       TAILQ_REMOVE(&c->status_confirms, cc, entry);
+       bzero(cc, sizeof(*cc));
+       xfree(cc);
+}
 
 /* -- tcp forwarding */
 
@@ -2718,35 +2786,37 @@ channel_clear_adm_permitted_opens(void)
        num_adm_permitted_opens = 0;
 }
 
-/* return socket to remote host, port */
+void
+channel_print_adm_permitted_opens(void)
+{
+       int i;
+
+       for (i = 0; i < num_adm_permitted_opens; i++)
+               if (permitted_adm_opens[i].host_to_connect != NULL)
+                       printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
+                           permitted_adm_opens[i].port_to_connect);
+}
+
+/* Try to start non-blocking connect to next host in cctx list */
 static int
-connect_to(const char *host, u_short port)
+connect_next(struct channel_connect *cctx)
 {
-       struct addrinfo hints, *ai, *aitop;
+       int sock, saved_errno;
        char ntop[NI_MAXHOST], strport[NI_MAXSERV];
-       int gaierr;
-       int sock = -1;
 
-       memset(&hints, 0, sizeof(hints));
-       hints.ai_family = IPv4or6;
-       hints.ai_socktype = SOCK_STREAM;
-       snprintf(strport, sizeof strport, "%d", port);
-       if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
-               error("connect_to %.100s: unknown host (%s)", host,
-                   ssh_gai_strerror(gaierr));
-               return -1;
-       }
-       for (ai = aitop; ai; ai = ai->ai_next) {
-               if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+       for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
+               if (cctx->ai->ai_family != AF_INET &&
+                   cctx->ai->ai_family != AF_INET6)
                        continue;
-               if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
-                   strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
-                       error("connect_to: getnameinfo failed");
+               if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
+                   ntop, sizeof(ntop), strport, sizeof(strport),
+                   NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                       error("connect_next: getnameinfo failed");
                        continue;
                }
-               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-               if (sock < 0) {
-                       if (ai->ai_next == NULL)
+               if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
+                   cctx->ai->ai_protocol)) == -1) {
+                       if (cctx->ai->ai_next == NULL)
                                error("socket: %.100s", strerror(errno));
                        else
                                verbose("socket: %.100s", strerror(errno));
@@ -2754,45 +2824,95 @@ connect_to(const char *host, u_short port)
                }
                if (set_nonblock(sock) == -1)
                        fatal("%s: set_nonblock(%d)", __func__, sock);
-               if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 &&
-                   errno != EINPROGRESS) {
-                       error("connect_to %.100s port %s: %.100s", ntop, strport,
+               if (connect(sock, cctx->ai->ai_addr,
+                   cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
+                       debug("connect_next: host %.100s ([%.100s]:%s): "
+                           "%.100s", cctx->host, ntop, strport,
                            strerror(errno));
+                       saved_errno = errno;
                        close(sock);
+                       errno = saved_errno;
                        continue;       /* fail -- try next */
                }
-               break; /* success */
+               debug("connect_next: host %.100s ([%.100s]:%s) "
+                   "in progress, fd=%d", cctx->host, ntop, strport, sock);
+               cctx->ai = cctx->ai->ai_next;
+               set_nodelay(sock);
+               return sock;
+       }
+       return -1;
+}
+
+static void
+channel_connect_ctx_free(struct channel_connect *cctx)
+{
+       xfree(cctx->host);
+       if (cctx->aitop)
+               freeaddrinfo(cctx->aitop);
+       bzero(cctx, sizeof(*cctx));
+       cctx->host = NULL;
+       cctx->ai = cctx->aitop = NULL;
+}
+
+/* Return CONNECTING channel to remote host, port */
+static Channel *
+connect_to(const char *host, u_short port, char *ctype, char *rname)
+{
+       struct addrinfo hints;
+       int gaierr;
+       int sock = -1;
+       char strport[NI_MAXSERV];
+       struct channel_connect cctx;
+       Channel *c;
 
+       memset(&cctx, 0, sizeof(cctx));
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = IPv4or6;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%d", port);
+       if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) {
+               error("connect_to %.100s: unknown host (%s)", host,
+                   ssh_gai_strerror(gaierr));
+               return NULL;
        }
-       freeaddrinfo(aitop);
-       if (!ai) {
-               error("connect_to %.100s port %d: failed.", host, port);
-               return -1;
+
+       cctx.host = xstrdup(host);
+       cctx.port = port;
+       cctx.ai = cctx.aitop;
+
+       if ((sock = connect_next(&cctx)) == -1) {
+               error("connect to %.100s port %d failed: %s",
+                   host, port, strerror(errno));
+               channel_connect_ctx_free(&cctx);
+               return NULL;
        }
-       /* success */
-       set_nodelay(sock);
-       return sock;
+       c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
+       c->connect_ctx = cctx;
+       return c;
 }
 
-int
-channel_connect_by_listen_address(u_short listen_port)
+Channel *
+channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
 {
        int i;
 
-       for (i = 0; i < num_permitted_opens; i++)
+       for (i = 0; i < num_permitted_opens; i++) {
                if (permitted_opens[i].host_to_connect != NULL &&
-                   permitted_opens[i].listen_port == listen_port)
+                   permitted_opens[i].listen_port == listen_port) {
                        return connect_to(
                            permitted_opens[i].host_to_connect,
-                           permitted_opens[i].port_to_connect);
+                           permitted_opens[i].port_to_connect, ctype, rname);
+               }
+       }
        error("WARNING: Server requests forwarding for unknown listen_port %d",
            listen_port);
-       return -1;
+       return NULL;
 }
 
 /* Check if connecting to that port is permitted and connect. */
-int
-channel_connect_to(const char *host, u_short port)
+Channel *
+channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
 {
        int i, permit, permit_adm = 1;
 
@@ -2818,9 +2938,9 @@ channel_connect_to(const char *host, u_short port)
        if (!permit || !permit_adm) {
                logit("Received request to connect to host %.100s port %d, "
                    "but the request was denied.", host, port);
-               return -1;
+               return NULL;
        }
-       return connect_to(host, port);
+       return connect_to(host, port, ctype, rname);
 }
 
 void
@@ -2901,7 +3021,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
                                        error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
                        }
 #endif
-                       channel_set_reuseaddr(sock);
+                       if (x11_use_localhost)
+                               channel_set_reuseaddr(sock);
                        if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
                                debug2("bind port %d: %.100s", port, strerror(errno));
                                close(sock);
@@ -2913,17 +3034,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
                                break;
                        }
                        socks[num_socks++] = sock;
-#ifndef DONT_TRY_OTHER_AF
                        if (num_socks == NUM_SOCKS)
                                break;
-#else
-                       if (x11_use_localhost) {
-                               if (num_socks == NUM_SOCKS)
-                                       break;
-                       } else {
-                               break;
-                       }
-#endif
                }
                freeaddrinfo(aitop);
                if (num_socks > 0)
index b632a86af3682abfb9b9848f390df4a00e95739e..108b360681d678557e56660bd5902b6ff683b34e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.89 2007/06/11 09:14:00 markus Exp $ */
+/* $OpenBSD: channels.h,v 1.96 2008/06/15 20:06:26 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -62,8 +62,27 @@ typedef struct Channel Channel;
 
 typedef void channel_callback_fn(int, void *);
 typedef int channel_infilter_fn(struct Channel *, char *, int);
+typedef void channel_filter_cleanup_fn(int, void *);
 typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *);
 
+/* Channel success/failure callbacks */
+typedef void channel_confirm_cb(int, struct Channel *, void *);
+typedef void channel_confirm_abandon_cb(struct Channel *, void *);
+struct channel_confirm {
+       TAILQ_ENTRY(channel_confirm) entry;
+       channel_confirm_cb *cb;
+       channel_confirm_abandon_cb *abandon_cb;
+       void *ctx;
+};
+TAILQ_HEAD(channel_confirms, channel_confirm);
+
+/* Context for non-blocking connects */
+struct channel_connect {
+       char *host;
+       int port;
+       struct addrinfo *ai, *aitop;
+};
+
 struct Channel {
        int     type;           /* channel type/state */
        int     self;           /* my own channel identifier */
@@ -104,16 +123,23 @@ struct Channel {
        char   *ctype;          /* type */
 
        /* callback */
-       channel_callback_fn     *confirm;
-       void                    *confirm_ctx;
+       channel_callback_fn     *open_confirm;
+       void                    *open_confirm_ctx;
        channel_callback_fn     *detach_user;
        int                     detach_close;
+       struct channel_confirms status_confirms;
 
        /* filter */
        channel_infilter_fn     *input_filter;
        channel_outfilter_fn    *output_filter;
+       void                    *filter_ctx;
+       channel_filter_cleanup_fn *filter_cleanup;
+
+       /* keep boundaries */
+       int                     datagram;
 
-       int     datagram;       /* keep boundaries */
+       /* non-blocking connect */
+       struct channel_connect  connect_ctx;
 };
 
 #define CHAN_EXTENDED_IGNORE           0
@@ -162,7 +188,7 @@ struct Channel {
 Channel        *channel_by_id(int);
 Channel        *channel_lookup(int);
 Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int);
-void    channel_set_fds(int, int, int, int, int, int, u_int);
+void    channel_set_fds(int, int, int, int, int, int, int, u_int);
 void    channel_free(Channel *);
 void    channel_free_all(void);
 void    channel_stop_listening(void);
@@ -170,8 +196,11 @@ void        channel_stop_listening(void);
 void    channel_send_open(int);
 void    channel_request_start(int, char *, int);
 void    channel_register_cleanup(int, channel_callback_fn *, int);
-void    channel_register_confirm(int, channel_callback_fn *, void *);
-void    channel_register_filter(int, channel_infilter_fn *, channel_outfilter_fn *);
+void    channel_register_open_confirm(int, channel_callback_fn *, void *);
+void    channel_register_filter(int, channel_infilter_fn *,
+    channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
+void    channel_register_status_confirm(int, channel_confirm_cb *,
+    channel_confirm_abandon_cb *, void *);
 void    channel_cancel_cleanup(int);
 int     channel_close_fd(int *);
 void    channel_send_window_changes(void);
@@ -188,6 +217,7 @@ void         channel_input_open_confirmation(int, u_int32_t, void *);
 void    channel_input_open_failure(int, u_int32_t, void *);
 void    channel_input_port_open(int, u_int32_t, void *);
 void    channel_input_window_adjust(int, u_int32_t, void *);
+void    channel_input_status_confirm(int, u_int32_t, void *);
 
 /* file descriptor handling (read/write) */
 
@@ -208,9 +238,10 @@ void        channel_add_permitted_opens(char *, int);
 int     channel_add_adm_permitted_opens(char *, int);
 void    channel_clear_permitted_opens(void);
 void    channel_clear_adm_permitted_opens(void);
+void    channel_print_adm_permitted_opens(void);
 int      channel_input_port_forward_request(int, int);
-int     channel_connect_to(const char *, u_short);
-int     channel_connect_by_listen_address(u_short);
+Channel        *channel_connect_to(const char *, u_short, char *, char *);
+Channel        *channel_connect_by_listen_address(u_short, char *, char *);
 int     channel_request_remote_forwarding(const char *, u_short,
             const char *, u_short);
 int     channel_setup_local_fwd_listener(const char *, u_short,
@@ -225,7 +256,7 @@ int  x11_connect_display(void);
 int     x11_create_display_inet(int, int, int, u_int *, int **);
 void     x11_input_open(int, u_int32_t, void *);
 void    x11_request_forwarding_with_spoofing(int, const char *, const char *,
-           const char *);
+            const char *);
 void    deny_input_open(int, u_int32_t, void *);
 
 /* agent forwarding */
@@ -240,6 +271,7 @@ void         chan_mark_dead(Channel *);
 /* channel events */
 
 void    chan_rcvd_oclose(Channel *);
+void    chan_rcvd_eow(Channel *);      /* SSH2-only */
 void    chan_read_failed(Channel *);
 void    chan_ibuf_empty(Channel *);
 
index 8a40bc71e0ed9828429d322e4c15c3f0297e559e..f10fab7698cf6b1f4e1dbe90b25d483892c2a578 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.188 2008/02/22 20:44:02 dtucker Exp $ */
+/* $OpenBSD: clientloop.c,v 1.201 2008/07/16 11:51:14 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -86,6 +86,7 @@
 #include <pwd.h>
 #include <unistd.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
@@ -120,7 +121,7 @@ extern int stdin_null_flag;
 extern int no_shell_flag;
 
 /* Control socket */
-extern int control_fd;
+extern int muxserver_sock;
 
 /*
  * Name of the host we are connecting to.  This is the name given on the
@@ -143,15 +144,14 @@ static int in_non_blocking_mode = 0;
 
 /* Common data for the client loop code. */
 static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
-static int escape_char;                /* Escape character. */
-static int escape_pending;     /* Last character was the escape character */
+static int escape_char1;       /* Escape character. (proto1 only) */
+static int escape_pending1;    /* Last character was an escape (proto1 only) */
 static int last_was_cr;                /* Last character was a newline. */
-static int exit_status;                /* Used to store the exit status of the command. */
-static int stdin_eof;          /* EOF has been encountered on standard error. */
+static int exit_status;                /* Used to store the command exit status. */
+static int stdin_eof;          /* EOF has been encountered on stderr. */
 static Buffer stdin_buffer;    /* Buffer for stdin data. */
 static Buffer stdout_buffer;   /* Buffer for stdout data. */
 static Buffer stderr_buffer;   /* Buffer for stderr data. */
-static u_long stdin_bytes, stdout_bytes, stderr_bytes;
 static u_int buffer_high;/* Soft max buffer size. */
 static int connection_in;      /* Connection to server (input). */
 static int connection_out;     /* Connection to server (output). */
@@ -161,17 +161,29 @@ static int session_closed = 0;    /* In SSH2: login session closed. */
 static void client_init_dispatch(void);
 int    session_ident = -1;
 
-struct confirm_ctx {
-       int want_tty;
-       int want_subsys;
-       int want_x_fwd;
-       int want_agent_fwd;
-       Buffer cmd;
-       char *term;
-       struct termios tio;
-       char **env;
+/* Track escape per proto2 channel */
+struct escape_filter_ctx {
+       int escape_pending;
+       int escape_char;
 };
 
+/* Context for channel confirmation replies */
+struct channel_reply_ctx {
+       const char *request_type;
+       int id, do_close;
+};
+
+/* Global request success/failure callbacks */
+struct global_confirm {
+       TAILQ_ENTRY(global_confirm) entry;
+       global_confirm_cb *cb;
+       void *ctx;
+       int ref_count;
+};
+TAILQ_HEAD(global_confirms, global_confirm);
+static struct global_confirms global_confirms =
+    TAILQ_HEAD_INITIALIZER(global_confirms);
+
 /*XXX*/
 extern Kex *xxx_kex;
 
@@ -379,7 +391,10 @@ client_check_initial_eof_on_stdin(void)
                /* Check for immediate EOF on stdin. */
                len = read(fileno(stdin), buf, 1);
                if (len == 0) {
-                       /* EOF.  Record that we have seen it and send EOF to server. */
+                       /*
+                        * EOF.  Record that we have seen it and send
+                        * EOF to server.
+                        */
                        debug("Sending eof.");
                        stdin_eof = 1;
                        packet_start(SSH_CMSG_EOF);
@@ -390,8 +405,8 @@ client_check_initial_eof_on_stdin(void)
                         * and also process it as an escape character if
                         * appropriate.
                         */
-                       if ((u_char) buf[0] == escape_char)
-                               escape_pending = 1;
+                       if ((u_char) buf[0] == escape_char1)
+                               escape_pending1 = 1;
                        else
                                buffer_append(&stdin_buffer, buf, 1);
                }
@@ -421,7 +436,6 @@ client_make_packets_from_stdin_data(void)
                packet_put_string(buffer_ptr(&stdin_buffer), len);
                packet_send();
                buffer_consume(&stdin_buffer, len);
-               stdin_bytes += len;
                /* If we have a pending EOF, send it now. */
                if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
                        packet_start(SSH_CMSG_EOF);
@@ -466,8 +480,19 @@ client_check_window_change(void)
 static void
 client_global_request_reply(int type, u_int32_t seq, void *ctxt)
 {
+       struct global_confirm *gc;
+
+       if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
+               return;
+       if (gc->cb != NULL)
+               gc->cb(type, seq, gc->ctx);
+       if (--gc->ref_count <= 0) {
+               TAILQ_REMOVE(&global_confirms, gc, entry);
+               bzero(gc, sizeof(*gc));
+               xfree(gc);
+       }
+
        keep_alive_timeouts = 0;
-       client_global_request_reply_fwd(type, seq, ctxt);
 }
 
 static void
@@ -481,6 +506,8 @@ server_alive_check(void)
        packet_put_cstring("keepalive@openssh.com");
        packet_put_char(1);     /* boolean: want reply */
        packet_send();
+       /* Insert an empty placeholder to maintain ordering */
+       client_register_global_confirm(NULL, NULL);
 }
 
 /*
@@ -532,8 +559,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
        if (packet_have_data_to_write())
                FD_SET(connection_out, *writesetp);
 
-       if (control_fd != -1)
-               FD_SET(control_fd, *readsetp);
+       if (muxserver_sock != -1)
+               FD_SET(muxserver_sock, *readsetp);
 
        /*
         * Wait for something to happen.  This will suspend the process until
@@ -575,9 +602,11 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
 {
        /* Flush stdout and stderr buffers. */
        if (buffer_len(bout) > 0)
-               atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout));
+               atomicio(vwrite, fileno(stdout), buffer_ptr(bout),
+                   buffer_len(bout));
        if (buffer_len(berr) > 0)
-               atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr));
+               atomicio(vwrite, fileno(stderr), buffer_ptr(berr),
+                   buffer_len(berr));
 
        leave_raw_mode();
 
@@ -617,9 +646,13 @@ client_process_net_input(fd_set *readset)
                /* Read as much as possible. */
                len = read(connection_in, buf, sizeof(buf));
                if (len == 0) {
-                       /* Received EOF.  The remote host has closed the connection. */
-                       snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n",
-                                host);
+                       /*
+                        * Received EOF.  The remote host has closed the
+                        * connection.
+                        */
+                       snprintf(buf, sizeof buf,
+                           "Connection to %.300s closed by remote host.\r\n",
+                           host);
                        buffer_append(&stderr_buffer, buf, strlen(buf));
                        quit_pending = 1;
                        return;
@@ -628,13 +661,18 @@ client_process_net_input(fd_set *readset)
                 * There is a kernel bug on Solaris that causes select to
                 * sometimes wake up even though there is no data available.
                 */
-               if (len < 0 && (errno == EAGAIN || errno == EINTR))
+               if (len < 0 &&
+                   (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
                        len = 0;
 
                if (len < 0) {
-                       /* An error has encountered.  Perhaps there is a network problem. */
-                       snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n",
-                                host, strerror(errno));
+                       /*
+                        * An error has encountered.  Perhaps there is a
+                        * network problem.
+                        */
+                       snprintf(buf, sizeof buf,
+                           "Read from remote host %.300s: %.100s\r\n",
+                           host, strerror(errno));
                        buffer_append(&stderr_buffer, buf, strlen(buf));
                        quit_pending = 1;
                        return;
@@ -644,303 +682,81 @@ client_process_net_input(fd_set *readset)
 }
 
 static void
-client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
+client_status_confirm(int type, Channel *c, void *ctx)
 {
-       int id;
-       Channel *c;
-
-       id = packet_get_int();
-       packet_check_eom();
-
-       if ((c = channel_lookup(id)) == NULL) {
-               error("%s: no channel for id %d", __func__, id);
-               return;
-       }
-
-       if (type == SSH2_MSG_CHANNEL_SUCCESS)
-               debug2("Request suceeded on channel %d", id);
-       else if (type == SSH2_MSG_CHANNEL_FAILURE) {
-               error("Request failed on channel %d", id);
-               channel_free(c);
+       struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx;
+       char errmsg[256];
+       int tochan;
+
+       /* XXX supress on mux _client_ quietmode */
+       tochan = options.log_level >= SYSLOG_LEVEL_ERROR &&
+           c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;
+
+       if (type == SSH2_MSG_CHANNEL_SUCCESS) {
+               debug2("%s request accepted on channel %d",
+                   cr->request_type, c->self);
+       } else if (type == SSH2_MSG_CHANNEL_FAILURE) {
+               if (tochan) {
+                       snprintf(errmsg, sizeof(errmsg),
+                           "%s request failed\r\n", cr->request_type);
+               } else {
+                       snprintf(errmsg, sizeof(errmsg),
+                           "%s request failed on channel %d",
+                           cr->request_type, c->self);
+               }
+               /* If error occurred on primary session channel, then exit */
+               if (cr->do_close && c->self == session_ident)
+                       fatal("%s", errmsg);
+               /* If error occurred on mux client, append to their stderr */
+               if (tochan)
+                       buffer_append(&c->extended, errmsg, strlen(errmsg));
+               else
+                       error("%s", errmsg);
+               if (cr->do_close) {
+                       chan_read_failed(c);
+                       chan_write_failed(c);
+               }
        }
+       xfree(cr);
 }
 
 static void
-client_extra_session2_setup(int id, void *arg)
+client_abandon_status_confirm(Channel *c, void *ctx)
 {
-       struct confirm_ctx *cctx = arg;
-       const char *display;
-       Channel *c;
-       int i;
-
-       if (cctx == NULL)
-               fatal("%s: cctx == NULL", __func__);
-       if ((c = channel_lookup(id)) == NULL)
-               fatal("%s: no channel for id %d", __func__, id);
-
-       display = getenv("DISPLAY");
-       if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
-               char *proto, *data;
-               /* Get reasonable local authentication information. */
-               client_x11_get_proto(display, options.xauth_location,
-                   options.forward_x11_trusted, &proto, &data);
-               /* Request forwarding with authentication spoofing. */
-               debug("Requesting X11 forwarding with authentication spoofing.");
-               x11_request_forwarding_with_spoofing(id, display, proto, data);
-               /* XXX wait for reply */
-       }
-
-       if (cctx->want_agent_fwd && options.forward_agent) {
-               debug("Requesting authentication agent forwarding.");
-               channel_request_start(id, "auth-agent-req@openssh.com", 0);
-               packet_send();
-       }
-
-       client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
-           cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env,
-           client_subsystem_reply);
-
-       c->confirm_ctx = NULL;
-       buffer_free(&cctx->cmd);
-       xfree(cctx->term);
-       if (cctx->env != NULL) {
-               for (i = 0; cctx->env[i] != NULL; i++)
-                       xfree(cctx->env[i]);
-               xfree(cctx->env);
-       }
-       xfree(cctx);
+       xfree(ctx);
 }
 
 static void
-client_process_control(fd_set *readset)
+client_expect_confirm(int id, const char *request, int do_close)
 {
-       Buffer m;
-       Channel *c;
-       int client_fd, new_fd[3], ver, allowed, window, packetmax;
-       socklen_t addrlen;
-       struct sockaddr_storage addr;
-       struct confirm_ctx *cctx;
-       char *cmd;
-       u_int i, j, len, env_len, command, flags;
-       uid_t euid;
-       gid_t egid;
+       struct channel_reply_ctx *cr = xmalloc(sizeof(*cr));
 
-       /*
-        * Accept connection on control socket
-        */
-       if (control_fd == -1 || !FD_ISSET(control_fd, readset))
-               return;
+       cr->request_type = request;
+       cr->do_close = do_close;
 
-       memset(&addr, 0, sizeof(addr));
-       addrlen = sizeof(addr);
-       if ((client_fd = accept(control_fd,
-           (struct sockaddr*)&addr, &addrlen)) == -1) {
-               error("%s accept: %s", __func__, strerror(errno));
-               return;
-       }
-
-       if (getpeereid(client_fd, &euid, &egid) < 0) {
-               error("%s getpeereid failed: %s", __func__, strerror(errno));
-               close(client_fd);
-               return;
-       }
-       if ((euid != 0) && (getuid() != euid)) {
-               error("control mode uid mismatch: peer euid %u != uid %u",
-                   (u_int) euid, (u_int) getuid());
-               close(client_fd);
-               return;
-       }
-
-       unset_nonblock(client_fd);
-
-       /* Read command */
-       buffer_init(&m);
-       if (ssh_msg_recv(client_fd, &m) == -1) {
-               error("%s: client msg_recv failed", __func__);
-               close(client_fd);
-               buffer_free(&m);
-               return;
-       }
-       if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
-               error("%s: wrong client version %d", __func__, ver);
-               buffer_free(&m);
-               close(client_fd);
-               return;
-       }
-
-       allowed = 1;
-       command = buffer_get_int(&m);
-       flags = buffer_get_int(&m);
-
-       buffer_clear(&m);
-
-       switch (command) {
-       case SSHMUX_COMMAND_OPEN:
-               if (options.control_master == SSHCTL_MASTER_ASK ||
-                   options.control_master == SSHCTL_MASTER_AUTO_ASK)
-                       allowed = ask_permission("Allow shared connection "
-                           "to %s? ", host);
-               /* continue below */
-               break;
-       case SSHMUX_COMMAND_TERMINATE:
-               if (options.control_master == SSHCTL_MASTER_ASK ||
-                   options.control_master == SSHCTL_MASTER_AUTO_ASK)
-                       allowed = ask_permission("Terminate shared connection "
-                           "to %s? ", host);
-               if (allowed)
-                       quit_pending = 1;
-               /* FALLTHROUGH */
-       case SSHMUX_COMMAND_ALIVE_CHECK:
-               /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */
-               buffer_clear(&m);
-               buffer_put_int(&m, allowed);
-               buffer_put_int(&m, getpid());
-               if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
-                       error("%s: client msg_send failed", __func__);
-                       close(client_fd);
-                       buffer_free(&m);
-                       return;
-               }
-               buffer_free(&m);
-               close(client_fd);
-               return;
-       default:
-               error("Unsupported command %d", command);
-               buffer_free(&m);
-               close(client_fd);
-               return;
-       }
-
-       /* Reply for SSHMUX_COMMAND_OPEN */
-       buffer_clear(&m);
-       buffer_put_int(&m, allowed);
-       buffer_put_int(&m, getpid());
-       if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
-               error("%s: client msg_send failed", __func__);
-               close(client_fd);
-               buffer_free(&m);
-               return;
-       }
-
-       if (!allowed) {
-               error("Refused control connection");
-               close(client_fd);
-               buffer_free(&m);
-               return;
-       }
-
-       buffer_clear(&m);
-       if (ssh_msg_recv(client_fd, &m) == -1) {
-               error("%s: client msg_recv failed", __func__);
-               close(client_fd);
-               buffer_free(&m);
-               return;
-       }
-       if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
-               error("%s: wrong client version %d", __func__, ver);
-               buffer_free(&m);
-               close(client_fd);
-               return;
-       }
-
-       cctx = xcalloc(1, sizeof(*cctx));
-       cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
-       cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
-       cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
-       cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
-       cctx->term = buffer_get_string(&m, &len);
-
-       cmd = buffer_get_string(&m, &len);
-       buffer_init(&cctx->cmd);
-       buffer_append(&cctx->cmd, cmd, strlen(cmd));
-
-       env_len = buffer_get_int(&m);
-       env_len = MIN(env_len, 4096);
-       debug3("%s: receiving %d env vars", __func__, env_len);
-       if (env_len != 0) {
-               cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env));
-               for (i = 0; i < env_len; i++)
-                       cctx->env[i] = buffer_get_string(&m, &len);
-               cctx->env[i] = NULL;
-       }
-
-       debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__,
-           cctx->want_tty, cctx->want_subsys, cmd);
-       xfree(cmd);
-
-       /* Gather fds from client */
-       for(i = 0; i < 3; i++) {
-               if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) {
-                       error("%s: failed to receive fd %d from slave",
-                           __func__, i);
-                       for (j = 0; j < i; j++)
-                               close(new_fd[j]);
-                       for (j = 0; j < env_len; j++)
-                               xfree(cctx->env[j]);
-                       if (env_len > 0)
-                               xfree(cctx->env);
-                       xfree(cctx->term);
-                       buffer_free(&cctx->cmd);
-                       close(client_fd);
-                       xfree(cctx);
-                       return;
-               }
-       }
+       channel_register_status_confirm(id, client_status_confirm,
+           client_abandon_status_confirm, cr);
+}
 
-       debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
-           new_fd[0], new_fd[1], new_fd[2]);
-
-       /* Try to pick up ttymodes from client before it goes raw */
-       if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
-               error("%s: tcgetattr: %s", __func__, strerror(errno));
-
-       /* This roundtrip is just for synchronisation of ttymodes */
-       buffer_clear(&m);
-       if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
-               error("%s: client msg_send failed", __func__);
-               close(client_fd);
-               close(new_fd[0]);
-               close(new_fd[1]);
-               close(new_fd[2]);
-               buffer_free(&m);
-               xfree(cctx->term);
-               if (env_len != 0) {
-                       for (i = 0; i < env_len; i++)
-                               xfree(cctx->env[i]);
-                       xfree(cctx->env);
-               }
+void
+client_register_global_confirm(global_confirm_cb *cb, void *ctx)
+{
+       struct global_confirm *gc, *last_gc;
+
+       /* Coalesce identical callbacks */
+       last_gc = TAILQ_LAST(&global_confirms, global_confirms);
+       if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) {
+               if (++last_gc->ref_count >= INT_MAX)
+                       fatal("%s: last_gc->ref_count = %d",
+                           __func__, last_gc->ref_count);
                return;
        }
-       buffer_free(&m);
-
-       /* enable nonblocking unless tty */
-       if (!isatty(new_fd[0]))
-               set_nonblock(new_fd[0]);
-       if (!isatty(new_fd[1]))
-               set_nonblock(new_fd[1]);
-       if (!isatty(new_fd[2]))
-               set_nonblock(new_fd[2]);
-
-       set_nonblock(client_fd);
-
-       window = CHAN_SES_WINDOW_DEFAULT;
-       packetmax = CHAN_SES_PACKET_DEFAULT;
-       if (cctx->want_tty) {
-               window >>= 1;
-               packetmax >>= 1;
-       }
-       
-       c = channel_new("session", SSH_CHANNEL_OPENING,
-           new_fd[0], new_fd[1], new_fd[2], window, packetmax,
-           CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
-
-       /* XXX */
-       c->ctl_fd = client_fd;
-
-       debug3("%s: channel_new: %d", __func__, c->self);
 
-       channel_send_open(c->self);
-       channel_register_confirm(c->self, client_extra_session2_setup, cctx);
+       gc = xmalloc(sizeof(*gc));
+       gc->cb = cb;
+       gc->ctx = ctx;
+       gc->ref_count = 1;
+       TAILQ_INSERT_TAIL(&global_confirms, gc, entry);
 }
 
 static void
@@ -1061,9 +877,12 @@ out:
                xfree(fwd.connect_host);
 }
 
-/* process the characters one by one */
+/* 
+ * Process the characters one by one, call with c==NULL for proto1 case.
+ */
 static int
-process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
+process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
+    char *buf, int len)
 {
        char string[1024];
        pid_t pid;
@@ -1071,7 +890,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
        u_int i;
        u_char ch;
        char *s;
+       int *escape_pendingp, escape_char;
+       struct escape_filter_ctx *efc;
 
+       if (c == NULL) {
+               escape_pendingp = &escape_pending1;
+               escape_char = escape_char1;
+       } else {
+               if (c->filter_ctx == NULL)
+                       return 0;
+               efc = (struct escape_filter_ctx *)c->filter_ctx;
+               escape_pendingp = &efc->escape_pending;
+               escape_char = efc->escape_char;
+       }
+       
        if (len <= 0)
                return (0);
 
@@ -1079,25 +911,42 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
                /* Get one character at a time. */
                ch = buf[i];
 
-               if (escape_pending) {
+               if (*escape_pendingp) {
                        /* We have previously seen an escape character. */
                        /* Clear the flag now. */
-                       escape_pending = 0;
+                       *escape_pendingp = 0;
 
                        /* Process the escaped character. */
                        switch (ch) {
                        case '.':
                                /* Terminate the connection. */
-                               snprintf(string, sizeof string, "%c.\r\n", escape_char);
+                               snprintf(string, sizeof string, "%c.\r\n",
+                                   escape_char);
                                buffer_append(berr, string, strlen(string));
 
-                               quit_pending = 1;
+                               if (c && c->ctl_fd != -1) {
+                                       chan_read_failed(c);
+                                       chan_write_failed(c);
+                                       return 0;
+                               } else
+                                       quit_pending = 1;
                                return -1;
 
                        case 'Z' - 64:
-                               /* Suspend the program. */
-                               /* Print a message to that effect to the user. */
-                               snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
+                               /* XXX support this for mux clients */
+                               if (c && c->ctl_fd != -1) {
+ noescape:
+                                       snprintf(string, sizeof string,
+                                           "%c%c escape not available to "
+                                           "multiplexed sessions\r\n",
+                                           escape_char, ch);
+                                       buffer_append(berr, string,
+                                           strlen(string));
+                                       continue;
+                               }
+                               /* Suspend the program. Inform the user */
+                               snprintf(string, sizeof string,
+                                   "%c^Z [suspend ssh]\r\n", escape_char);
                                buffer_append(berr, string, strlen(string));
 
                                /* Restore terminal modes and suspend. */
@@ -1122,16 +971,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
                        case 'R':
                                if (compat20) {
                                        if (datafellows & SSH_BUG_NOREKEY)
-                                               logit("Server does not support re-keying");
+                                               logit("Server does not "
+                                                   "support re-keying");
                                        else
                                                need_rekeying = 1;
                                }
                                continue;
 
                        case '&':
+                               if (c && c->ctl_fd != -1)
+                                       goto noescape;
                                /*
-                                * Detach the program (continue to serve connections,
-                                * but put in background and no more new connections).
+                                * Detach the program (continue to serve
+                                * connections, but put in background and no
+                                * more new connections).
                                 */
                                /* Restore tty modes. */
                                leave_raw_mode();
@@ -1160,9 +1013,9 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
                                        return -1;
                                } else if (!stdin_eof) {
                                        /*
-                                        * Sending SSH_CMSG_EOF alone does not always appear
-                                        * to be enough.  So we try to send an EOF character
-                                        * first.
+                                        * Sending SSH_CMSG_EOF alone does not
+                                        * always appear to be enough.  So we
+                                        * try to send an EOF character first.
                                         */
                                        packet_start(SSH_CMSG_STDIN_DATA);
                                        packet_put_string("\004", 1);
@@ -1177,27 +1030,50 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
                                continue;
 
                        case '?':
-                               snprintf(string, sizeof string,
+                               if (c && c->ctl_fd != -1) {
+                                       snprintf(string, sizeof string,
+"%c?\r\n\
+Supported escape sequences:\r\n\
+  %c.  - terminate session\r\n\
+  %cB  - send a BREAK to the remote system\r\n\
+  %cC  - open a command line\r\n\
+  %cR  - Request rekey (SSH protocol 2 only)\r\n\
+  %c#  - list forwarded connections\r\n\
+  %c?  - this message\r\n\
+  %c%c  - send the escape character by typing it twice\r\n\
+(Note that escapes are only recognized immediately after newline.)\r\n",
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char);
+                               } else {
+                                       snprintf(string, sizeof string,
 "%c?\r\n\
 Supported escape sequences:\r\n\
-%c.  - terminate connection\r\n\
-%cB  - send a BREAK to the remote system\r\n\
-%cC  - open a command line\r\n\
-%cR  - Request rekey (SSH protocol 2 only)\r\n\
-%c^Z - suspend ssh\r\n\
-%c#  - list forwarded connections\r\n\
-%c&  - background ssh (when waiting for connections to terminate)\r\n\
-%c?  - this message\r\n\
-%c%c  - send the escape character by typing it twice\r\n\
+  %c.  - terminate connection (and any multiplexed sessions)\r\n\
+  %cB  - send a BREAK to the remote system\r\n\
+  %cC  - open a command line\r\n\
+  %cR  - Request rekey (SSH protocol 2 only)\r\n\
+  %c^Z - suspend ssh\r\n\
+  %c#  - list forwarded connections\r\n\
+  %c&  - background ssh (when waiting for connections to terminate)\r\n\
+  %c?  - this message\r\n\
+  %c%c  - send the escape character by typing it twice\r\n\
 (Note that escapes are only recognized immediately after newline.)\r\n",
-                                   escape_char, escape_char, escape_char, escape_char,
-                                   escape_char, escape_char, escape_char, escape_char,
-                                   escape_char, escape_char, escape_char);
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char);
+                               }
                                buffer_append(berr, string, strlen(string));
                                continue;
 
                        case '#':
-                               snprintf(string, sizeof string, "%c#\r\n", escape_char);
+                               snprintf(string, sizeof string, "%c#\r\n",
+                                   escape_char);
                                buffer_append(berr, string, strlen(string));
                                s = channel_open_message();
                                buffer_append(berr, s, strlen(s));
@@ -1218,12 +1094,15 @@ Supported escape sequences:\r\n\
                        }
                } else {
                        /*
-                        * The previous character was not an escape char. Check if this
-                        * is an escape.
+                        * The previous character was not an escape char.
+                        * Check if this is an escape.
                         */
                        if (last_was_cr && ch == escape_char) {
-                               /* It is. Set the flag and continue to next character. */
-                               escape_pending = 1;
+                               /*
+                                * It is. Set the flag and continue to
+                                * next character.
+                                */
+                               *escape_pendingp = 1;
                                continue;
                        }
                }
@@ -1249,7 +1128,8 @@ client_process_input(fd_set *readset)
        if (FD_ISSET(fileno(stdin), readset)) {
                /* Read as much as possible. */
                len = read(fileno(stdin), buf, sizeof(buf));
-               if (len < 0 && (errno == EAGAIN || errno == EINTR))
+               if (len < 0 &&
+                   (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
                        return;         /* we'll try again later */
                if (len <= 0) {
                        /*
@@ -1258,7 +1138,8 @@ client_process_input(fd_set *readset)
                         * if it was an error condition.
                         */
                        if (len < 0) {
-                               snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno));
+                               snprintf(buf, sizeof buf, "read: %.100s\r\n",
+                                   strerror(errno));
                                buffer_append(&stderr_buffer, buf, strlen(buf));
                        }
                        /* Mark that we have seen EOF. */
@@ -1274,7 +1155,7 @@ client_process_input(fd_set *readset)
                                packet_start(SSH_CMSG_EOF);
                                packet_send();
                        }
-               } else if (escape_char == SSH_ESCAPECHAR_NONE) {
+               } else if (escape_char1 == SSH_ESCAPECHAR_NONE) {
                        /*
                         * Normal successful read, and no escape character.
                         * Just append the data to buffer.
@@ -1282,11 +1163,12 @@ client_process_input(fd_set *readset)
                        buffer_append(&stdin_buffer, buf, len);
                } else {
                        /*
-                        * Normal, successful read.  But we have an escape character
-                        * and have to process the characters one by one.
+                        * Normal, successful read.  But we have an escape
+                        * character and have to process the characters one
+                        * by one.
                         */
-                       if (process_escapes(&stdin_buffer, &stdout_buffer,
-                           &stderr_buffer, buf, len) == -1)
+                       if (process_escapes(NULL, &stdin_buffer,
+                           &stdout_buffer, &stderr_buffer, buf, len) == -1)
                                return;
                }
        }
@@ -1304,14 +1186,16 @@ client_process_output(fd_set *writeset)
                len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
                    buffer_len(&stdout_buffer));
                if (len <= 0) {
-                       if (errno == EINTR || errno == EAGAIN)
+                       if (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK)
                                len = 0;
                        else {
                                /*
                                 * An error or EOF was encountered.  Put an
                                 * error message to stderr buffer.
                                 */
-                               snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno));
+                               snprintf(buf, sizeof buf,
+                                   "write stdout: %.50s\r\n", strerror(errno));
                                buffer_append(&stderr_buffer, buf, strlen(buf));
                                quit_pending = 1;
                                return;
@@ -1319,7 +1203,6 @@ client_process_output(fd_set *writeset)
                }
                /* Consume printed data from the buffer. */
                buffer_consume(&stdout_buffer, len);
-               stdout_bytes += len;
        }
        /* Write buffered output to stderr. */
        if (FD_ISSET(fileno(stderr), writeset)) {
@@ -1327,17 +1210,20 @@ client_process_output(fd_set *writeset)
                len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
                    buffer_len(&stderr_buffer));
                if (len <= 0) {
-                       if (errno == EINTR || errno == EAGAIN)
+                       if (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK)
                                len = 0;
                        else {
-                               /* EOF or error, but can't even print error message. */
+                               /*
+                                * EOF or error, but can't even print
+                                * error message.
+                                */
                                quit_pending = 1;
                                return;
                        }
                }
                /* Consume printed characters from the buffer. */
                buffer_consume(&stderr_buffer, len);
-               stderr_bytes += len;
        }
 }
 
@@ -1356,16 +1242,39 @@ client_process_output(fd_set *writeset)
 static void
 client_process_buffered_input_packets(void)
 {
-       dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL);
+       dispatch_run(DISPATCH_NONBLOCK, &quit_pending,
+           compat20 ? xxx_kex : NULL);
 }
 
 /* scan buf[] for '~' before sending data to the peer */
 
-static int
-simple_escape_filter(Channel *c, char *buf, int len)
+/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
+void *
+client_new_escape_filter_ctx(int escape_char)
 {
-       /* XXX we assume c->extended is writeable */
-       return process_escapes(&c->input, &c->output, &c->extended, buf, len);
+       struct escape_filter_ctx *ret;
+
+       ret = xmalloc(sizeof(*ret));
+       ret->escape_pending = 0;
+       ret->escape_char = escape_char;
+       return (void *)ret;
+}
+
+/* Free the escape filter context on channel free */
+void
+client_filter_cleanup(int cid, void *ctx)
+{
+       xfree(ctx);
+}
+
+int
+client_simple_escape_filter(Channel *c, char *buf, int len)
+{
+       if (c->extended_usage != CHAN_EXTENDED_WRITE)
+               return 0;
+
+       return process_escapes(c, &c->input, &c->output, &c->extended,
+           buf, len);
 }
 
 static void
@@ -1389,6 +1298,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
        fd_set *readset = NULL, *writeset = NULL;
        double start_time, total_time;
        int max_fd = 0, max_fd2 = 0, len, rekeying = 0;
+       u_int64_t ibytes, obytes;
        u_int nalloc = 0;
        char buf[100];
 
@@ -1397,7 +1307,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
        start_time = get_current_time();
 
        /* Initialize variables. */
-       escape_pending = 0;
+       escape_pending1 = 0;
        last_was_cr = 1;
        exit_status = -1;
        stdin_eof = 0;
@@ -1405,8 +1315,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
        connection_in = packet_get_connection_in();
        connection_out = packet_get_connection_out();
        max_fd = MAX(connection_in, connection_out);
-       if (control_fd != -1)
-               max_fd = MAX(max_fd, control_fd);
+       if (muxserver_sock != -1)
+               max_fd = MAX(max_fd, muxserver_sock);
 
        if (!compat20) {
                /* enable nonblocking unless tty */
@@ -1420,11 +1330,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
                max_fd = MAX(max_fd, fileno(stdout));
                max_fd = MAX(max_fd, fileno(stderr));
        }
-       stdin_bytes = 0;
-       stdout_bytes = 0;
-       stderr_bytes = 0;
        quit_pending = 0;
-       escape_char = escape_char_arg;
+       escape_char1 = escape_char_arg;
 
        /* Initialize buffers. */
        buffer_init(&stdin_buffer);
@@ -1452,9 +1359,11 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 
        if (compat20) {
                session_ident = ssh2_chan_id;
-               if (escape_char != SSH_ESCAPECHAR_NONE)
+               if (escape_char_arg != SSH_ESCAPECHAR_NONE)
                        channel_register_filter(session_ident,
-                           simple_escape_filter, NULL);
+                           client_simple_escape_filter, NULL,
+                           client_filter_cleanup,
+                           client_new_escape_filter_ctx(escape_char_arg));
                if (session_ident != -1)
                        channel_register_cleanup(session_ident,
                            client_channel_closed, 0);
@@ -1526,7 +1435,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
                client_process_net_input(readset);
 
                /* Accept control connections.  */
-               client_process_control(readset);
+               if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) {
+                       if (muxserver_accept_control())
+                               quit_pending = 1;
+               }
 
                if (quit_pending)
                        break;
@@ -1541,7 +1453,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
                        client_process_output(writeset);
                }
 
-               /* Send as much buffered packet data as possible to the sender. */
+               /*
+                * Send as much buffered packet data as possible to the
+                * sender.
+                */
                if (FD_ISSET(connection_out, writeset))
                        packet_write_poll();
        }
@@ -1586,7 +1501,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
         * that the connection has been closed.
         */
        if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) {
-               snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host);
+               snprintf(buf, sizeof buf,
+                   "Connection to %.64s closed.\r\n", host);
                buffer_append(&stderr_buffer, buf, strlen(buf));
        }
 
@@ -1599,7 +1515,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
                        break;
                }
                buffer_consume(&stdout_buffer, len);
-               stdout_bytes += len;
        }
 
        /* Output any buffered data for stderr. */
@@ -1611,7 +1526,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
                        break;
                }
                buffer_consume(&stderr_buffer, len);
-               stderr_bytes += len;
        }
 
        /* Clear and free any buffers. */
@@ -1622,13 +1536,13 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
 
        /* Report bytes transferred, and transfer rates. */
        total_time = get_current_time() - start_time;
-       debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds",
-           stdin_bytes, stdout_bytes, stderr_bytes, total_time);
+       packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
+       packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
+       verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds",
+           obytes, ibytes, total_time);
        if (total_time > 0)
-               debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f",
-                   stdin_bytes / total_time, stdout_bytes / total_time,
-                   stderr_bytes / total_time);
-
+               verbose("Bytes per second: sent %.1f, received %.1f",
+                   obytes / total_time, ibytes / total_time);
        /* Return the exit status of the program. */
        debug("Exit status %d", exit_status);
        return exit_status;
@@ -1719,7 +1633,6 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
        Channel *c = NULL;
        char *listen_address, *originator_address;
        int listen_port, originator_port;
-       int sock;
 
        /* Get rest of the packet */
        listen_address = packet_get_string(NULL);
@@ -1728,19 +1641,13 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
        originator_port = packet_get_int();
        packet_check_eom();
 
-       debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d",
-           listen_address, listen_port, originator_address, originator_port);
+       debug("client_request_forwarded_tcpip: listen %s port %d, "
+           "originator %s port %d", listen_address, listen_port,
+           originator_address, originator_port);
+
+       c = channel_connect_by_listen_address(listen_port,
+           "forwarded-tcpip", originator_address);
 
-       sock = channel_connect_by_listen_address(listen_port);
-       if (sock < 0) {
-               xfree(originator_address);
-               xfree(listen_address);
-               return NULL;
-       }
-       c = channel_new("forwarded-tcpip",
-           SSH_CHANNEL_CONNECTING, sock, sock, -1,
-           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0,
-           originator_address, 1);
        xfree(originator_address);
        xfree(listen_address);
        return c;
@@ -1756,7 +1663,8 @@ client_request_x11(const char *request_type, int rchan)
 
        if (!options.forward_x11) {
                error("Warning: ssh server tried X11 forwarding.");
-               error("Warning: this is probably a break-in attempt by a malicious server.");
+               error("Warning: this is probably a break-in attempt by a "
+                   "malicious server.");
                return NULL;
        }
        originator = packet_get_string(NULL);
@@ -1789,7 +1697,8 @@ client_request_agent(const char *request_type, int rchan)
 
        if (!options.forward_agent) {
                error("Warning: ssh server tried agent forwarding.");
-               error("Warning: this is probably a break-in attempt by a malicious server.");
+               error("Warning: this is probably a break-in attempt by a "
+                   "malicious server.");
                return NULL;
        }
        sock = ssh_get_authentication_socket();
@@ -1832,7 +1741,7 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
 #if defined(SSH_TUN_FILTER)
        if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
                channel_register_filter(c->self, sys_tun_infilter,
-                   sys_tun_outfilter);
+                   sys_tun_outfilter, NULL, NULL);
 #endif
 
        packet_start(SSH2_MSG_CHANNEL_OPEN);
@@ -1915,7 +1824,11 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
        if (id == -1) {
                error("client_input_channel_req: request for channel -1");
        } else if ((c = channel_lookup(id)) == NULL) {
-               error("client_input_channel_req: channel %d: unknown channel", id);
+               error("client_input_channel_req: channel %d: "
+                   "unknown channel", id);
+       } else if (strcmp(rtype, "eow@openssh.com") == 0) {
+               packet_check_eom();
+               chan_rcvd_eow(c);
        } else if (strcmp(rtype, "exit-status") == 0) {
                exitval = packet_get_int();
                if (id == session_ident) {
@@ -1960,8 +1873,7 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
 
 void
 client_session2_setup(int id, int want_tty, int want_subsystem,
-    const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env,
-    dispatch_fn *subsys_repl)
+    const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env)
 {
        int len;
        Channel *c = NULL;
@@ -1973,20 +1885,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
 
        if (want_tty) {
                struct winsize ws;
-               struct termios tio;
 
                /* Store window size in the packet. */
                if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0)
                        memset(&ws, 0, sizeof(ws));
 
-               channel_request_start(id, "pty-req", 0);
+               channel_request_start(id, "pty-req", 1);
+               client_expect_confirm(id, "PTY allocation", 0);
                packet_put_cstring(term != NULL ? term : "");
                packet_put_int((u_int)ws.ws_col);
                packet_put_int((u_int)ws.ws_row);
                packet_put_int((u_int)ws.ws_xpixel);
                packet_put_int((u_int)ws.ws_ypixel);
-               tio = get_saved_tio();
-               tty_make_modes(-1, tiop != NULL ? tiop : &tio);
+               if (tiop == NULL)
+                       tiop = get_saved_tio();
+               tty_make_modes(-1, tiop);
                packet_send();
                /* XXX wait for reply */
                c->client_tty = 1;
@@ -2034,22 +1947,21 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
                if (len > 900)
                        len = 900;
                if (want_subsystem) {
-                       debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd));
-                       channel_request_start(id, "subsystem", subsys_repl != NULL);
-                       if (subsys_repl != NULL) {
-                               /* register callback for reply */
-                               /* XXX we assume that client_loop has already been called */
-                               dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl);
-                               dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl);
-                       }
+                       debug("Sending subsystem: %.*s",
+                           len, (u_char*)buffer_ptr(cmd));
+                       channel_request_start(id, "subsystem", 1);
+                       client_expect_confirm(id, "subsystem", 1);
                } else {
-                       debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd));
-                       channel_request_start(id, "exec", 0);
+                       debug("Sending command: %.*s",
+                           len, (u_char*)buffer_ptr(cmd));
+                       channel_request_start(id, "exec", 1);
+                       client_expect_confirm(id, "exec", 1);
                }
                packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
                packet_send();
        } else {
-               channel_request_start(id, "shell", 0);
+               channel_request_start(id, "shell", 1);
+               client_expect_confirm(id, "shell", 1);
                packet_send();
        }
 }
@@ -2068,6 +1980,8 @@ client_init_dispatch_20(void)
        dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
        dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req);
        dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
+       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm);
+       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm);
        dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request);
 
        /* rekeying */
@@ -2077,6 +1991,7 @@ client_init_dispatch_20(void)
        dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply);
        dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply);
 }
+
 static void
 client_init_dispatch_13(void)
 {
@@ -2096,6 +2011,7 @@ client_init_dispatch_13(void)
        dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
            &x11_input_open : &deny_input_open);
 }
+
 static void
 client_init_dispatch_15(void)
 {
@@ -2103,6 +2019,7 @@ client_init_dispatch_15(void)
        dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
        dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
 }
+
 static void
 client_init_dispatch(void)
 {
@@ -2120,7 +2037,7 @@ cleanup_exit(int i)
 {
        leave_raw_mode();
        leave_non_blocking();
-       if (options.control_path != NULL && control_fd != -1)
+       if (options.control_path != NULL && muxserver_sock != -1)
                unlink(options.control_path);
        _exit(i);
 }
index c7d2233d03a82106848d0f98575d6a011011b723..8bb874b38821962e1757f043434566d9999f9000 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.h,v 1.17 2007/08/07 07:32:53 djm Exp $ */
+/* $OpenBSD: clientloop.h,v 1.22 2008/06/12 15:19:17 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -43,11 +43,20 @@ void         client_x11_get_proto(const char *, const char *, u_int,
            char **, char **);
 void    client_global_request_reply_fwd(int, u_int32_t, void *);
 void    client_session2_setup(int, int, int, const char *, struct termios *,
-           int, Buffer *, char **, dispatch_fn *);
+           int, Buffer *, char **);
 int     client_request_tun_fwd(int, int, int);
 
+/* Escape filter for protocol 2 sessions */
+void   *client_new_escape_filter_ctx(int);
+void    client_filter_cleanup(int, void *);
+int     client_simple_escape_filter(Channel *, char *, int);
+
+/* Global request confirmation callbacks */
+typedef void global_confirm_cb(int, u_int32_t seq, void *);
+void    client_register_global_confirm(global_confirm_cb *, void *);
+
 /* Multiplexing protocol version */
-#define SSHMUX_VER                     1
+#define SSHMUX_VER                     2
 
 /* Multiplexing control protocol flags */
 #define SSHMUX_COMMAND_OPEN            1       /* Open new connection */
@@ -58,3 +67,7 @@ int    client_request_tun_fwd(int, int, int);
 #define SSHMUX_FLAG_SUBSYS             (1<<1)  /* Subsystem request on open */
 #define SSHMUX_FLAG_X11_FWD            (1<<2)  /* Request X11 forwarding */
 #define SSHMUX_FLAG_AGENT_FWD          (1<<3)  /* Request agent forwarding */
+
+void   muxserver_listen(void);
+int    muxserver_accept_control(void);
+void   muxclient(const char *);
index 839e8f1ae52ac590bc8b1a6df284abf415fe08f0..26820850088b82faff37eea81a70ce1bc74d0292 100644 (file)
@@ -107,11 +107,23 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
                     no_attrib_nonnull=1
                     ;;
                2.*) no_attrib_nonnull=1 ;;
-               3.*) CFLAGS="$CFLAGS -Wsign-compare" ;;
-               4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;;
+               3.*) CFLAGS="$CFLAGS -Wsign-compare -Wformat-security" ;;
+               4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign -Wformat-security" ;;
                *) ;;
        esac
 
+       AC_MSG_CHECKING(if $CC accepts -fno-builtin-memset)
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -fno-builtin-memset"
+       AC_LINK_IFELSE( [AC_LANG_SOURCE([[
+#include <string.h>
+int main(void){char b[10]; memset(b, 0, sizeof(b));}
+               ]])],
+               [ AC_MSG_RESULT(yes) ],
+               [ AC_MSG_RESULT(no)
+                 CFLAGS="$saved_CFLAGS" ]
+)
+
        # -fstack-protector-all doesn't always work for some GCC versions
        # and/or platforms, so we test if we can.  If it's not supported
        # on a give platform gcc will emit a warning so we use -Werror.
@@ -267,6 +279,7 @@ AC_CHECK_HEADERS( \
        sys/cdefs.h \
        sys/dir.h \
        sys/mman.h \
+       sys/mount.h \
        sys/ndir.h \
        sys/poll.h \
        sys/prctl.h \
@@ -276,6 +289,7 @@ AC_CHECK_HEADERS( \
        sys/stream.h \
        sys/stropts.h \
        sys/strtio.h \
+       sys/statvfs.h \
        sys/sysmacros.h \
        sys/time.h \
        sys/timers.h \
@@ -551,7 +565,6 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
        no_dev_ptmx=1
        check_for_libcrypt_later=1
        check_for_openpty_ctty_bug=1
-       AC_DEFINE(DONT_TRY_OTHER_AF, 1, [Workaround more Linux IPv6 quirks])
        AC_DEFINE(PAM_TTY_KLUDGE, 1,
                [Work around problematic Linux PAM modules handling of PAM_TTY])
        AC_DEFINE(LOCKED_PASSWD_PREFIX, "!",
@@ -828,6 +841,7 @@ mips-sony-bsd|mips-sony-newsos4)
        AC_DEFINE(SETEUID_BREAKS_SETUID)
        AC_DEFINE(BROKEN_SETREUID)
        AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(BROKEN_READV_COMPARISON, 1, [Can't do comparisons on readv])
        ;;
 
 *-*-nto-qnx*)
@@ -1034,7 +1048,7 @@ dnl    Checks for libutil functions
 AC_CHECK_HEADERS(libutil.h)
 AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN, 1,
        [Define if your libraries define login()])])
-AC_CHECK_FUNCS(logout updwtmp logwtmp)
+AC_CHECK_FUNCS(fmt_scaled logout updwtmp logwtmp)
 
 AC_FUNC_STRFTIME
 
@@ -1288,6 +1302,8 @@ AC_ARG_WITH(audit,
 dnl    Checks for library functions. Please keep in alphabetical order
 AC_CHECK_FUNCS( \
        arc4random \
+       arc4random_buf \
+       arc4random_uniform \
        asprintf \
        b64_ntop \
        __b64_ntop \
@@ -1301,6 +1317,7 @@ AC_CHECK_FUNCS( \
        fchmod \
        fchown \
        freeaddrinfo \
+       fstatvfs \
        futimes \
        getaddrinfo \
        getcwd \
@@ -1352,6 +1369,8 @@ AC_CHECK_FUNCS( \
        sigvec \
        snprintf \
        socketpair \
+       statfs \
+       statvfs \
        strdup \
        strerror \
        strlcat \
@@ -2645,6 +2664,18 @@ fi
 TYPE_SOCKLEN_T
 
 AC_CHECK_TYPES(sig_atomic_t,,,[#include <signal.h>])
+AC_CHECK_TYPES([fsblkcnt_t, fsfilcnt_t],,,[
+#include <sys/types.h>
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+])
 
 AC_CHECK_TYPES(in_addr_t,,,
 [#include <sys/types.h>
@@ -3007,6 +3038,16 @@ if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then
                file descriptor passing])
 fi
 
+AC_MSG_CHECKING(if f_fsid has val members)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/statvfs.h>],
+[struct fsid_t t; t.val[0] = 0;],
+       [ AC_MSG_RESULT(yes)
+         AC_DEFINE(FSID_HAS_VAL, 1, f_fsid has members) ],
+       [ AC_MSG_RESULT(no) ]
+)
+
 AC_CACHE_CHECK([for msg_control field in struct msghdr],
                ac_cv_have_control_in_msghdr, [
        AC_COMPILE_IFELSE(
@@ -3335,12 +3376,12 @@ AC_ARG_WITH(kerberos5,
                        )
                        AC_SEARCH_LIBS(dn_expand, resolv)
 
-                       AC_CHECK_LIB(gssapi,gss_init_sec_context,
+                       AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context,
                                [ AC_DEFINE(GSSAPI)
-                                 K5LIBS="-lgssapi $K5LIBS" ],
-                               [ AC_CHECK_LIB(gssapi_krb5,gss_init_sec_context,
+                                 K5LIBS="-lgssapi_krb5 $K5LIBS" ],
+                               [ AC_CHECK_LIB(gssapigss_init_sec_context,
                                        [ AC_DEFINE(GSSAPI)
-                                         K5LIBS="-lgssapi_krb5 $K5LIBS" ],
+                                         K5LIBS="-lgssapi $K5LIBS" ],
                                        AC_MSG_WARN([Cannot find any suitable gss-api library - build may fail]),
                                        $K5LIBS)
                                ],
@@ -4039,6 +4080,13 @@ dnl Adding -Werror to CFLAGS early prevents configure tests from running.
 dnl Add now.
 CFLAGS="$CFLAGS $werror_flags"
 
+if grep "#define BROKEN_GETADDRINFO 1" confdefs.h >/dev/null || \
+    test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
+       AC_SUBST(TEST_SSH_IPV6, no)
+else
+       AC_SUBST(TEST_SSH_IPV6, yes)
+fi
+
 AC_EXEEXT
 AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \
        openbsd-compat/Makefile openbsd-compat/regress/Makefile \
index 5b2fcdf1a35323b07a008bfdf3cd3bf49687ee27..264cd16aec8f10236416cff59163281201d31a2a 100644 (file)
 #old cvs stuff.  please update before use.  may be deprecated.
 %define use_stable     1
 %if %{use_stable}
-  %define version      5.0p1
+  %define version      5.1p1
   %define cvs          %{nil}
   %define release      1
 %else
-  %define version      5.0p1
+  %define version      5.1p1
   %define cvs          cvs20050315
   %define release      0r1
 %endif
@@ -342,6 +342,7 @@ fi
 %config %{SVIcdir}/sshd
 %{_libexecdir}/sftp-server
 %{_sbindir}/sshd
+%{_mandir}/man5/moduli.5.gz
 %{_mandir}/man5/sshd_config.5.gz
 %{_mandir}/man8/sftp-server.8.gz
 %{_mandir}/man8/sshd.8.gz
index 09e8ea2db213e3210eef46f4fbc6105b9cf95347..3e2d264041dfcdcdd4aca017fda7d01604ec385f 100644 (file)
@@ -8,6 +8,7 @@ sshdocdir=$(docdir)/openssh
 cygdocdir=$(docdir)/Cygwin
 sysconfdir=/etc
 defaultsdir=$(sysconfdir)/defaults/etc
+inetdefdir=$(defaultsdir)/inetd.d
 PRIVSEP_PATH=/var/empty
 INSTALL=/usr/bin/install -c
 
@@ -27,6 +28,10 @@ move-config-files: $(DESTDIR)$(sysconfdir)/ssh_config $(DESTDIR)$(sysconfdir)/ss
 remove-empty-dir:
        rm -rf $(DESTDIR)$(PRIVSEP_PATH)
 
+install-inetd-config:
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(inetdefdir)
+       $(INSTALL) -m 644 sshd-inetd  $(DESTDIR)$(inetdefdir)/sshd-inetd
+
 install-sshdoc:
        $(srcdir)/mkinstalldirs $(DESTDIR)$(sshdocdir)
        $(INSTALL) -m 644 $(srcdir)/CREDITS $(DESTDIR)$(sshdocdir)/CREDITS
@@ -52,5 +57,5 @@ install-scripts: ssh-host-config ssh-user-config
        $(INSTALL) -m 755 ssh-host-config $(DESTDIR)$(bindir)/ssh-host-config
        $(INSTALL) -m 755 ssh-user-config $(DESTDIR)$(bindir)/ssh-user-config
 
-cygwin-postinstall: move-config-files remove-empty-dir install-doc install-scripts
+cygwin-postinstall: move-config-files remove-empty-dir install-inetd-config install-doc install-scripts
        @echo "Cygwin specific configuration finished."
index f90af8d2a5e1e59d387ed6136abbacdd2776b2a5..bbb6da4c4e767bb310300102b4213a2dcaeb9553 100644 (file)
@@ -4,6 +4,15 @@
 #
 # This file is part of the Cygwin port of OpenSSH.
 
+# ======================================================================
+# Initialization
+# ======================================================================
+PROGNAME=$(basename $0)
+_tdir=$(dirname $0)
+PROGDIR=$(cd $_tdir && pwd)
+
+CSIH_SCRIPT=/usr/share/csih/cygwin-service-installation-helper.sh
+
 # Subdirectory where the new package is being installed
 PREFIX=/usr
 
@@ -11,43 +20,371 @@ PREFIX=/usr
 SYSCONFDIR=/etc
 LOCALSTATEDIR=/var
 
-progname=$0
-auto_answer=""
-port_number=22
+source ${CSIH_SCRIPT}
 
+port_number=22
 privsep_configured=no
 privsep_used=yes
-sshd_in_passwd=no
-sshd_in_sam=no
+cygwin_value="ntsec"
+password_value=
+
+# ======================================================================
+# Routine: create_host_keys
+# ======================================================================
+create_host_keys() {
+  if [ ! -f "${SYSCONFDIR}/ssh_host_key" ]
+  then
+    csih_inform "Generating ${SYSCONFDIR}/ssh_host_key"
+    ssh-keygen -t rsa1 -f ${SYSCONFDIR}/ssh_host_key -N '' > /dev/null
+  fi
+  
+  if [ ! -f "${SYSCONFDIR}/ssh_host_rsa_key" ]
+  then
+    csih_inform "Generating ${SYSCONFDIR}/ssh_host_rsa_key"
+    ssh-keygen -t rsa -f ${SYSCONFDIR}/ssh_host_rsa_key -N '' > /dev/null
+  fi
+  
+  if [ ! -f "${SYSCONFDIR}/ssh_host_dsa_key" ]
+  then
+    csih_inform "Generating ${SYSCONFDIR}/ssh_host_dsa_key"
+    ssh-keygen -t dsa -f ${SYSCONFDIR}/ssh_host_dsa_key -N '' > /dev/null
+  fi
+} # --- End of create_host_keys --- #
+
+# ======================================================================
+# Routine: update_services_file
+# ======================================================================
+update_services_file() {
+  local _my_etcdir="/ssh-host-config.$$"
+  local _win_etcdir
+  local _services
+  local _spaces
+  local _serv_tmp
+  local _wservices
+
+  if csih_is_nt
+  then
+    _win_etcdir="${SYSTEMROOT}\\system32\\drivers\\etc"
+    _services="${_my_etcdir}/services"
+    # On NT, 27 spaces, no space after the hash
+    _spaces="                           #"
+  else
+    _win_etcdir="${WINDIR}"
+    _services="${_my_etcdir}/SERVICES"
+    # On 9x, 18 spaces (95 is very touchy), a space after the hash
+    _spaces="                  # "
+  fi
+  _serv_tmp="${_my_etcdir}/srv.out.$$"
+  
+  mount -t -f "${_win_etcdir}" "${_my_etcdir}"
+  
+  # Depends on the above mount
+  _wservices=`cygpath -w "${_services}"`
+  
+  # Remove sshd 22/port from services
+  if [ `grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ]
+  then
+    grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}"
+    if [ -f "${_serv_tmp}" ]
+    then
+      if mv "${_serv_tmp}" "${_services}"
+      then
+        csih_inform "Removing sshd from ${_wservices}"
+      else
+        csih_warning "Removing sshd from ${_wservices} failed!"
+      fi
+      rm -f "${_serv_tmp}"
+    else
+      csih_warning "Removing sshd from ${_wservices} failed!"
+    fi
+  fi
+  
+  # Add ssh 22/tcp  and ssh 22/udp to services
+  if [ `grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ]
+  then
+    if awk '{ if ( $2 ~ /^23\/tcp/ ) print "ssh                22/tcp'"${_spaces}"'SSH Remote Login Protocol\nssh                22/udp'"${_spaces}"'SSH Remote Login Protocol"; print $0; }' < "${_services}" > "${_serv_tmp}"
+    then
+      if mv "${_serv_tmp}" "${_services}"
+      then
+        csih_inform "Added ssh to ${_wservices}"
+      else
+        csih_warning "Adding ssh to ${_wservices} failed!"
+      fi
+      rm -f "${_serv_tmp}"
+    else
+      csih_warning "Adding ssh to ${_wservices} failed!"
+    fi
+  fi
+  umount "${_my_etcdir}"
+} # --- End of update_services_file --- #
 
-request()
-{
-  if [ "${auto_answer}" = "yes" ]
+# ======================================================================
+# Routine: sshd_privsep
+#  MODIFIES: privsep_configured  privsep_used
+# ======================================================================
+sshd_privsep() {
+  local sshdconfig_tmp
+
+  if [ "${privsep_configured}" != "yes" ]
+  then
+    if csih_is_nt
+    then
+      csih_inform "Privilege separation is set to yes by default since OpenSSH 3.3."
+      csih_inform "However, this requires a non-privileged account called 'sshd'."
+      csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep."
+      if csih_request "Should privilege separation be used?"
+      then
+        privsep_used=yes
+        if ! csih_create_unprivileged_user sshd
+        then
+         csih_warning "Couldn't create user 'sshd'!"
+          csih_warning "Privilege separation set to 'no' again!"
+          csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
+         privsep_used=no
+        fi
+      else
+        privsep_used=no
+      fi
+    else
+      # On 9x don't use privilege separation.  Since security isn't
+      # available it just adds useless additional processes.
+      privsep_used=no
+    fi
+  fi
+  
+  # Create default sshd_config from skeleton files in /etc/defaults/etc or
+  # modify to add the missing privsep configuration option
+  if cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
   then
-    echo "$1 (yes/no) yes"
-    return 0
-  elif [ "${auto_answer}" = "no" ]
+    csih_inform "Updating ${SYSCONFDIR}/sshd_config file"
+    sshdconfig_tmp=${SYSCONFDIR}/sshd_config.$$
+    sed -e "s/^#UsePrivilegeSeparation yes/UsePrivilegeSeparation ${privsep_used}/
+         s/^#Port 22/Port ${port_number}/
+         s/^#StrictModes yes/StrictModes no/" \
+        < ${SYSCONFDIR}/sshd_config \
+        > "${sshdconfig_tmp}"
+    mv "${sshdconfig_tmp}" ${SYSCONFDIR}/sshd_config
+  elif [ "${privsep_configured}" != "yes" ]
   then
-    echo "$1 (yes/no) no"
-    return 1
+    echo >> ${SYSCONFDIR}/sshd_config
+    echo "UsePrivilegeSeparation ${privsep_used}" >> ${SYSCONFDIR}/sshd_config
   fi
+} # --- End of sshd_privsep --- #
+
+# ======================================================================
+# Routine: update_inetd_conf
+# ======================================================================
+update_inetd_conf() {
+  local _inetcnf="${SYSCONFDIR}/inetd.conf"
+  local _inetcnf_tmp="${SYSCONFDIR}/inetd.conf.$$"
+  local _inetcnf_dir="${SYSCONFDIR}/inetd.d"
+  local _sshd_inetd_conf="${_inetcnf_dir}/sshd-inetd"
+  local _sshd_inetd_conf_tmp="${_inetcnf_dir}/sshd-inetd.$$"
+  local _with_comment=1
+
+  if [ -d "${_inetcnf_dir}" ]
+  then
+    # we have inetutils-1.5 inetd.d support
+    if [ -f "${_inetcnf}" ]
+    then
+      grep -q '^[ \t]*ssh' "${_inetcnf}" && _with_comment=0
+
+      # check for sshd OR ssh in top-level inetd.conf file, and remove
+      # will be replaced by a file in inetd.d/
+      if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -eq 0 ]
+      then
+        grep -v '^[# \t]*ssh' "${_inetcnf}" >> "${_inetcnf_tmp}"
+        if [ -f "${_inetcnf_tmp}" ]
+        then
+          if mv "${_inetcnf_tmp}" "${_inetcnf}"
+          then
+           csih_inform "Removed ssh[d] from ${_inetcnf}"
+          else
+           csih_warning "Removing ssh[d] from ${_inetcnf} failed!"
+          fi
+          rm -f "${_inetcnf_tmp}"
+        else
+          csih_warning "Removing ssh[d] from ${_inetcnf} failed!"
+        fi
+      fi
+    fi
+
+    csih_install_config "${_sshd_inetd_conf}"   "${SYSCONFDIR}/defaults"
+    if cmp "${SYSCONFDIR}/defaults${_sshd_inetd_conf}" "${_sshd_inetd_conf}" >/dev/null 2>&1
+    then
+      if [ "${_with_comment}" -eq 0 ]
+      then
+        sed -e 's/@COMMENT@[ \t]*//' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
+      else
+        sed -e 's/@COMMENT@[ \t]*/# /' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
+      fi
+      mv "${_sshd_inetd_conf_tmp}" "${_sshd_inetd_conf}"
+      csih_inform "Updated ${_sshd_inetd_conf}"
+    fi 
 
-  answer=""
-  while [ "X${answer}" != "Xyes" -a "X${answer}" != "Xno" ]
-  do
-    echo -n "$1 (yes/no) "
-    read -e answer
-  done
-  if [ "X${answer}" = "Xyes" ]
+  elif [ -f "${_inetcnf}" ]
   then
-    return 0
-  else
-    return 1
+    grep -q '^[ \t]*sshd' "${_inetcnf}" && _with_comment=0
+
+    # check for sshd in top-level inetd.conf file, and remove
+    # will be replaced by a file in inetd.d/
+    if [ `grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
+    then
+      grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
+      if [ -f "${_inetcnf_tmp}" ]
+      then
+        if mv "${_inetcnf_tmp}" "${_inetcnf}"
+        then
+           csih_inform "Removed sshd from ${_inetcnf}"
+        else
+           csih_warning "Removing sshd from ${_inetcnf} failed!"
+        fi
+        rm -f "${_inetcnf_tmp}"
+      else
+        csih_warning "Removing sshd from ${_inetcnf} failed!"
+      fi
+    fi
+  
+    # Add ssh line to inetd.conf
+    if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -ne 0 ]
+    then
+      if [ "${_with_comment}" -eq 0 ]
+      then
+        echo 'ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
+      else
+        echo '# ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
+      fi
+      csih_inform "Added ssh to ${_inetcnf}"
+    fi
   fi
-}
+} # --- End of update_inetd_conf --- #
 
-# Check options
+# ======================================================================
+# Routine: install_service
+#   Install sshd as a service
+# ======================================================================
+install_service() {
+  local run_service_as
+  local password
 
+  if csih_is_nt
+  then
+    if ! cygrunsrv -Q sshd >/dev/null 2>&1
+    then
+      echo
+      echo
+      csih_warning "The following functions require administrator privileges!"
+      echo
+      echo -e "${_csih_QUERY_STR} Do you want to install sshd as a service?"
+      if csih_request "(Say \"no\" if it is already installed as a service)"
+      then
+       csih_inform "Note that the CYGWIN variable must contain at least \"ntsec\""
+        csih_inform "for sshd to be able to change user context without password."
+        csih_get_cygenv "${cygwin_value}"
+
+        if ( csih_is_nt2003 || [ "$csih_FORCE_PRIVILEGED_USER" = "yes" ] )
+        then
+          csih_inform "On Windows Server 2003, Windows Vista, and above, the"
+          csih_inform "SYSTEM account cannot setuid to other users -- a capability"
+          csih_inform "sshd requires.  You need to have or to create a privileged"
+          csih_inform "account.  This script will help you do so."
+          echo
+          if ! csih_create_privileged_user "${password_value}"
+          then
+            csih_error_recoverable "There was a serious problem creating a privileged user."
+            csih_request "Do you want to proceed anyway?" || exit 1
+          fi
+        fi
+
+        # never returns empty if NT or above
+        run_service_as=$(csih_service_should_run_as)
+
+        if [ "${run_service_as}" = "${csih_PRIVILEGED_USERNAME}" ]
+        then
+          password="${csih_PRIVILEGED_PASSWORD}"
+          if [ -z "${password}" ]
+          then
+            csih_get_value "Please enter the password for user '${run_service_as}':" "-s"
+            password="${csih_value}"
+          fi
+        fi
+
+        # at this point, we either have $run_service_as = "system" and $password is empty,
+        # or $run_service_as is some privileged user and (hopefully) $password contains
+        # the correct password.  So, from here out, we use '-z "${password}"' to discriminate
+        # the two cases.
+
+        csih_check_user "${run_service_as}"
+
+        if [ -z "${password}" ]
+        then
+         if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd -a "-D" -y tcpip \
+             -e CYGWIN="${csih_cygenv}"
+          then
+            echo
+            csih_inform "The sshd service has been installed under the LocalSystem"
+            csih_inform "account (also known as SYSTEM). To start the service now, call"
+            csih_inform "\`net start sshd' or \`cygrunsrv -S sshd'.  Otherwise, it"
+            csih_inform "will start automatically after the next reboot."
+          fi
+        else
+         if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd -a "-D" -y tcpip \
+             -e CYGWIN="${csih_cygenv}" -u "${run_service_as}" -w "${password}"
+          then
+           echo
+           csih_inform "The sshd service has been installed under the '${run_service_as}'"
+           csih_inform "account.  To start the service now, call \`net start sshd' or"
+            csih_inform "\`cygrunsrv -S sshd'.  Otherwise, it will start automatically"
+            csih_inform "after the next reboot."
+          fi
+        fi
+
+        # now, if successfully installed, set ownership of the affected files 
+        if cygrunsrv -Q sshd >/dev/null 2>&1
+        then
+          chown "${run_service_as}" ${SYSCONFDIR}/ssh*
+          chown "${run_service_as}".544 ${LOCALSTATEDIR}/empty
+          chown "${run_service_as}".544 ${LOCALSTATEDIR}/log/lastlog
+          if [ -f ${LOCALSTATEDIR}/log/sshd.log ]
+          then
+           chown "${run_service_as}".544 ${LOCALSTATEDIR}/log/sshd.log
+          fi
+        else
+          csih_warning "Something went wrong installing the sshd service."
+        fi
+      fi # user allowed us to install as service
+    fi # service not yet installed
+  fi # csih_is_nt
+} # --- End of install_service --- #
+
+# ======================================================================
+# Main Entry Point
+# ======================================================================
+
+# Check how the script has been started.  If
+#   (1) it has been started by giving the full path and
+#       that path is /etc/postinstall, OR
+#   (2) Otherwise, if the environment variable
+#       SSH_HOST_CONFIG_AUTO_ANSWER_NO is set
+# then set auto_answer to "no".  This allows automatic
+# creation of the config files in /etc w/o overwriting
+# them if they already exist.  In both cases, color
+# escape sequences are suppressed, so as to prevent
+# cluttering setup's logfiles.
+if [ "$PROGDIR" = "/etc/postinstall" ]
+then
+  csih_auto_answer="no"
+  csih_disable_color
+fi
+if [ -n "${SSH_HOST_CONFIG_AUTO_ANSWER_NO}" ]
+then
+  csih_auto_answer="no"
+  csih_disable_color
+fi
+
+# ======================================================================
+# Parse options
+# ======================================================================
 while :
 do
   case $# in
@@ -62,14 +399,15 @@ do
   case "${option}" in
   -d | --debug )
     set -x
+    csih_trace_on
     ;;
 
   -y | --yes )
-    auto_answer=yes
+    csih_auto_answer=yes
     ;;
 
   -n | --no )
-    auto_answer=no
+    csih_auto_answer=no
     ;;
 
   -c | --cygwin )
@@ -87,6 +425,10 @@ do
     shift
     ;;
 
+  --privileged )
+    csih_FORCE_PRIVILEGED_USER=yes
+    ;;
+
   *)
     echo "usage: ${progname} [OPTION]..."
     echo
@@ -98,7 +440,9 @@ do
     echo "  --no     -n            Answer all questions with \"no\" automatically."
     echo "  --cygwin -c <options>  Use \"options\" as value for CYGWIN environment var."
     echo "  --port   -p <n>        sshd listens on port n."
-    echo "  --pwd    -w <passwd>   Use \"pwd\" as password for user 'sshd_server'."
+    echo "  --pwd    -w <passwd>   Use \"pwd\" as password for privileged user."
+    echo "  --privileged           On Windows NT/2k/XP, require privileged user"
+    echo "                         instead of LocalSystem for sshd service."
     echo
     exit 1
     ;;
@@ -106,73 +450,34 @@ do
   esac
 done
 
-# Check if running on NT
-_sys="`uname`"
-_nt=`expr "${_sys}" : "CYGWIN_NT"`
-# If running on NT, check if running under 2003 Server or later
-if [ ${_nt} -gt 0 ]
-then
-  _nt2003=`uname | awk -F- '{print ( $2 >= 5.2 ) ? 1 : 0;}'`
-fi
+# ======================================================================
+# Action!
+# ======================================================================
 
 # Check for running ssh/sshd processes first. Refuse to do anything while
 # some ssh processes are still running
-
 if ps -ef | grep -v grep | grep -q ssh
 then
   echo
-  echo "There are still ssh processes running. Please shut them down first."
-  echo
-  exit 1
+  csih_error "There are still ssh processes running. Please shut them down first."
 fi
 
 # Check for ${SYSCONFDIR} directory
+csih_make_dir "${SYSCONFDIR}" "Cannot create global configuration files."
+chmod 775 "${SYSCONFDIR}"
+setfacl -m u:system:rwx "${SYSCONFDIR}"
 
-if [ -e "${SYSCONFDIR}" -a ! -d "${SYSCONFDIR}" ]
-then
-  echo
-  echo "${SYSCONFDIR} exists but is not a directory."
-  echo "Cannot create global configuration files."
-  echo
-  exit 1
-fi
-
-# Create it if necessary
-
-if [ ! -e "${SYSCONFDIR}" ]
-then
-  mkdir "${SYSCONFDIR}"
-  if [ ! -e "${SYSCONFDIR}" ]
-  then
-    echo
-    echo "Creating ${SYSCONFDIR} directory failed"
-    echo
-    exit 1
-  fi
-fi
-
-# Create /var/log and /var/log/lastlog if not already existing
-
-if [ -e ${LOCALSTATEDIR}/log -a ! -d ${LOCALSTATEDIR}/log ]
-then
-  echo
-  echo "${LOCALSTATEDIR}/log exists but is not a directory."
-  echo "Cannot create ssh host configuration."
-  echo
-  exit 1
-fi
-if [ ! -e ${LOCALSTATEDIR}/log ]
-then
-  mkdir -p ${LOCALSTATEDIR}/log
-fi
+# Check for /var/log directory
+csih_make_dir "${LOCALSTATEDIR}/log" "Cannot create log directory."
+chmod 775 "${LOCALSTATEDIR}/log"
+setfacl -m u:system:rwx "${LOCALSTATEDIR}/log"
 
+# Create /var/log/lastlog if not already exists
 if [ -e ${LOCALSTATEDIR}/log/lastlog -a ! -f ${LOCALSTATEDIR}/log/lastlog ]
 then
   echo 
-  echo "${LOCALSTATEDIR}/log/lastlog exists, but is not a file."
-  echo "Cannot create ssh host configuration."
-  echo 
-  exit 1
+  csih_error_multi "${LOCALSTATEDIR}/log/lastlog exists, but is not a file." \
+                   "Cannot create ssh host configuration."
 fi
 if [ ! -e ${LOCALSTATEDIR}/log/lastlog ]
 then
@@ -181,443 +486,44 @@ then
 fi
 
 # Create /var/empty file used as chroot jail for privilege separation
-if [ -e ${LOCALSTATEDIR}/empty -a ! -d ${LOCALSTATEDIR}/empty ]
-then
-  echo
-  echo "${LOCALSTATEDIR}/empty exists but is not a directory."
-  echo "Cannot create ssh host configuration."
-  echo
-  exit 1
-if [ ! -e ${LOCALSTATEDIR}/empty ]
-then
-  if ! mkdir -p ${LOCALSTATEDIR}/empty
-  then
-    echo
-    echo "Creating ${LOCALSTATEDIR}/empty directory failed."
-    echo "Cannot create ssh host configuration."
-    echo
-    exit 1
-  fi
-  if [ ${_nt} -gt 0 ]
-  then
-    chmod 755 ${LOCALSTATEDIR}/empty
-  fi
-fi
+csih_make_dir "${LOCALSTATEDIR}/empty" "Cannot create log directory."
+chmod 755 "${LOCALSTATEDIR}/empty"
+setfacl -m u:system:rwx "${LOCALSTATEDIR}/empty"
 
-# First generate host keys if not already existing
+# host keys
+create_host_keys
 
-if [ ! -f "${SYSCONFDIR}/ssh_host_key" ]
-then
-  echo "Generating ${SYSCONFDIR}/ssh_host_key"
-  ssh-keygen -t rsa1 -f ${SYSCONFDIR}/ssh_host_key -N '' > /dev/null
-fi
-
-if [ ! -f "${SYSCONFDIR}/ssh_host_rsa_key" ]
-then
-  echo "Generating ${SYSCONFDIR}/ssh_host_rsa_key"
-  ssh-keygen -t rsa -f ${SYSCONFDIR}/ssh_host_rsa_key -N '' > /dev/null
-fi
-
-if [ ! -f "${SYSCONFDIR}/ssh_host_dsa_key" ]
-then
-  echo "Generating ${SYSCONFDIR}/ssh_host_dsa_key"
-  ssh-keygen -t dsa -f ${SYSCONFDIR}/ssh_host_dsa_key -N '' > /dev/null
-fi
+# use 'cmp' program to determine if a config file is identical
+# to the default version of that config file
+csih_check_program_or_error cmp diffutils
 
-# Check if ssh_config exists. If yes, ask for overwriting
 
-if [ -f "${SYSCONFDIR}/ssh_config" ]
+# handle ssh_config
+csih_install_config "${SYSCONFDIR}/ssh_config"   "${SYSCONFDIR}/defaults"
+if cmp "${SYSCONFDIR}/ssh_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/ssh_config" >/dev/null 2>&1
 then
-  if request "Overwrite existing ${SYSCONFDIR}/ssh_config file?"
-  then
-    rm -f "${SYSCONFDIR}/ssh_config"
-    if [ -f "${SYSCONFDIR}/ssh_config" ]
-    then
-      echo "Can't overwrite. ${SYSCONFDIR}/ssh_config is write protected."
-    fi
-  fi
-fi
-
-# Create default ssh_config from skeleton file in /etc/defaults/etc
-
-if [ ! -f "${SYSCONFDIR}/ssh_config" ]
-then
-  echo "Generating ${SYSCONFDIR}/ssh_config file"
-  cp ${SYSCONFDIR}/defaults/etc/ssh_config ${SYSCONFDIR}/ssh_config
   if [ "${port_number}" != "22" ]
   then
+    csih_inform "Updating ${SYSCONFDIR}/ssh_config file with requested port"
     echo "Host localhost" >> ${SYSCONFDIR}/ssh_config
     echo "    Port ${port_number}" >> ${SYSCONFDIR}/ssh_config
   fi
 fi
 
-# Check if sshd_config exists. If yes, ask for overwriting
-
-if [ -f "${SYSCONFDIR}/sshd_config" ]
+# handle sshd_config (and privsep)
+csih_install_config "${SYSCONFDIR}/sshd_config"   "${SYSCONFDIR}/defaults"
+if ! cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
 then
-  if request "Overwrite existing ${SYSCONFDIR}/sshd_config file?"
-  then
-    rm -f "${SYSCONFDIR}/sshd_config"
-    if [ -f "${SYSCONFDIR}/sshd_config" ]
-    then
-      echo "Can't overwrite. ${SYSCONFDIR}/sshd_config is write protected."
-    fi
-  else
-    grep -q UsePrivilegeSeparation ${SYSCONFDIR}/sshd_config && privsep_configured=yes
-  fi
+  grep -q UsePrivilegeSeparation ${SYSCONFDIR}/sshd_config && privsep_configured=yes
 fi
+sshd_privsep
 
-# Prior to creating or modifying sshd_config, care for privilege separation
 
-if [ "${privsep_configured}" != "yes" ]
-then
-  if [ ${_nt} -gt 0 ]
-  then
-    echo "Privilege separation is set to yes by default since OpenSSH 3.3."
-    echo "However, this requires a non-privileged account called 'sshd'."
-    echo "For more info on privilege separation read /usr/share/doc/openssh/README.privsep."
-    echo
-    if request "Should privilege separation be used?"
-    then
-      privsep_used=yes
-      grep -q '^sshd:' ${SYSCONFDIR}/passwd && sshd_in_passwd=yes
-      net user sshd >/dev/null 2>&1 && sshd_in_sam=yes
-      if [ "${sshd_in_passwd}" != "yes" ]
-      then
-       if [ "${sshd_in_sam}" != "yes" ]
-       then
-         echo "Warning: The following function requires administrator privileges!"
-         if request "Should this script create a local user 'sshd' on this machine?"
-         then
-           dos_var_empty=`cygpath -w ${LOCALSTATEDIR}/empty`
-           net user sshd /add /fullname:"sshd privsep" "/homedir:${dos_var_empty}" /active:no > /dev/null 2>&1 && sshd_in_sam=yes
-           if [ "${sshd_in_sam}" != "yes" ]
-           then
-             echo "Warning: Creating the user 'sshd' failed!"
-           fi
-         fi
-       fi
-       if [ "${sshd_in_sam}" != "yes" ]
-       then
-         echo "Warning: Can't create user 'sshd' in ${SYSCONFDIR}/passwd!"
-         echo "         Privilege separation set to 'no' again!"
-         echo "         Check your ${SYSCONFDIR}/sshd_config file!"
-         privsep_used=no
-       else
-         mkpasswd -l -u sshd | sed -e 's/bash$/false/' >> ${SYSCONFDIR}/passwd
-       fi
-      fi
-    else
-      privsep_used=no
-    fi
-  else
-    # On 9x don't use privilege separation.  Since security isn't
-    # available it just adds useless additional processes.
-    privsep_used=no
-  fi
-fi
-
-# Create default sshd_config from skeleton files in /etc/defaults/etc or
-# modify to add the missing privsep configuration option
-
-if [ ! -f "${SYSCONFDIR}/sshd_config" ]
-then
-  echo "Generating ${SYSCONFDIR}/sshd_config file"
-  sed -e "s/^#UsePrivilegeSeparation yes/UsePrivilegeSeparation ${privsep_used}/
-         s/^#Port 22/Port ${port_number}/
-         s/^#StrictModes yes/StrictModes no/" \
-      < ${SYSCONFDIR}/defaults/etc/sshd_config \
-      > ${SYSCONFDIR}/sshd_config
-elif [ "${privsep_configured}" != "yes" ]
-then
-  echo >> ${SYSCONFDIR}/sshd_config
-  echo "UsePrivilegeSeparation ${privsep_used}" >> ${SYSCONFDIR}/sshd_config
-fi
-
-# Care for services file
-_my_etcdir="/ssh-host-config.$$"
-if [ ${_nt} -gt 0 ]
-then
-  _win_etcdir="${SYSTEMROOT}\\system32\\drivers\\etc"
-  _services="${_my_etcdir}/services"
-  # On NT, 27 spaces, no space after the hash
-  _spaces="                           #"
-else
-  _win_etcdir="${WINDIR}"
-  _services="${_my_etcdir}/SERVICES"
-  # On 9x, 18 spaces (95 is very touchy), a space after the hash
-  _spaces="                  # "
-fi
-_serv_tmp="${_my_etcdir}/srv.out.$$"
-
-mount -t -f "${_win_etcdir}" "${_my_etcdir}"
 
-# Depends on the above mount
-_wservices=`cygpath -w "${_services}"`
-
-# Remove sshd 22/port from services
-if [ `grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ]
-then
-  grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}"
-  if [ -f "${_serv_tmp}" ]
-  then
-    if mv "${_serv_tmp}" "${_services}"
-    then
-      echo "Removing sshd from ${_wservices}"
-    else
-      echo "Removing sshd from ${_wservices} failed!"
-    fi
-    rm -f "${_serv_tmp}"
-  else
-    echo "Removing sshd from ${_wservices} failed!"
-  fi
-fi
-
-# Add ssh 22/tcp  and ssh 22/udp to services
-if [ `grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ]
-then
-  if awk '{ if ( $2 ~ /^23\/tcp/ ) print "ssh                22/tcp'"${_spaces}"'SSH Remote Login Protocol\nssh                22/udp'"${_spaces}"'SSH Remote Login Protocol"; print $0; }' < "${_services}" > "${_serv_tmp}"
-  then
-    if mv "${_serv_tmp}" "${_services}"
-    then
-      echo "Added ssh to ${_wservices}"
-    else
-      echo "Adding ssh to ${_wservices} failed!"
-    fi
-    rm -f "${_serv_tmp}"
-  else
-    echo "WARNING: Adding ssh to ${_wservices} failed!"
-  fi
-fi
-
-umount "${_my_etcdir}"
-
-# Care for inetd.conf file
-_inetcnf="${SYSCONFDIR}/inetd.conf"
-_inetcnf_tmp="${SYSCONFDIR}/inetd.conf.$$"
-
-if [ -f "${_inetcnf}" ]
-then
-  # Check if ssh service is already in use as sshd
-  with_comment=1
-  grep -q '^[ \t]*sshd' "${_inetcnf}" && with_comment=0
-  # Remove sshd line from inetd.conf
-  if [ `grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
-  then
-    grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
-    if [ -f "${_inetcnf_tmp}" ]
-    then
-      if mv "${_inetcnf_tmp}" "${_inetcnf}"
-      then
-       echo "Removed sshd from ${_inetcnf}"
-      else
-       echo "Removing sshd from ${_inetcnf} failed!"
-      fi
-      rm -f "${_inetcnf_tmp}"
-    else
-      echo "Removing sshd from ${_inetcnf} failed!"
-    fi
-  fi
-
-  # Add ssh line to inetd.conf
-  if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -ne 0 ]
-  then
-    if [ "${with_comment}" -eq 0 ]
-    then
-      echo 'ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
-    else
-      echo '# ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
-    fi
-    echo "Added ssh to ${_inetcnf}"
-  fi
-fi
-
-# On NT ask if sshd should be installed as service
-if [ ${_nt} -gt 0 ]
-then
-  # But only if it is not already installed
-  if ! cygrunsrv -Q sshd > /dev/null 2>&1
-  then
-    echo
-    echo
-    echo "Warning: The following functions require administrator privileges!"
-    echo
-    echo "Do you want to install sshd as service?"
-    if request "(Say \"no\" if it's already installed as service)"
-    then
-      if [ $_nt2003 -gt 0 ]
-      then
-       grep -q '^sshd_server:' ${SYSCONFDIR}/passwd && sshd_server_in_passwd=yes
-       if [ "${sshd_server_in_passwd}" = "yes" ]
-       then
-         # Drop sshd_server from passwd since it could have wrong settings
-         grep -v '^sshd_server:' ${SYSCONFDIR}/passwd > ${SYSCONFDIR}/passwd.$$
-         rm -f ${SYSCONFDIR}/passwd
-         mv ${SYSCONFDIR}/passwd.$$ ${SYSCONFDIR}/passwd
-         chmod g-w,o-w ${SYSCONFDIR}/passwd
-       fi
-       net user sshd_server >/dev/null 2>&1 && sshd_server_in_sam=yes
-       if [ "${sshd_server_in_sam}" != "yes" ]
-       then
-         echo
-         echo "You appear to be running Windows 2003 Server or later.  On 2003 and"
-         echo "later systems, it's not possible to use the LocalSystem account"
-         echo "if sshd should allow passwordless logon (e. g. public key authentication)."
-         echo "If you want to enable that functionality, it's required to create a new"
-         echo "account 'sshd_server' with special privileges, which is then used to run"
-         echo "the sshd service under."
-         echo
-         echo "Should this script create a new local account 'sshd_server' which has"
-         if request "the required privileges?"
-         then
-           _admingroup=`mkgroup -l | awk -F: '{if ( $2 == "S-1-5-32-544" ) print $1;}' `
-           if [ -z "${_admingroup}" ]
-           then
-             echo "mkgroup -l produces no group with SID S-1-5-32-544 (Local administrators group)."
-             exit 1
-           fi
-           dos_var_empty=`cygpath -w ${LOCALSTATEDIR}/empty`
-           while [ "${sshd_server_in_sam}" != "yes" ]
-           do
-             if [ -n "${password_value}" ]
-             then
-               _password="${password_value}"
-               # Allow to ask for password if first try fails
-               password_value=""
-             else
-               echo
-               echo "Please enter a password for new user 'sshd_server'.  Please be sure that"
-               echo "this password matches the password rules given on your system."
-               echo -n "Entering no password will exit the configuration.  PASSWORD="
-               read -e _password
-               if [ -z "${_password}" ]
-               then
-                 echo
-                 echo "Exiting configuration.  No user sshd_server has been created,"
-                 echo "no sshd service installed."
-                 exit 1
-               fi
-             fi
-             net user sshd_server "${_password}" /add /fullname:"sshd server account" "/homedir:${dos_var_empty}" /yes > /tmp/nu.$$ 2>&1 && sshd_server_in_sam=yes
-             if [ "${sshd_server_in_sam}" != "yes" ]
-             then
-               echo "Creating the user 'sshd_server' failed!  Reason:"
-               cat /tmp/nu.$$
-               rm /tmp/nu.$$
-             fi
-           done
-           net localgroup "${_admingroup}" sshd_server /add > /dev/null 2>&1 && sshd_server_in_admingroup=yes
-           if [ "${sshd_server_in_admingroup}" != "yes" ]
-           then
-             echo "WARNING: Adding user sshd_server to local group ${_admingroup} failed!"
-             echo "Please add sshd_server to local group ${_admingroup} before"
-             echo "starting the sshd service!"
-             echo
-           fi
-           passwd_has_expiry_flags=`passwd -v | awk '/^passwd /{print ( $3 >= 1.5 ) ? "yes" : "no";}'`
-           if [ "${passwd_has_expiry_flags}" != "yes" ]
-           then
-             echo
-             echo "WARNING: User sshd_server has password expiry set to system default."
-             echo "Please check that password never expires or set it to your needs."
-           elif ! passwd -e sshd_server
-           then
-             echo
-             echo "WARNING: Setting password expiry for user sshd_server failed!"
-             echo "Please check that password never expires or set it to your needs."
-           fi
-           editrights -a SeAssignPrimaryTokenPrivilege -u sshd_server &&
-           editrights -a SeCreateTokenPrivilege -u sshd_server &&
-           editrights -a SeTcbPrivilege -u sshd_server &&
-           editrights -a SeDenyInteractiveLogonRight -u sshd_server &&
-           editrights -a SeDenyNetworkLogonRight -u sshd_server &&
-           editrights -a SeDenyRemoteInteractiveLogonRight -u sshd_server &&
-           editrights -a SeIncreaseQuotaPrivilege -u sshd_server &&
-           editrights -a SeServiceLogonRight -u sshd_server &&
-           sshd_server_got_all_rights="yes"
-           if [ "${sshd_server_got_all_rights}" != "yes" ]
-           then
-             echo
-             echo "Assigning the appropriate privileges to user 'sshd_server' failed!"
-             echo "Can't create sshd service!"
-             exit 1
-           fi
-           echo
-           echo "User 'sshd_server' has been created with password '${_password}'."
-           echo "If you change the password, please keep in mind to change the password"
-           echo "for the sshd service, too."
-           echo
-           echo "Also keep in mind that the user sshd_server needs read permissions on all"
-           echo "users' .ssh/authorized_keys file to allow public key authentication for"
-           echo "these users!.  (Re-)running ssh-user-config for each user will set the"
-           echo "required permissions correctly."
-           echo
-         fi
-       fi
-       if [ "${sshd_server_in_sam}" = "yes" ]
-       then
-         mkpasswd -l -u sshd_server | sed -e 's/bash$/false/' >> ${SYSCONFDIR}/passwd
-       fi
-      fi
-      if [ -n "${cygwin_value}" ]
-      then
-       _cygwin="${cygwin_value}"
-      else
-       echo
-       echo "Which value should the environment variable CYGWIN have when"
-       echo "sshd starts? It's recommended to set at least \"ntsec\" to be"
-       echo "able to change user context without password."
-       echo -n "Default is \"ntsec\".  CYGWIN="
-       read -e _cygwin
-      fi
-      [ -z "${_cygwin}" ] && _cygwin="ntsec"
-      if [ $_nt2003 -gt 0 -a "${sshd_server_in_sam}" = "yes" ]
-      then
-       if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd -a -D -u sshd_server -w "${_password}" -e "CYGWIN=${_cygwin}" -y tcpip
-       then
-         echo
-         echo "The service has been installed under sshd_server account."
-         echo "To start the service, call \`net start sshd' or \`cygrunsrv -S sshd'."
-       fi
-      else
-       if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd -a -D -e "CYGWIN=${_cygwin}" -y tcpip
-       then
-         echo
-         echo "The service has been installed under LocalSystem account."
-         echo "To start the service, call \`net start sshd' or \`cygrunsrv -S sshd'."
-       fi
-      fi
-    fi
-    # Now check if sshd has been successfully installed.  This allows to
-    # set the ownership of the affected files correctly.
-    if cygrunsrv -Q sshd > /dev/null 2>&1
-    then
-      if [ $_nt2003 -gt 0 -a "${sshd_server_in_sam}" = "yes" ]
-      then
-       _user="sshd_server"
-      else
-       _user="system"
-      fi
-      chown "${_user}" ${SYSCONFDIR}/ssh*
-      chown "${_user}".544 ${LOCALSTATEDIR}/empty
-      chown "${_user}".544 ${LOCALSTATEDIR}/log/lastlog
-      if [ -f ${LOCALSTATEDIR}/log/sshd.log ]
-      then
-       chown "${_user}".544 ${LOCALSTATEDIR}/log/sshd.log
-      fi
-    fi
-    if ! ( mount | egrep -q 'on /(|usr/(bin|lib)) type system' )
-    then
-      echo
-      echo "Warning: It appears that you have user mode mounts (\"Just me\""
-      echo "chosen during install.)  Any daemons installed as services will"
-      echo "fail to function unless system mounts are used.  To change this,"
-      echo "re-run setup.exe and choose \"All users\"."
-      echo
-      echo "For more information, see http://cygwin.com/faq/faq0.html#TOC33"
-    fi
-  fi
-fi
+update_services_file 
+update_inetd_conf
+install_service
 
 echo
-echo "Host configuration finished. Have fun!"
+csih_inform "Host configuration finished. Have fun!"
+
index 9482efe9e7a41ef1808c6bfc8cc8f8bd296bb7cb..f210bd556cf414f77d2115a2c1b6308ab2986b07 100644 (file)
-#!/bin/sh
+#!/bin/bash
 #
 # ssh-user-config, Copyright 2000, 2001, 2002, 2003, Red Hat Inc.
 #
 # This file is part of the Cygwin port of OpenSSH.
 
+# ======================================================================
+# Initialization
+# ======================================================================
+PROGNAME=$(basename -- $0)
+_tdir=$(dirname -- $0)
+PROGDIR=$(cd $_tdir && pwd)
+
+CSIH_SCRIPT=/usr/share/csih/cygwin-service-installation-helper.sh
+
+# Subdirectory where the new package is being installed
+PREFIX=/usr
+
 # Directory where the config files are stored
 SYSCONFDIR=/etc
 
-progname=$0
-auto_answer=""
+source ${CSIH_SCRIPT}
+
 auto_passphrase="no"
 passphrase=""
+pwdhome=
+with_passphrase=
+
+# ======================================================================
+# Routine: create_ssh1_identity
+#   optionally create ~/.ssh/identity[.pub]
+#   optionally add result to ~/.ssh/authorized_keys
+# ======================================================================
+create_ssh1_identity() {
+  if [ ! -f "${pwdhome}/.ssh/identity" ]
+  then
+    if csih_request "Shall I create an SSH1 RSA identity file for you?"
+    then
+      csih_inform "Generating ${pwdhome}/.ssh/identity"
+      if [ "${with_passphrase}" = "yes" ]
+      then
+        ssh-keygen -t rsa1 -N "${passphrase}" -f "${pwdhome}/.ssh/identity" > /dev/null
+      else
+        ssh-keygen -t rsa1 -f "${pwdhome}/.ssh/identity" > /dev/null
+      fi
+      if csih_request "Do you want to use this identity to login to this machine?"
+      then
+        csih_inform "Adding to ${pwdhome}/.ssh/authorized_keys"
+        cat "${pwdhome}/.ssh/identity.pub" >> "${pwdhome}/.ssh/authorized_keys"
+      fi
+    fi
+  fi
+} # === End of create_ssh1_identity() === #
+readonly -f create_ssh1_identity
+
+# ======================================================================
+# Routine: create_ssh2_rsa_identity
+#   optionally create ~/.ssh/id_rsa[.pub]
+#   optionally add result to ~/.ssh/authorized_keys
+# ======================================================================
+create_ssh2_rsa_identity() {
+  if [ ! -f "${pwdhome}/.ssh/id_rsa" ]
+  then
+    if csih_request "Shall I create an SSH2 RSA identity file for you?"
+    then
+      csih_inform "Generating ${pwdhome}/.ssh/id_rsa"
+      if [ "${with_passphrase}" = "yes" ]
+      then
+        ssh-keygen -t rsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_rsa" > /dev/null
+      else
+        ssh-keygen -t rsa -f "${pwdhome}/.ssh/id_rsa" > /dev/null
+      fi
+      if csih_request "Do you want to use this identity to login to this machine?"
+      then
+        csih_inform "Adding to ${pwdhome}/.ssh/authorized_keys"
+        cat "${pwdhome}/.ssh/id_rsa.pub" >> "${pwdhome}/.ssh/authorized_keys"
+      fi
+    fi
+  fi
+} # === End of create_ssh2_rsa_identity() === #
+readonly -f create_ssh2_rsa_identity
+
+# ======================================================================
+# Routine: create_ssh2_dsa_identity
+#   optionally create ~/.ssh/id_dsa[.pub]
+#   optionally add result to ~/.ssh/authorized_keys
+# ======================================================================
+create_ssh2_dsa_identity() {
+  if [ ! -f "${pwdhome}/.ssh/id_dsa" ]
+  then
+    if csih_request "Shall I create an SSH2 DSA identity file for you?"
+    then
+      csih_inform "Generating ${pwdhome}/.ssh/id_dsa"
+      if [ "${with_passphrase}" = "yes" ]
+      then
+        ssh-keygen -t dsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_dsa" > /dev/null
+      else
+        ssh-keygen -t dsa -f "${pwdhome}/.ssh/id_dsa" > /dev/null
+      fi
+      if csih_request "Do you want to use this identity to login to this machine?"
+      then
+        csih_inform "Adding to ${pwdhome}/.ssh/authorized_keys"
+        cat "${pwdhome}/.ssh/id_dsa.pub" >> "${pwdhome}/.ssh/authorized_keys"
+      fi
+    fi
+  fi
+} # === End of create_ssh2_dsa_identity() === #
+readonly -f create_ssh2_dsa_identity
+
+# ======================================================================
+# Routine: check_user_homedir
+#   Perform various checks on the user's home directory
+# SETS GLOBAL VARIABLE:
+#   pwdhome
+# ======================================================================
+check_user_homedir() {
+  local uid=$(id -u)
+  pwdhome=$(awk -F: '{ if ( $3 == '${uid}' ) print $6; }' < ${SYSCONFDIR}/passwd)
+  if [ "X${pwdhome}" = "X" ]
+  then
+    csih_error_multiline \
+      "There is no home directory set for you in ${SYSCONFDIR}/passwd." \
+      'Setting $HOME is not sufficient!'
+  fi
+  
+  if [ ! -d "${pwdhome}" ]
+  then
+    csih_error_multiline \
+      "${pwdhome} is set in ${SYSCONFDIR}/passwd as your home directory" \
+      'but it is not a valid directory. Cannot create user identity files.'
+  fi
+  
+  # If home is the root dir, set home to empty string to avoid error messages
+  # in subsequent parts of that script.
+  if [ "X${pwdhome}" = "X/" ]
+  then
+    # But first raise a warning!
+    csih_warning "Your home directory in ${SYSCONFDIR}/passwd is set to root (/). This is not recommended!"
+    if csih_request "Would you like to proceed anyway?"
+    then
+      pwdhome=''
+    else
+      csih_warning "Exiting. Configuration is not complete"
+      exit 1
+    fi
+  fi
+  
+  if [ -d "${pwdhome}" -a csih_is_nt -a -n "`chmod -c g-w,o-w "${pwdhome}"`" ]
+  then
+    echo
+    csih_warning 'group and other have been revoked write permission to your home'
+    csih_warning "directory ${pwdhome}."
+    csih_warning 'This is required by OpenSSH to allow public key authentication using'
+    csih_warning 'the key files stored in your .ssh subdirectory.'
+    csih_warning 'Revert this change ONLY if you know what you are doing!'
+    echo
+  fi
+} # === End of check_user_homedir() === #
+readonly -f check_user_homedir
 
-request()
-{
-  if [ "${auto_answer}" = "yes" ]
+# ======================================================================
+# Routine: check_user_dot_ssh_dir
+#   Perform various checks on the ~/.ssh directory
+# PREREQUISITE:
+#   pwdhome -- check_user_homedir()
+# ======================================================================
+check_user_dot_ssh_dir() {
+  if [ -e "${pwdhome}/.ssh" -a ! -d "${pwdhome}/.ssh" ]
   then
-    return 0
-  elif [ "${auto_answer}" = "no" ]
+    csih_error "${pwdhome}/.ssh is existant but not a directory. Cannot create user identity files."
+  fi
+  
+  if [ ! -e "${pwdhome}/.ssh" ]
   then
-    return 1
+    mkdir "${pwdhome}/.ssh"
+    if [ ! -e "${pwdhome}/.ssh" ]
+    then
+      csih_error "Creating users ${pwdhome}/.ssh directory failed"
+    fi
   fi
+} # === End of check_user_dot_ssh_dir() === #
+readonly -f check_user_dot_ssh_dir
 
-  answer=""
-  while [ "X${answer}" != "Xyes" -a "X${answer}" != "Xno" ]
-  do
-    echo -n "$1 (yes/no) "
-    read answer
-  done
-  if [ "X${answer}" = "Xyes" ]
+# ======================================================================
+# Routine: fix_authorized_keys_perms
+#   Corrects the permissions of ~/.ssh/authorized_keys
+# PREREQUISITE:
+#   pwdhome   -- check_user_homedir()
+# ======================================================================
+fix_authorized_keys_perms() {
+  if [ csih_is_nt -a -e "${pwdhome}/.ssh/authorized_keys" ]
   then
-    return 0
-  else
-    return 1
+    if ! setfacl -m "u::rw-,g::---,o::---" "${pwdhome}/.ssh/authorized_keys"
+    then
+      csih_warning "Setting correct permissions to ${pwdhome}/.ssh/authorized_keys"
+      csih_warning "failed.  Please care for the correct permissions.  The minimum requirement"
+      csih_warning "is, the owner needs read permissions."
+      echo
+    fi
   fi
-}
+} # === End of fix_authorized_keys_perms() === #
+readonly -f fix_authorized_keys_perms
+
+
+# ======================================================================
+# Main Entry Point
+# ======================================================================
 
-# Check if running on NT
-_sys="`uname -a`"
-_nt=`expr "$_sys" : "CYGWIN_NT"`
-# If running on NT, check if running under 2003 Server or later
-if [ $_nt -gt 0 ]
+# Check how the script has been started.  If
+#   (1) it has been started by giving the full path and
+#       that path is /etc/postinstall, OR
+#   (2) Otherwise, if the environment variable
+#       SSH_USER_CONFIG_AUTO_ANSWER_NO is set
+# then set auto_answer to "no".  This allows automatic
+# creation of the config files in /etc w/o overwriting
+# them if they already exist.  In both cases, color
+# escape sequences are suppressed, so as to prevent
+# cluttering setup's logfiles.
+if [ "$PROGDIR" = "/etc/postinstall" ]
 then
-  _nt2003=`uname | awk -F- '{print ( $2 >= 5.2 ) ? 1 : 0;}'`
+  csih_auto_answer="no"
+  csih_disable_color
+fi
+if [ -n "${SSH_USER_CONFIG_AUTO_ANSWER_NO}" ]
+then
+  csih_auto_answer="no"
+  csih_disable_color
 fi
 
-# Check options
-
+# ======================================================================
+# Parse options
+# ======================================================================
 while :
 do
   case $# in
@@ -61,14 +244,15 @@ do
   case "$option" in
   -d | --debug )
     set -x
+    csih_trace_on
     ;;
 
   -y | --yes )
-    auto_answer=yes
+    csih_auto_answer=yes
     ;;
 
   -n | --no )
-    auto_answer=no
+    csih_auto_answer=no
     ;;
 
   -p | --passphrase )
@@ -77,8 +261,12 @@ do
     shift
     ;;
 
+  --privileged )
+    csih_FORCE_PRIVILEGED_USER=yes
+    ;;
+
   *)
-    echo "usage: ${progname} [OPTION]..."
+    echo "usage: ${PROGNAME} [OPTION]..."
     echo
     echo "This script creates an OpenSSH user configuration."
     echo
@@ -87,6 +275,8 @@ do
     echo "    --yes        -y        Answer all questions with \"yes\" automatically."
     echo "    --no         -n        Answer all questions with \"no\" automatically."
     echo "    --passphrase -p word   Use \"word\" as passphrase automatically."
+    echo "    --privileged           On Windows NT/2k/XP, assume privileged user"
+    echo "                           instead of LocalSystem for sshd service."
     echo
     exit 1
     ;;
@@ -94,157 +284,27 @@ do
   esac
 done
 
-# Ask user if user identity should be generated
+# ======================================================================
+# Action!
+# ======================================================================
 
+# Check passwd file
 if [ ! -f ${SYSCONFDIR}/passwd ]
 then
-  echo "${SYSCONFDIR}/passwd is nonexistant. Please generate an ${SYSCONFDIR}/passwd file"
-  echo 'first using mkpasswd. Check if it contains an entry for you and'
-  echo 'please care for the home directory in your entry as well.'
-  exit 1
-fi
-
-uid=`id -u`
-pwdhome=`awk -F: '{ if ( $3 == '${uid}' ) print $6; }' < ${SYSCONFDIR}/passwd`
-
-if [ "X${pwdhome}" = "X" ]
-then
-  echo "There is no home directory set for you in ${SYSCONFDIR}/passwd."
-  echo 'Setting $HOME is not sufficient!'
-  exit 1
-fi
-
-if [ ! -d "${pwdhome}" ]
-then
-  echo "${pwdhome} is set in ${SYSCONFDIR}/passwd as your home directory"
-  echo 'but it is not a valid directory. Cannot create user identity files.'
-  exit 1
-fi
-
-# If home is the root dir, set home to empty string to avoid error messages
-# in subsequent parts of that script.
-if [ "X${pwdhome}" = "X/" ]
-then
-  # But first raise a warning!
-  echo "Your home directory in ${SYSCONFDIR}/passwd is set to root (/). This is not recommended!"
-  if request "Would you like to proceed anyway?"
-  then
-    pwdhome=''
-  else
-    exit 1
-  fi
-fi
-
-if [ -d "${pwdhome}" -a $_nt -gt 0 -a -n "`chmod -c g-w,o-w "${pwdhome}"`" ]
-then
-  echo
-  echo 'WARNING: group and other have been revoked write permission to your home'
-  echo "         directory ${pwdhome}."
-  echo '         This is required by OpenSSH to allow public key authentication using'
-  echo '         the key files stored in your .ssh subdirectory.'
-  echo '         Revert this change ONLY if you know what you are doing!'
-  echo
-fi
-
-if [ -e "${pwdhome}/.ssh" -a ! -d "${pwdhome}/.ssh" ]
-then
-  echo "${pwdhome}/.ssh is existant but not a directory. Cannot create user identity files."
-  exit 1
-fi
-
-if [ ! -e "${pwdhome}/.ssh" ]
-then
-  mkdir "${pwdhome}/.ssh"
-  if [ ! -e "${pwdhome}/.ssh" ]
-  then
-    echo "Creating users ${pwdhome}/.ssh directory failed"
-    exit 1
-  fi
-fi
-
-if [ $_nt -gt 0 ]
-then
-  _user="system"
-  if [ $_nt2003 -gt 0 ]
-  then
-    grep -q '^sshd_server:' ${SYSCONFDIR}/passwd && _user="sshd_server"
-  fi
-  if ! setfacl -m "u::rwx,u:${_user}:r--,g::---,o::---" "${pwdhome}/.ssh"
-  then
-    echo "${pwdhome}/.ssh couldn't be given the correct permissions."
-    echo "Please try to solve this problem first."
-    exit 1
-  fi
-fi
-
-if [ ! -f "${pwdhome}/.ssh/identity" ]
-then
-  if request "Shall I create an SSH1 RSA identity file for you?"
-  then
-    echo "Generating ${pwdhome}/.ssh/identity"
-    if [ "${with_passphrase}" = "yes" ]
-    then
-      ssh-keygen -t rsa1 -N "${passphrase}" -f "${pwdhome}/.ssh/identity" > /dev/null
-    else
-      ssh-keygen -t rsa1 -f "${pwdhome}/.ssh/identity" > /dev/null
-    fi
-    if request "Do you want to use this identity to login to this machine?"
-    then
-      echo "Adding to ${pwdhome}/.ssh/authorized_keys"
-      cat "${pwdhome}/.ssh/identity.pub" >> "${pwdhome}/.ssh/authorized_keys"
-    fi
-  fi
+  csih_error_multiline \
+    "${SYSCONFDIR}/passwd is nonexistant. Please generate an ${SYSCONFDIR}/passwd file" \
+    'first using mkpasswd. Check if it contains an entry for you and' \
+    'please care for the home directory in your entry as well.'
 fi
 
-if [ ! -f "${pwdhome}/.ssh/id_rsa" ]
-then
-  if request "Shall I create an SSH2 RSA identity file for you?"
-  then
-    echo "Generating ${pwdhome}/.ssh/id_rsa"
-    if [ "${with_passphrase}" = "yes" ]
-    then
-      ssh-keygen -t rsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_rsa" > /dev/null
-    else
-      ssh-keygen -t rsa -f "${pwdhome}/.ssh/id_rsa" > /dev/null
-    fi
-    if request "Do you want to use this identity to login to this machine?"
-    then
-      echo "Adding to ${pwdhome}/.ssh/authorized_keys"
-      cat "${pwdhome}/.ssh/id_rsa.pub" >> "${pwdhome}/.ssh/authorized_keys"
-    fi
-  fi
-fi
+check_user_homedir
+check_user_dot_ssh_dir
+create_ssh1_identity
+create_ssh2_rsa_identity
+create_ssh2_dsa_identity
+fix_authorized_keys_perms
 
-if [ ! -f "${pwdhome}/.ssh/id_dsa" ]
-then
-  if request "Shall I create an SSH2 DSA identity file for you?"
-  then
-    echo "Generating ${pwdhome}/.ssh/id_dsa"
-    if [ "${with_passphrase}" = "yes" ]
-    then
-      ssh-keygen -t dsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_dsa" > /dev/null
-    else
-      ssh-keygen -t dsa -f "${pwdhome}/.ssh/id_dsa" > /dev/null
-    fi
-    if request "Do you want to use this identity to login to this machine?"
-    then
-      echo "Adding to ${pwdhome}/.ssh/authorized_keys"
-      cat "${pwdhome}/.ssh/id_dsa.pub" >> "${pwdhome}/.ssh/authorized_keys"
-    fi
-  fi
-fi
+echo
+csih_inform "Configuration finished. Have fun!"
 
-if [ $_nt -gt 0 -a -e "${pwdhome}/.ssh/authorized_keys" ]
-then
-  if ! setfacl -m "u::rw-,u:${_user}:r--,g::---,o::---" "${pwdhome}/.ssh/authorized_keys"
-  then
-    echo
-    echo "WARNING: Setting correct permissions to ${pwdhome}/.ssh/authorized_keys"
-    echo "failed.  Please care for the correct permissions.  The minimum requirement"
-    echo "is, the owner and ${_user} both need read permissions."
-    echo
-  fi
-fi
 
-echo
-echo "Configuration finished. Have fun!"
diff --git a/openssh/contrib/cygwin/sshd-inetd b/openssh/contrib/cygwin/sshd-inetd
new file mode 100644 (file)
index 0000000..aa6bf07
--- /dev/null
@@ -0,0 +1,4 @@
+# This file can be used to enable sshd as a slave of the inetd service
+# To do so, the line below should be uncommented.
+@COMMENT@ ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i
+
index 28f3fdadaae18c103e40461c226957c576a8f8c5..bb9e4d616c98357375180ad9d6d5d74d71a43c70 100644 (file)
@@ -1,4 +1,4 @@
-%define ver 5.0p1
+%define ver 5.1p1
 %define rel 1
 
 # OpenSSH privilege separation requires a user & group ID
@@ -376,6 +376,7 @@ fi
 %attr(0755,root,root) %{_sbindir}/sshd
 %attr(0755,root,root) %{_libexecdir}/openssh/sftp-server
 %attr(0644,root,root) %{_mandir}/man8/sshd.8*
+%attr(0644,root,root) %{_mandir}/man5/moduli.5*
 %attr(0644,root,root) %{_mandir}/man5/sshd_config.5*
 %attr(0644,root,root) %{_mandir}/man8/sftp-server.8*
 %attr(0755,root,root) %dir %{_sysconfdir}/ssh
index 4e8c1e3326e37eea1d3bf0593f26ec604f6780a9..7bd9e05694c8a5811f33372ee683d8e3ffe9bc05 100644 (file)
@@ -13,7 +13,7 @@
 
 Summary:       OpenSSH, a free Secure Shell (SSH) protocol implementation
 Name:          openssh
-Version:       5.0p1
+Version:       5.1p1
 URL:           http://www.openssh.com/
 Release:       1
 Source0:       openssh-%{version}.tar.gz
@@ -201,7 +201,7 @@ fi
 %files
 %defattr(-,root,root)
 %doc ChangeLog OVERVIEW README*
-%doc RFC.nroff TODO CREDITS LICENCE
+%doc TODO CREDITS LICENCE
 %attr(0755,root,root) %dir %{_sysconfdir}/ssh
 %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config
 %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config
@@ -228,6 +228,7 @@ fi
 %attr(0644,root,root) %doc %{_mandir}/man1/ssh-agent.1*
 %attr(0644,root,root) %doc %{_mandir}/man1/ssh-keygen.1*
 %attr(0644,root,root) %doc %{_mandir}/man1/ssh-keyscan.1*
+%attr(0644,root,root) %doc %{_mandir}/man5/moduli.5*
 %attr(0644,root,root) %doc %{_mandir}/man5/ssh_config.5*
 %attr(0644,root,root) %doc %{_mandir}/man5/sshd_config.5*
 %attr(0644,root,root) %doc %{_mandir}/man8/sftp-server.8*
index ee5649dc5f6201428a153a0dbed26020b306dacd..febc590602756998241ddf03dcd80211d5c1d087 100644 (file)
@@ -431,10 +431,6 @@ struct winsize {
 # define __attribute__(x)
 #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
 
-#ifndef __dead
-# define __dead        __attribute__((noreturn))
-#endif
-
 #if !defined(HAVE_ATTRIBUTE__SENTINEL__) && !defined(__sentinel__)
 # define __sentinel__
 #endif
@@ -590,6 +586,15 @@ struct winsize {
 # define SSH_SYSFDMAX 10000
 #endif
 
+#ifdef FSID_HAS_VAL
+/* encode f_fsid into a 64 bit value  */
+#define FSID_TO_ULONG(f) \
+       ((((u_int64_t)(f).val[0] & 0xffffffffUL) << 32) | \
+           ((f).val[1] & 0xffffffffUL))
+#else
+# define FSID_TO_ULONG(f) ((f))
+#endif
+
 #if defined(__Lynx__)
  /*
   * LynxOS defines these in param.h which we do not want to include since
@@ -729,4 +734,8 @@ struct winsize {
 # endif
 #endif
 
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK EAGAIN
+#endif
+
 #endif /* _DEFINES_H */
index 66858104cb9383916fc4a76409ed94042c446261..b76605325deab1455fbf9c730c92e05b30469449 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: dh.c,v 1.45 2007/09/27 00:15:57 ray Exp $ */
+/* $OpenBSD: dh.c,v 1.47 2008/06/26 09:19:39 djm Exp $ */
 /*
  * Copyright (c) 2000 Niels Provos.  All rights reserved.
  *
@@ -46,6 +46,7 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
        char *cp, *arg;
        char *strsize, *gen, *prime;
        const char *errstr = NULL;
+       long long n;
 
        cp = line;
        if ((arg = strdelim(&cp)) == NULL)
@@ -62,12 +63,24 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
        arg = strsep(&cp, " "); /* type */
        if (cp == NULL || *arg == '\0')
                goto fail;
+       /* Ensure this is a safe prime */
+       n = strtonum(arg, 0, 5, &errstr);
+       if (errstr != NULL || n != MODULI_TYPE_SAFE)
+               goto fail;
        arg = strsep(&cp, " "); /* tests */
        if (cp == NULL || *arg == '\0')
                goto fail;
+       /* Ensure prime has been tested and is not composite */
+       n = strtonum(arg, 0, 0x1f, &errstr);
+       if (errstr != NULL ||
+           (n & MODULI_TESTS_COMPOSITE) || !(n & ~MODULI_TESTS_COMPOSITE))
+               goto fail;
        arg = strsep(&cp, " "); /* tries */
        if (cp == NULL || *arg == '\0')
                goto fail;
+       n = strtonum(arg, 0, 1<<30, &errstr);
+       if (errstr != NULL || n == 0)
+               goto fail;
        strsize = strsep(&cp, " "); /* size */
        if (cp == NULL || *strsize == '\0' ||
            (dhg->size = (u_int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 ||
@@ -153,7 +166,7 @@ choose_dh(int min, int wantbits, int max)
        }
 
        linenum = 0;
-       which = arc4random() % bestcount;
+       which = arc4random_uniform(bestcount);
        while (fgets(line, sizeof(line), f)) {
                if (!parse_prime(linenum, line, &dhg))
                        continue;
index 8e580ee87ded15a08e5294ea6a7be47a38d52a25..dfc1480eac66798c32483656f5a78d2fa2c525d3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: dh.h,v 1.9 2006/03/25 22:22:43 djm Exp $ */
+/* $OpenBSD: dh.h,v 1.10 2008/06/26 09:19:40 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Niels Provos.  All rights reserved.
@@ -46,4 +46,28 @@ int   dh_estimate(int);
 #define DH_GRP_MIN     1024
 #define DH_GRP_MAX     8192
 
+/*
+ * Values for "type" field of moduli(5)
+ * Specifies the internal structure of the prime modulus.
+ */
+#define MODULI_TYPE_UNKNOWN            (0)
+#define MODULI_TYPE_UNSTRUCTURED       (1)
+#define MODULI_TYPE_SAFE               (2)
+#define MODULI_TYPE_SCHNORR            (3)
+#define MODULI_TYPE_SOPHIE_GERMAIN     (4)
+#define MODULI_TYPE_STRONG             (5)
+
+/*
+ * Values for "tests" field of moduli(5)
+ * Specifies the methods used in checking for primality.
+ * Usually, more than one test is used.
+ */
+#define MODULI_TESTS_UNTESTED          (0x00)
+#define MODULI_TESTS_COMPOSITE         (0x01)
+#define MODULI_TESTS_SIEVE             (0x02)
+#define MODULI_TESTS_MILLER_RABIN      (0x04)
+#define MODULI_TESTS_JACOBI            (0x08)
+#define MODULI_TESTS_ELLIPTIC          (0x10)
+
+
 #endif
index a89176f882835c2931261ff909a934af7efa4e39..a7da03fa3efd14ce5feb2199995a2f344d01dbe0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.24 2007/01/03 03:01:40 stevesk Exp $ */
+/* $OpenBSD: dns.c,v 1.25 2008/06/12 00:03:49 dtucker Exp $ */
 
 /*
  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -145,11 +145,20 @@ is_numeric_hostname(const char *hostname)
 {
        struct addrinfo hints, *ai;
 
+       /*
+        * We shouldn't ever get a null host but if we do then log an error
+        * and return -1 which stops DNS key fingerprint processing.
+        */
+       if (hostname == NULL) {
+               error("is_numeric_hostname called with NULL hostname");
+               return -1;
+       }
+
        memset(&hints, 0, sizeof(hints));
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_flags = AI_NUMERICHOST;
 
-       if (getaddrinfo(hostname, "0", &hints, &ai) == 0) {
+       if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) {
                freeaddrinfo(ai);
                return -1;
        }
index e73f62b22fdf29bfa6ac29a54f7abc8aef5d87cf..2381aeb15b57edf4deefacd0084ba5697a522149 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: groupaccess.c,v 1.12 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: groupaccess.c,v 1.13 2008/07/04 03:44:59 djm Exp $ */
 /*
  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
  *
@@ -31,6 +31,7 @@
 #include <grp.h>
 #include <unistd.h>
 #include <stdarg.h>
+#include <string.h>
 
 #include "xmalloc.h"
 #include "groupaccess.h"
@@ -87,6 +88,30 @@ ga_match(char * const *groups, int n)
        return 0;
 }
 
+/*
+ * Return 1 if one of user's groups matches group_pattern list.
+ * Return 0 on negated or no match.
+ */
+int
+ga_match_pattern_list(const char *group_pattern)
+{
+       int i, found = 0;
+       size_t len = strlen(group_pattern);
+
+       for (i = 0; i < ngroups; i++) {
+               switch (match_pattern_list(groups_byname[i],
+                   group_pattern, len, 0)) {
+               case -1:
+                       return 0;       /* Negated match wins */
+               case 0:
+                       continue;
+               case 1:
+                       found = 1;
+               }
+       }
+       return found;
+}
+
 /*
  * Free memory allocated for group access list.
  */
index 04b4498940161059726c293857c018f57c452368..000578e76461df6ccbef1dcad35f3399f40ac68d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: groupaccess.h,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: groupaccess.h,v 1.8 2008/07/04 03:44:59 djm Exp $ */
 
 /*
  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
@@ -29,6 +29,7 @@
 
 int     ga_init(const char *, gid_t);
 int     ga_match(char * const *, int);
+int     ga_match_pattern_list(const char *);
 void    ga_free(void);
 
 #endif
index bc498fd47eb2144d7c3cb17dc87ae4ed863d3c3f..2ec7ea19c2da3fb41f1ed55ba02d94ef56ab5117 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: gss-serv.c,v 1.21 2007/06/12 08:20:00 djm Exp $ */
+/* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "buffer.h"
 #include "key.h"
index 9fcf1b023287c0965f0263086da78085cc666aee..f1b47f666d038b69aa98721b4d455b6094a48210 100644 (file)
 # include <sys/syslog.h>
 #endif
 
+#include <errno.h>
+
 /*
  * On HP-UX 11.11, shadow.h and prot.h provide conflicting declarations
  * of getspnam when _INCLUDE__STDC__ is defined, so we unset it here.
index 62bf8361d6791caea9bae2be052eb3ae125cc269..2ea13d27d1b1ef8156c935679e7e61a82b7aa79d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.c,v 1.69 2007/07/12 05:48:05 ray Exp $ */
+/* $OpenBSD: key.c,v 1.78 2008/07/07 23:32:51 stevesk Exp $ */
 /*
  * read_bignum():
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -11,6 +11,7 @@
  *
  *
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,6 +36,7 @@
 
 #include "includes.h"
 
+#include <sys/param.h>
 #include <sys/types.h>
 
 #include <openssl/evp.h>
@@ -172,6 +174,7 @@ key_equal(const Key *a, const Key *b)
        default:
                fatal("key_equal: bad key type %d", a->type);
        }
+       /* NOTREACHED */
 }
 
 u_char*
@@ -295,6 +298,114 @@ key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len)
        return retval;
 }
 
+/*
+ * Draw an ASCII-Art representing the fingerprint so human brain can
+ * profit from its built-in pattern recognition ability.
+ * This technique is called "random art" and can be found in some
+ * scientific publications like this original paper:
+ *
+ * "Hash Visualization: a New Technique to improve Real-World Security",
+ * Perrig A. and Song D., 1999, International Workshop on Cryptographic
+ * Techniques and E-Commerce (CrypTEC '99)
+ * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
+ *
+ * The subject came up in a talk by Dan Kaminsky, too.
+ *
+ * If you see the picture is different, the key is different.
+ * If the picture looks the same, you still know nothing.
+ *
+ * The algorithm used here is a worm crawling over a discrete plane,
+ * leaving a trace (augmenting the field) everywhere it goes.
+ * Movement is taken from dgst_raw 2bit-wise.  Bumping into walls
+ * makes the respective movement vector be ignored for this turn.
+ * Graphs are not unambiguous, because circles in graphs can be
+ * walked in either direction.
+ */
+
+/*
+ * Field sizes for the random art.  Have to be odd, so the starting point
+ * can be in the exact middle of the picture, and FLDBASE should be >=8 .
+ * Else pictures would be too dense, and drawing the frame would
+ * fail, too, because the key type would not fit in anymore.
+ */
+#define        FLDBASE         8
+#define        FLDSIZE_Y       (FLDBASE + 1)
+#define        FLDSIZE_X       (FLDBASE * 2 + 1)
+static char *
+key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k)
+{
+       /*
+        * Chars to be used after each other every time the worm
+        * intersects with itself.  Matter of taste.
+        */
+       char    *augmentation_string = " .o+=*BOX@%&#/^SE";
+       char    *retval, *p;
+       u_char   field[FLDSIZE_X][FLDSIZE_Y];
+       u_int    i, b;
+       int      x, y;
+       size_t   len = strlen(augmentation_string) - 1;
+
+       retval = xcalloc(1, (FLDSIZE_X + 3) * (FLDSIZE_Y + 2));
+
+       /* initialize field */
+       memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
+       x = FLDSIZE_X / 2;
+       y = FLDSIZE_Y / 2;
+
+       /* process raw key */
+       for (i = 0; i < dgst_raw_len; i++) {
+               int input;
+               /* each byte conveys four 2-bit move commands */
+               input = dgst_raw[i];
+               for (b = 0; b < 4; b++) {
+                       /* evaluate 2 bit, rest is shifted later */
+                       x += (input & 0x1) ? 1 : -1;
+                       y += (input & 0x2) ? 1 : -1;
+
+                       /* assure we are still in bounds */
+                       x = MAX(x, 0);
+                       y = MAX(y, 0);
+                       x = MIN(x, FLDSIZE_X - 1);
+                       y = MIN(y, FLDSIZE_Y - 1);
+
+                       /* augment the field */
+                       field[x][y]++;
+                       input = input >> 2;
+               }
+       }
+
+       /* mark starting point and end point*/
+       field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
+       field[x][y] = len;
+
+       /* fill in retval */
+       snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", key_type(k), key_size(k));
+       p = strchr(retval, '\0');
+
+       /* output upper border */
+       for (i = p - retval - 1; i < FLDSIZE_X; i++)
+               *p++ = '-';
+       *p++ = '+';
+       *p++ = '\n';
+
+       /* output content */
+       for (y = 0; y < FLDSIZE_Y; y++) {
+               *p++ = '|';
+               for (x = 0; x < FLDSIZE_X; x++)
+                       *p++ = augmentation_string[MIN(field[x][y], len)];
+               *p++ = '|';
+               *p++ = '\n';
+       }
+
+       /* output lower border */
+       *p++ = '+';
+       for (i = 0; i < FLDSIZE_X; i++)
+               *p++ = '-';
+       *p++ = '+';
+
+       return retval;
+}
+
 char *
 key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
 {
@@ -312,6 +423,9 @@ key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
        case SSH_FP_BUBBLEBABBLE:
                retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
                break;
+       case SSH_FP_RANDOMART:
+               retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k);
+               break;
        default:
                fatal("key_fingerprint_ex: bad digest representation %d",
                    dgst_rep);
index 6873dd7933e947e176f18d0f1b3239dae2c10093..14aac79c2de07d69cf9be3d6640cfecad378852c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.h,v 1.26 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: key.h,v 1.27 2008/06/11 21:01:35 grunk Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -42,7 +42,8 @@ enum fp_type {
 };
 enum fp_rep {
        SSH_FP_HEX,
-       SSH_FP_BUBBLEBABBLE
+       SSH_FP_BUBBLEBABBLE,
+       SSH_FP_RANDOMART
 };
 
 /* key is stored in external hardware */
index fae5b043f3e55701a9ca1d8a99aa9791e2513bff..4a8239b931de474319b3cb21420eedbfaaeccc30 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.c,v 1.40 2007/05/17 07:50:31 djm Exp $ */
+/* $OpenBSD: log.c,v 1.41 2008/06/10 04:50:25 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -114,6 +114,17 @@ log_facility_number(char *name)
        return SYSLOG_FACILITY_NOT_SET;
 }
 
+const char *
+log_facility_name(SyslogFacility facility)
+{
+       u_int i;
+
+       for (i = 0;  log_facilities[i].name; i++)
+               if (log_facilities[i].val == facility)
+                       return log_facilities[i].name;
+       return NULL;
+}
+
 LogLevel
 log_level_number(char *name)
 {
@@ -126,6 +137,17 @@ log_level_number(char *name)
        return SYSLOG_LEVEL_NOT_SET;
 }
 
+const char *
+log_level_name(LogLevel level)
+{
+       u_int i;
+
+       for (i = 0; log_levels[i].name != NULL; i++)
+               if (log_levels[i].val == level)
+                       return log_levels[i].name;
+       return NULL;
+}
+
 /* Error messages that should be logged. */
 
 void
index 7a8c57079cca6242938bc18ce901143c5996be43..650582791113b2d72e48faeda6353238a6d29707 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: log.h,v 1.15 2006/08/18 09:13:25 deraadt Exp $ */
+/* $OpenBSD: log.h,v 1.17 2008/06/13 00:12:02 dtucker Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -49,11 +49,15 @@ typedef enum {
 void     log_init(char *, LogLevel, SyslogFacility, int);
 
 SyslogFacility log_facility_number(char *);
-LogLevel log_level_number(char *);
+const char *   log_facility_name(SyslogFacility);
+LogLevel       log_level_number(char *);
+const char *   log_level_name(LogLevel);
 
-void     fatal(const char *, ...) __dead __attribute__((format(printf, 1, 2)));
+void     fatal(const char *, ...) __attribute__((noreturn))
+    __attribute__((format(printf, 1, 2)));
 void     error(const char *, ...) __attribute__((format(printf, 1, 2)));
-void     sigdie(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     sigdie(const char *, ...)  __attribute__((noreturn))
+    __attribute__((format(printf, 1, 2)));
 void     logit(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     verbose(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     debug(const char *, ...) __attribute__((format(printf, 1, 2)));
@@ -61,5 +65,5 @@ void     debug2(const char *, ...) __attribute__((format(printf, 1, 2)));
 void     debug3(const char *, ...) __attribute__((format(printf, 1, 2)));
 
 void    do_log(LogLevel, const char *, va_list);
-void    cleanup_exit(int) __dead;
+void    cleanup_exit(int) __attribute__((noreturn));
 #endif
index 34464659ad66ca17aa7f70c7aa8e98f54f0475a2..fabc3ed661da8d532eaeaecbc57f4da67b8c06be 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mac.c,v 1.14 2007/06/07 19:37:34 pvalchev Exp $ */
+/* $OpenBSD: mac.c,v 1.15 2008/06/13 00:51:47 dtucker Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  *
@@ -128,7 +128,7 @@ mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
 
        if (mac->mac_len > sizeof(m))
                fatal("mac_compute: mac too long %u %lu",
-                   mac->mac_len, sizeof(m));
+                   mac->mac_len, (u_long)sizeof(m));
 
        switch (mac->type) {
        case SSH_EVP:
index e3c993073fd80799073a935c667d184c57dcf3b9..2389477789043df3384bfcad1e4858279b99cf5d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: match.c,v 1.26 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: match.c,v 1.27 2008/06/10 23:06:19 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -183,7 +183,8 @@ match_hostname(const char *host, const char *pattern, u_int len)
 
 /*
  * returns 0 if we get a negative match for the hostname or the ip
- * or if we get no match at all.  returns 1 otherwise.
+ * or if we get no match at all.  returns -1 on error, or 1 on
+ * successful match.
  */
 int
 match_host_and_ip(const char *host, const char *ipaddr,
@@ -191,9 +192,12 @@ match_host_and_ip(const char *host, const char *ipaddr,
 {
        int mhost, mip;
 
-       /* negative ipaddr match */
-       if ((mip = match_hostname(ipaddr, patterns, strlen(patterns))) == -1)
+       /* error in ipaddr match */
+       if ((mip = addr_match_list(ipaddr, patterns)) == -2)
+               return -1;
+       else if (mip == -1) /* negative ip address match */
                return 0;
+
        /* negative hostname match */
        if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1)
                return 0;
index d1d53865433a7be9ab6def8a876d33592dcad36c..18f6830703b7174f4b08b9515576b30502730590 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: match.h,v 1.13 2006/03/25 22:22:43 djm Exp $ */
+/* $OpenBSD: match.h,v 1.14 2008/06/10 03:57:27 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -21,4 +21,7 @@ int    match_host_and_ip(const char *, const char *, const char *);
 int     match_user(const char *, const char *, const char *, const char *);
 char   *match_list(const char *, const char *, u_int *);
 
+/* addrmatch.c */
+int     addr_match_list(const char *, const char *);
+
 #endif
index b4fe489af52febae5a89e874434fb176e348bb53..8b303f16f7720f4a4cb5e344394a627f5bacb6a7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.67 2008/01/01 08:47:04 dtucker Exp $ */
+/* $OpenBSD: misc.c,v 1.69 2008/06/13 01:38:23 dtucker Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2005,2006 Damien Miller.  All rights reserved.
@@ -534,7 +534,7 @@ tilde_expand_filename(const char *filename, uid_t uid)
                if ((pw = getpwnam(user)) == NULL)
                        fatal("tilde_expand_filename: No such user %s", user);
        } else if ((pw = getpwuid(uid)) == NULL)        /* ~/path */
-               fatal("tilde_expand_filename: No such uid %d", uid);
+               fatal("tilde_expand_filename: No such uid %ld", (long)uid);
 
        if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret))
                fatal("tilde_expand_filename: Path too long");
@@ -832,3 +832,23 @@ put_u16(void *vp, u_int16_t v)
        p[0] = (u_char)(v >> 8) & 0xff;
        p[1] = (u_char)v & 0xff;
 }
+
+void
+ms_subtract_diff(struct timeval *start, int *ms)
+{
+       struct timeval diff, finish;
+
+       gettimeofday(&finish, NULL);
+       timersub(&finish, start, &diff);        
+       *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
+}
+
+void
+ms_to_timeval(struct timeval *tv, int ms)
+{
+       if (ms < 0)
+               ms = 0;
+       tv->tv_sec = ms / 1000;
+       tv->tv_usec = (ms % 1000) * 1000;
+}
+
index be05e806b16703a11fe7284996f34f69cb20583f..5da170d2fd82f402a469ca858b6bcedef039bd50 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.h,v 1.37 2007/12/27 14:22:08 dtucker Exp $ */
+/* $OpenBSD: misc.h,v 1.38 2008/06/12 20:38:28 dtucker Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -33,6 +33,8 @@ char  *tilde_expand_filename(const char *, uid_t);
 char   *percent_expand(const char *, ...) __attribute__((__sentinel__));
 char   *tohex(const void *, size_t);
 void    sanitise_stdfd(void);
+void    ms_subtract_diff(struct timeval *, int *);
+void    ms_to_timeval(struct timeval *, int);
 
 struct passwd *pwcopy(struct passwd *);
 const char *ssh_gai_strerror(int);
diff --git a/openssh/moduli.5 b/openssh/moduli.5
new file mode 100644 (file)
index 0000000..4a99439
--- /dev/null
@@ -0,0 +1,124 @@
+.\"    $OpenBSD: moduli.5,v 1.12 2008/06/26 05:57:54 djm Exp $
+.\"
+.\" Copyright (c) 2008 Damien Miller <djm@mindrot.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.Dd $Mdocdate: June 26 2008 $
+.Dt MODULI 5
+.Os
+.Sh NAME
+.Nm moduli
+.Nd Diffie Hellman moduli
+.Sh DESCRIPTION
+The
+.Pa /etc/moduli
+file contains prime numbers and generators for use by 
+.Xr sshd 8
+in the Diffie-Hellman Group Exchange key exchange method.
+.Pp
+New moduli may be generated with
+.Xr ssh-keygen 1
+using a two-step process.
+An initial
+.Em candidate generation
+pass, using 
+.Ic ssh-keygen -G ,
+calculates numbers that are likely to be useful.
+A second
+.Em primality testing
+pass, using
+.Ic ssh-keygen -T
+provides a high degree of assurance that the numbers are prime and are
+safe for use in Diffie Hellman operations by
+.Xr sshd 8 .
+This
+.Nm
+format is used as the output from each pass.
+.Pp
+The file consists of newline-separated records, one per modulus,
+containing seven space separated fields.
+These fields are as follows:
+.Pp
+.Bl -tag -width Description -offset indent
+.It timestamp
+The time that the modulus was last processed as YYYYMMDDHHMMSS.
+.It type
+Decimal number specifying the internal structure of the prime modulus.
+Supported types are:
+.Pp
+.Bl -tag -width 0x00 -compact
+.It 0
+Unknown, not tested
+.It 2
+"Safe" prime; (p-1)/2 is also prime.
+.It 4
+Sophie Germain; (p+1)*2 is also prime.
+.El
+.Pp
+Moduli candidates initially produced by
+.Xr ssh-keygen 1
+are Sophie Germain primes (type 4).
+Futher primality testing with
+.Xr ssh-keygen 1
+produces safe prime moduli (type 2) that are ready for use in
+.Xr sshd 8 .
+Other types are not used by OpenSSH.
+.It tests
+Decimal number indicating the type of primality tests that the number
+has been subjected to represented as a bitmask of the following values:
+.Pp
+.Bl -tag -width 0x00 -compact
+.It 0x00
+Not tested
+.It 0x01
+Composite number - not prime.
+.It 0x02
+Sieve of Eratosthenes
+.It 0x04
+Probabalistic Miller-Rabin primality tests.
+.El
+.Pp
+The
+.Xr ssh-keygen 1
+moduli candidate generation uses the Sieve of Eratosthenes (flag 0x02).
+Subsequent
+.Xr ssh-keygen 1
+primality tests are Miller-Rabin tests (flag 0x04).
+.It trials
+Decimal number indicating of primaility trials that have been performed
+on the modulus.
+.It size
+Decimal number indicating the size of the prime in bits.
+.It generator
+The recommended generator for use with this modulus (hexadecimal).
+.It modulus
+The modulus itself in hexadecimal.
+.El
+.Pp
+When performing Diffie Hellman Group Exchange,
+.Xr sshd 8
+first estimates the size of the modulus required to produce enough
+Diffie Hellman output to sufficiently key the selected symmetric cipher.
+.Xr sshd 8
+then randomly selects a modulus from
+.Fa /etc/moduli
+that best meets the size requirement.
+.Pp
+.Sh SEE ALSO
+.Xr ssh-keygen 1 ,
+.Xr sshd 8 ,
+.Rs
+.%R RFC 4419
+.%T "Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol"
+.%D 2006
+.Re
index 8fa545daf090aea41121aadcb295ce3a8c0272a8..f737cb3f517d2063ac30d4774da4e0d06dcc6677 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: moduli.c,v 1.20 2007/02/24 03:30:11 ray Exp $ */
+/* $OpenBSD: moduli.c,v 1.21 2008/06/26 09:19:40 djm Exp $ */
 /*
  * Copyright 1994 Phil Karn <karn@qualcomm.com>
  * Copyright 1996-1998, 2003 William Allen Simpson <wsimpson@greendragon.com>
@@ -42,6 +42,7 @@
 #include <sys/types.h>
 
 #include <openssl/bn.h>
+#include <openssl/dh.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -50,6 +51,7 @@
 #include <time.h>
 
 #include "xmalloc.h"
+#include "dh.h"
 #include "log.h"
 
 /*
 /* need line long enough for largest moduli plus headers */
 #define QLINESIZE              (100+8192)
 
-/* Type: decimal.
- * Specifies the internal structure of the prime modulus.
- */
-#define QTYPE_UNKNOWN          (0)
-#define QTYPE_UNSTRUCTURED     (1)
-#define QTYPE_SAFE             (2)
-#define QTYPE_SCHNORR          (3)
-#define QTYPE_SOPHIE_GERMAIN   (4)
-#define QTYPE_STRONG           (5)
-
-/* Tests: decimal (bit field).
- * Specifies the methods used in checking for primality.
- * Usually, more than one test is used.
- */
-#define QTEST_UNTESTED         (0x00)
-#define QTEST_COMPOSITE                (0x01)
-#define QTEST_SIEVE            (0x02)
-#define QTEST_MILLER_RABIN     (0x04)
-#define QTEST_JACOBI           (0x08)
-#define QTEST_ELLIPTIC         (0x10)
-
 /*
  * Size: decimal.
  * Specifies the number of the most significant bit (0 to M).
@@ -434,8 +415,9 @@ gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start)
                        fatal("BN_set_word failed");
                if (BN_add(q, q, largebase) == 0)
                        fatal("BN_add failed");
-               if (qfileout(out, QTYPE_SOPHIE_GERMAIN, QTEST_SIEVE,
-                   largetries, (power - 1) /* MSB */, (0), q) == -1) {
+               if (qfileout(out, MODULI_TYPE_SOPHIE_GERMAIN,
+                   MODULI_TESTS_SIEVE, largetries,
+                   (power - 1) /* MSB */, (0), q) == -1) {
                        ret = -1;
                        break;
                }
@@ -507,7 +489,7 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
                /* tests */
                in_tests = strtoul(cp, &cp, 10);
 
-               if (in_tests & QTEST_COMPOSITE) {
+               if (in_tests & MODULI_TESTS_COMPOSITE) {
                        debug2("%10u: known composite", count_in);
                        continue;
                }
@@ -526,7 +508,7 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
 
                /* modulus (hex) */
                switch (in_type) {
-               case QTYPE_SOPHIE_GERMAIN:
+               case MODULI_TYPE_SOPHIE_GERMAIN:
                        debug2("%10u: (%u) Sophie-Germain", count_in, in_type);
                        a = q;
                        if (BN_hex2bn(&a, cp) == 0)
@@ -539,11 +521,11 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
                        in_size += 1;
                        generator_known = 0;
                        break;
-               case QTYPE_UNSTRUCTURED:
-               case QTYPE_SAFE:
-               case QTYPE_SCHNORR:
-               case QTYPE_STRONG:
-               case QTYPE_UNKNOWN:
+               case MODULI_TYPE_UNSTRUCTURED:
+               case MODULI_TYPE_SAFE:
+               case MODULI_TYPE_SCHNORR:
+               case MODULI_TYPE_STRONG:
+               case MODULI_TYPE_UNKNOWN:
                        debug2("%10u: (%u)", count_in, in_type);
                        a = p;
                        if (BN_hex2bn(&a, cp) == 0)
@@ -570,7 +552,7 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
                        continue;
                }
 
-               if (in_tests & QTEST_MILLER_RABIN)
+               if (in_tests & MODULI_TESTS_MILLER_RABIN)
                        in_tries += trials;
                else
                        in_tries = trials;
@@ -644,7 +626,8 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
                }
                debug("%10u: q is almost certainly prime", count_in);
 
-               if (qfileout(out, QTYPE_SAFE, (in_tests | QTEST_MILLER_RABIN),
+               if (qfileout(out, MODULI_TYPE_SAFE,
+                   in_tests | MODULI_TESTS_MILLER_RABIN,
                    in_tries, in_size, generator_known, p)) {
                        res = -1;
                        break;
index cc0e0fcac03c9de8beb188f4bbf63c3a632f4e92..73cf6bc9b9698aba41ac0cbef5aaad3611adf3cf 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.94 2007/10/29 04:08:08 dtucker Exp $ */
+/* $OpenBSD: monitor.c,v 1.99 2008/07/10 18:08:11 markus Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -51,6 +51,7 @@
 
 #include <openssl/dh.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
 #include "key.h"
@@ -1014,6 +1015,8 @@ mm_answer_keyallowed(int sock, Buffer *m)
                        allowed = options.pubkey_authentication &&
                            user_key_allowed(authctxt->pw, key);
                        auth_method = "publickey";
+                       if (options.pubkey_authentication && allowed != 1)
+                               auth_clear_options();
                        break;
                case MM_HOSTKEY:
                        allowed = options.hostbased_authentication &&
@@ -1026,6 +1029,8 @@ mm_answer_keyallowed(int sock, Buffer *m)
                        allowed = options.rhosts_rsa_authentication &&
                            auth_rhosts_rsa_key_allowed(authctxt->pw,
                            cuser, chost, key);
+                       if (options.rhosts_rsa_authentication && allowed != 1)
+                               auth_clear_options();
                        auth_method = "rsa";
                        break;
                default:
@@ -1055,7 +1060,7 @@ mm_answer_keyallowed(int sock, Buffer *m)
        }
 
        debug3("%s: key %p is %s",
-           __func__, key, allowed ? "allowed" : "disallowed");
+           __func__, key, allowed ? "allowed" : "not allowed");
 
        buffer_clear(m);
        buffer_put_int(m, allowed);
@@ -1272,7 +1277,7 @@ mm_session_close(Session *s)
                debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
                session_pty_cleanup2(s);
        }
-       s->used = 0;
+       session_unused(s->self);
 }
 
 int
@@ -1700,7 +1705,7 @@ mm_get_keystate(struct monitor *pmonitor)
        u_char *blob, *p;
        u_int bloblen, plen;
        u_int32_t seqnr, packets;
-       u_int64_t blocks;
+       u_int64_t blocks, bytes;
 
        debug3("%s: Waiting for new keys", __func__);
 
@@ -1733,11 +1738,13 @@ mm_get_keystate(struct monitor *pmonitor)
        seqnr = buffer_get_int(&m);
        blocks = buffer_get_int64(&m);
        packets = buffer_get_int(&m);
-       packet_set_state(MODE_OUT, seqnr, blocks, packets);
+       bytes = buffer_get_int64(&m);
+       packet_set_state(MODE_OUT, seqnr, blocks, packets, bytes);
        seqnr = buffer_get_int(&m);
        blocks = buffer_get_int64(&m);
        packets = buffer_get_int(&m);
-       packet_set_state(MODE_IN, seqnr, blocks, packets);
+       bytes = buffer_get_int64(&m);
+       packet_set_state(MODE_IN, seqnr, blocks, packets, bytes);
 
  skip:
        /* Get the key context */
index 36a07a06df6b2aacf144f52aed4a0c37d4be11b9..c890f77097df624fe014d09431f77ffe4ea410b0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_mm.h,v 1.4 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: monitor_mm.h,v 1.5 2008/04/29 11:20:31 otto Exp $ */
 
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -41,9 +41,6 @@ struct mm_master {
        size_t size;
 
        struct mm_master *mmalloc;      /* Used to completely share */
-
-       int write;              /* used to writing to other party */
-       int read;               /* used for reading from other party */
 };
 
 RB_PROTOTYPE(mmtree, mm_share, next, mm_compare)
index e895f19240ae6971bcee8346d5d35d1f5ef2a986..40463d07800a0e5b505ae6cec98a86a3e14ce67c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.60 2007/10/29 04:08:08 dtucker Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.63 2008/07/10 18:08:11 markus Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -41,6 +41,7 @@
 #include <openssl/bn.h>
 #include <openssl/dh.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
 #include "dh.h"
@@ -572,7 +573,7 @@ mm_send_keystate(struct monitor *monitor)
        u_char *blob, *p;
        u_int bloblen, plen;
        u_int32_t seqnr, packets;
-       u_int64_t blocks;
+       u_int64_t blocks, bytes;
 
        buffer_init(&m);
 
@@ -621,14 +622,16 @@ mm_send_keystate(struct monitor *monitor)
        buffer_put_string(&m, blob, bloblen);
        xfree(blob);
 
-       packet_get_state(MODE_OUT, &seqnr, &blocks, &packets);
+       packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes);
        buffer_put_int(&m, seqnr);
        buffer_put_int64(&m, blocks);
        buffer_put_int(&m, packets);
-       packet_get_state(MODE_IN, &seqnr, &blocks, &packets);
+       buffer_put_int64(&m, bytes);
+       packet_get_state(MODE_IN, &seqnr, &blocks, &packets, &bytes);
        buffer_put_int(&m, seqnr);
        buffer_put_int64(&m, blocks);
        buffer_put_int(&m, packets);
+       buffer_put_int64(&m, bytes);
 
        debug3("%s: New keys have been sent", __func__);
  skip:
@@ -665,7 +668,20 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
 {
        Buffer m;
        char *p, *msg;
-       int success = 0;
+       int success = 0, tmp1 = -1, tmp2 = -1;
+
+       /* Kludge: ensure there are fds free to receive the pty/tty */
+       if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
+           (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
+               error("%s: cannot allocate fds for pty", __func__);
+               if (tmp1 > 0)
+                       close(tmp1);
+               if (tmp2 > 0)
+                       close(tmp2);
+               return 0;
+       }
+       close(tmp1);
+       close(tmp2);
 
        buffer_init(&m);
        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m);
@@ -710,8 +726,9 @@ mm_session_pty_cleanup2(Session *s)
        buffer_free(&m);
 
        /* closed dup'ed master */
-       if (close(s->ptymaster) < 0)
-               error("close(s->ptymaster): %s", strerror(errno));
+       if (s->ptymaster != -1 && close(s->ptymaster) < 0)
+               error("close(s->ptymaster/%d): %s",
+                   s->ptymaster, strerror(errno));
 
        /* unlink pty from session */
        s->ttyfd = -1;
diff --git a/openssh/mux.c b/openssh/mux.c
new file mode 100644 (file)
index 0000000..79f8376
--- /dev/null
@@ -0,0 +1,728 @@
+/* $OpenBSD: mux.c,v 1.7 2008/06/13 17:21:20 dtucker Exp $ */
+/*
+ * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ssh session multiplexing support */
+
+#include "includes.h"
+
+/*
+ * TODO:
+ *   1. partial reads in muxserver_accept_control (maybe make channels
+ *      from accepted connections)
+ *   2. Better signalling from master to slave, especially passing of
+ *      error messages
+ *   3. Better fall-back from mux slave error to new connection.
+ *   3. Add/delete forwardings via slave
+ *   4. ExitOnForwardingFailure (after #3 obviously)
+ *   5. Maybe extension mechanisms for multi-X11/multi-agent forwarding
+ *   6. Document the mux mini-protocol somewhere.
+ *   7. Support ~^Z in mux slaves.
+ *   8. Inspect or control sessions in master.
+ *   9. If we ever support the "signal" channel request, send signals on
+ *      sessions in master.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "ssh.h"
+#include "pathnames.h"
+#include "misc.h"
+#include "match.h"
+#include "buffer.h"
+#include "channels.h"
+#include "msg.h"
+#include "packet.h"
+#include "monitor_fdpass.h"
+#include "sshpty.h"
+#include "key.h"
+#include "readconf.h"
+#include "clientloop.h"
+
+/* from ssh.c */
+extern int tty_flag;
+extern Options options;
+extern int stdin_null_flag;
+extern char *host;
+int subsystem_flag;
+extern Buffer command;
+
+/* Context for session open confirmation callback */
+struct mux_session_confirm_ctx {
+       int want_tty;
+       int want_subsys;
+       int want_x_fwd;
+       int want_agent_fwd;
+       Buffer cmd;
+       char *term;
+       struct termios tio;
+       char **env;
+};
+
+/* fd to control socket */
+int muxserver_sock = -1;
+
+/* Multiplexing control command */
+u_int muxclient_command = 0;
+
+/* Set when signalled. */
+static volatile sig_atomic_t muxclient_terminate = 0;
+
+/* PID of multiplex server */
+static u_int muxserver_pid = 0;
+
+
+/* ** Multiplexing master support */
+
+/* Prepare a mux master to listen on a Unix domain socket. */
+void
+muxserver_listen(void)
+{
+       struct sockaddr_un addr;
+       mode_t old_umask;
+       int addr_len;
+
+       if (options.control_path == NULL ||
+           options.control_master == SSHCTL_MASTER_NO)
+               return;
+
+       debug("setting up multiplex master socket");
+
+       memset(&addr, '\0', sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       addr_len = offsetof(struct sockaddr_un, sun_path) +
+           strlen(options.control_path) + 1;
+
+       if (strlcpy(addr.sun_path, options.control_path,
+           sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
+               fatal("ControlPath too long");
+
+       if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+               fatal("%s socket(): %s", __func__, strerror(errno));
+
+       old_umask = umask(0177);
+       if (bind(muxserver_sock, (struct sockaddr *)&addr, addr_len) == -1) {
+               muxserver_sock = -1;
+               if (errno == EINVAL || errno == EADDRINUSE) {
+                       error("ControlSocket %s already exists, "
+                           "disabling multiplexing", options.control_path);
+                       close(muxserver_sock);
+                       muxserver_sock = -1;
+                       xfree(options.control_path);
+                       options.control_path = NULL;
+                       options.control_master = SSHCTL_MASTER_NO;
+                       return;
+               } else
+                       fatal("%s bind(): %s", __func__, strerror(errno));
+       }
+       umask(old_umask);
+
+       if (listen(muxserver_sock, 64) == -1)
+               fatal("%s listen(): %s", __func__, strerror(errno));
+
+       set_nonblock(muxserver_sock);
+}
+
+/* Callback on open confirmation in mux master for a mux client session. */
+static void
+mux_session_confirm(int id, void *arg)
+{
+       struct mux_session_confirm_ctx *cctx = arg;
+       const char *display;
+       Channel *c;
+       int i;
+
+       if (cctx == NULL)
+               fatal("%s: cctx == NULL", __func__);
+       if ((c = channel_lookup(id)) == NULL)
+               fatal("%s: no channel for id %d", __func__, id);
+
+       display = getenv("DISPLAY");
+       if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
+               char *proto, *data;
+               /* Get reasonable local authentication information. */
+               client_x11_get_proto(display, options.xauth_location,
+                   options.forward_x11_trusted, &proto, &data);
+               /* Request forwarding with authentication spoofing. */
+               debug("Requesting X11 forwarding with authentication spoofing.");
+               x11_request_forwarding_with_spoofing(id, display, proto, data);
+               /* XXX wait for reply */
+       }
+
+       if (cctx->want_agent_fwd && options.forward_agent) {
+               debug("Requesting authentication agent forwarding.");
+               channel_request_start(id, "auth-agent-req@openssh.com", 0);
+               packet_send();
+       }
+
+       client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
+           cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
+
+       c->open_confirm_ctx = NULL;
+       buffer_free(&cctx->cmd);
+       xfree(cctx->term);
+       if (cctx->env != NULL) {
+               for (i = 0; cctx->env[i] != NULL; i++)
+                       xfree(cctx->env[i]);
+               xfree(cctx->env);
+       }
+       xfree(cctx);
+}
+
+/*
+ * Accept a connection on the mux master socket and process the
+ * client's request. Returns flag indicating whether mux master should
+ * begin graceful close.
+ */
+int
+muxserver_accept_control(void)
+{
+       Buffer m;
+       Channel *c;
+       int client_fd, new_fd[3], ver, allowed, window, packetmax;
+       socklen_t addrlen;
+       struct sockaddr_storage addr;
+       struct mux_session_confirm_ctx *cctx;
+       char *cmd;
+       u_int i, j, len, env_len, mux_command, flags, escape_char;
+       uid_t euid;
+       gid_t egid;
+       int start_close = 0;
+
+       /*
+        * Accept connection on control socket
+        */
+       memset(&addr, 0, sizeof(addr));
+       addrlen = sizeof(addr);
+       if ((client_fd = accept(muxserver_sock,
+           (struct sockaddr*)&addr, &addrlen)) == -1) {
+               error("%s accept: %s", __func__, strerror(errno));
+               return 0;
+       }
+
+       if (getpeereid(client_fd, &euid, &egid) < 0) {
+               error("%s getpeereid failed: %s", __func__, strerror(errno));
+               close(client_fd);
+               return 0;
+       }
+       if ((euid != 0) && (getuid() != euid)) {
+               error("control mode uid mismatch: peer euid %u != uid %u",
+                   (u_int) euid, (u_int) getuid());
+               close(client_fd);
+               return 0;
+       }
+
+       /* XXX handle asynchronously */
+       unset_nonblock(client_fd);
+
+       /* Read command */
+       buffer_init(&m);
+       if (ssh_msg_recv(client_fd, &m) == -1) {
+               error("%s: client msg_recv failed", __func__);
+               close(client_fd);
+               buffer_free(&m);
+               return 0;
+       }
+       if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
+               error("%s: wrong client version %d", __func__, ver);
+               buffer_free(&m);
+               close(client_fd);
+               return 0;
+       }
+
+       allowed = 1;
+       mux_command = buffer_get_int(&m);
+       flags = buffer_get_int(&m);
+
+       buffer_clear(&m);
+
+       switch (mux_command) {
+       case SSHMUX_COMMAND_OPEN:
+               if (options.control_master == SSHCTL_MASTER_ASK ||
+                   options.control_master == SSHCTL_MASTER_AUTO_ASK)
+                       allowed = ask_permission("Allow shared connection "
+                           "to %s? ", host);
+               /* continue below */
+               break;
+       case SSHMUX_COMMAND_TERMINATE:
+               if (options.control_master == SSHCTL_MASTER_ASK ||
+                   options.control_master == SSHCTL_MASTER_AUTO_ASK)
+                       allowed = ask_permission("Terminate shared connection "
+                           "to %s? ", host);
+               if (allowed)
+                       start_close = 1;
+               /* FALLTHROUGH */
+       case SSHMUX_COMMAND_ALIVE_CHECK:
+               /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */
+               buffer_clear(&m);
+               buffer_put_int(&m, allowed);
+               buffer_put_int(&m, getpid());
+               if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
+                       error("%s: client msg_send failed", __func__);
+                       close(client_fd);
+                       buffer_free(&m);
+                       return start_close;
+               }
+               buffer_free(&m);
+               close(client_fd);
+               return start_close;
+       default:
+               error("Unsupported command %d", mux_command);
+               buffer_free(&m);
+               close(client_fd);
+               return 0;
+       }
+
+       /* Reply for SSHMUX_COMMAND_OPEN */
+       buffer_clear(&m);
+       buffer_put_int(&m, allowed);
+       buffer_put_int(&m, getpid());
+       if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
+               error("%s: client msg_send failed", __func__);
+               close(client_fd);
+               buffer_free(&m);
+               return 0;
+       }
+
+       if (!allowed) {
+               error("Refused control connection");
+               close(client_fd);
+               buffer_free(&m);
+               return 0;
+       }
+
+       buffer_clear(&m);
+       if (ssh_msg_recv(client_fd, &m) == -1) {
+               error("%s: client msg_recv failed", __func__);
+               close(client_fd);
+               buffer_free(&m);
+               return 0;
+       }
+       if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
+               error("%s: wrong client version %d", __func__, ver);
+               buffer_free(&m);
+               close(client_fd);
+               return 0;
+       }
+
+       cctx = xcalloc(1, sizeof(*cctx));
+       cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
+       cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
+       cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
+       cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
+       cctx->term = buffer_get_string(&m, &len);
+       escape_char = buffer_get_int(&m);
+
+       cmd = buffer_get_string(&m, &len);
+       buffer_init(&cctx->cmd);
+       buffer_append(&cctx->cmd, cmd, strlen(cmd));
+
+       env_len = buffer_get_int(&m);
+       env_len = MIN(env_len, 4096);
+       debug3("%s: receiving %d env vars", __func__, env_len);
+       if (env_len != 0) {
+               cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env));
+               for (i = 0; i < env_len; i++)
+                       cctx->env[i] = buffer_get_string(&m, &len);
+               cctx->env[i] = NULL;
+       }
+
+       debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__,
+           cctx->want_tty, cctx->want_subsys, cmd);
+       xfree(cmd);
+
+       /* Gather fds from client */
+       for(i = 0; i < 3; i++) {
+               if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) {
+                       error("%s: failed to receive fd %d from slave",
+                           __func__, i);
+                       for (j = 0; j < i; j++)
+                               close(new_fd[j]);
+                       for (j = 0; j < env_len; j++)
+                               xfree(cctx->env[j]);
+                       if (env_len > 0)
+                               xfree(cctx->env);
+                       xfree(cctx->term);
+                       buffer_free(&cctx->cmd);
+                       close(client_fd);
+                       xfree(cctx);
+                       return 0;
+               }
+       }
+
+       debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
+           new_fd[0], new_fd[1], new_fd[2]);
+
+       /* Try to pick up ttymodes from client before it goes raw */
+       if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
+               error("%s: tcgetattr: %s", __func__, strerror(errno));
+
+       /* This roundtrip is just for synchronisation of ttymodes */
+       buffer_clear(&m);
+       if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
+               error("%s: client msg_send failed", __func__);
+               close(client_fd);
+               close(new_fd[0]);
+               close(new_fd[1]);
+               close(new_fd[2]);
+               buffer_free(&m);
+               xfree(cctx->term);
+               if (env_len != 0) {
+                       for (i = 0; i < env_len; i++)
+                               xfree(cctx->env[i]);
+                       xfree(cctx->env);
+               }
+               return 0;
+       }
+       buffer_free(&m);
+
+       /* enable nonblocking unless tty */
+       if (!isatty(new_fd[0]))
+               set_nonblock(new_fd[0]);
+       if (!isatty(new_fd[1]))
+               set_nonblock(new_fd[1]);
+       if (!isatty(new_fd[2]))
+               set_nonblock(new_fd[2]);
+
+       set_nonblock(client_fd);
+
+       window = CHAN_SES_WINDOW_DEFAULT;
+       packetmax = CHAN_SES_PACKET_DEFAULT;
+       if (cctx->want_tty) {
+               window >>= 1;
+               packetmax >>= 1;
+       }
+       
+       c = channel_new("session", SSH_CHANNEL_OPENING,
+           new_fd[0], new_fd[1], new_fd[2], window, packetmax,
+           CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
+
+       c->ctl_fd = client_fd;
+       if (cctx->want_tty && escape_char != 0xffffffff) {
+               channel_register_filter(c->self,
+                   client_simple_escape_filter, NULL,
+                   client_filter_cleanup,
+                   client_new_escape_filter_ctx((int)escape_char));
+       }
+
+       debug3("%s: channel_new: %d", __func__, c->self);
+
+       channel_send_open(c->self);
+       channel_register_open_confirm(c->self, mux_session_confirm, cctx);
+       return 0;
+}
+
+/* ** Multiplexing client support */
+
+/* Exit signal handler */
+static void
+control_client_sighandler(int signo)
+{
+       muxclient_terminate = signo;
+}
+
+/*
+ * Relay signal handler - used to pass some signals from mux client to
+ * mux master.
+ */
+static void
+control_client_sigrelay(int signo)
+{
+       int save_errno = errno;
+
+       if (muxserver_pid > 1)
+               kill(muxserver_pid, signo);
+
+       errno = save_errno;
+}
+
+/* Check mux client environment variables before passing them to mux master. */
+static int
+env_permitted(char *env)
+{
+       int i, ret;
+       char name[1024], *cp;
+
+       if ((cp = strchr(env, '=')) == NULL || cp == env)
+               return (0);
+       ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
+       if (ret <= 0 || (size_t)ret >= sizeof(name))
+               fatal("env_permitted: name '%.100s...' too long", env);
+
+       for (i = 0; i < options.num_send_env; i++)
+               if (match_pattern(name, options.send_env[i]))
+                       return (1);
+
+       return (0);
+}
+
+/* Multiplex client main loop. */
+void
+muxclient(const char *path)
+{
+       struct sockaddr_un addr;
+       int i, r, fd, sock, exitval[2], num_env, addr_len;
+       Buffer m;
+       char *term;
+       extern char **environ;
+       u_int allowed, flags;
+
+       if (muxclient_command == 0)
+               muxclient_command = SSHMUX_COMMAND_OPEN;
+
+       switch (options.control_master) {
+       case SSHCTL_MASTER_AUTO:
+       case SSHCTL_MASTER_AUTO_ASK:
+               debug("auto-mux: Trying existing master");
+               /* FALLTHROUGH */
+       case SSHCTL_MASTER_NO:
+               break;
+       default:
+               return;
+       }
+
+       memset(&addr, '\0', sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       addr_len = offsetof(struct sockaddr_un, sun_path) +
+           strlen(path) + 1;
+
+       if (strlcpy(addr.sun_path, path,
+           sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
+               fatal("ControlPath too long");
+
+       if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+               fatal("%s socket(): %s", __func__, strerror(errno));
+
+       if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
+               if (muxclient_command != SSHMUX_COMMAND_OPEN) {
+                       fatal("Control socket connect(%.100s): %s", path,
+                           strerror(errno));
+               }
+               if (errno == ENOENT)
+                       debug("Control socket \"%.100s\" does not exist", path);
+               else {
+                       error("Control socket connect(%.100s): %s", path,
+                           strerror(errno));
+               }
+               close(sock);
+               return;
+       }
+
+       if (stdin_null_flag) {
+               if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
+                       fatal("open(/dev/null): %s", strerror(errno));
+               if (dup2(fd, STDIN_FILENO) == -1)
+                       fatal("dup2: %s", strerror(errno));
+               if (fd > STDERR_FILENO)
+                       close(fd);
+       }
+
+       term = getenv("TERM");
+
+       flags = 0;
+       if (tty_flag)
+               flags |= SSHMUX_FLAG_TTY;
+       if (subsystem_flag)
+               flags |= SSHMUX_FLAG_SUBSYS;
+       if (options.forward_x11)
+               flags |= SSHMUX_FLAG_X11_FWD;
+       if (options.forward_agent)
+               flags |= SSHMUX_FLAG_AGENT_FWD;
+
+       signal(SIGPIPE, SIG_IGN);
+
+       buffer_init(&m);
+
+       /* Send our command to server */
+       buffer_put_int(&m, muxclient_command);
+       buffer_put_int(&m, flags);
+       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
+               error("%s: msg_send", __func__);
+ muxerr:
+               close(sock);
+               buffer_free(&m);
+               if (muxclient_command != SSHMUX_COMMAND_OPEN)
+                       cleanup_exit(255);
+               logit("Falling back to non-multiplexed connection");
+               xfree(options.control_path);
+               options.control_path = NULL;
+               options.control_master = SSHCTL_MASTER_NO;
+               return;
+       }
+       buffer_clear(&m);
+
+       /* Get authorisation status and PID of controlee */
+       if (ssh_msg_recv(sock, &m) == -1) {
+               error("%s: Did not receive reply from master", __func__);
+               goto muxerr;
+       }
+       if (buffer_get_char(&m) != SSHMUX_VER) {
+               error("%s: Master replied with wrong version", __func__);
+               goto muxerr;
+       }
+       if (buffer_get_int_ret(&allowed, &m) != 0) {
+               error("%s: bad server reply", __func__);
+               goto muxerr;
+       }
+       if (allowed != 1) {
+               error("Connection to master denied");
+               goto muxerr;
+       }
+       muxserver_pid = buffer_get_int(&m);
+
+       buffer_clear(&m);
+
+       switch (muxclient_command) {
+       case SSHMUX_COMMAND_ALIVE_CHECK:
+               fprintf(stderr, "Master running (pid=%d)\r\n",
+                   muxserver_pid);
+               exit(0);
+       case SSHMUX_COMMAND_TERMINATE:
+               fprintf(stderr, "Exit request sent.\r\n");
+               exit(0);
+       case SSHMUX_COMMAND_OPEN:
+               buffer_put_cstring(&m, term ? term : "");
+               if (options.escape_char == SSH_ESCAPECHAR_NONE)
+                       buffer_put_int(&m, 0xffffffff);
+               else
+                       buffer_put_int(&m, options.escape_char);
+               buffer_append(&command, "\0", 1);
+               buffer_put_cstring(&m, buffer_ptr(&command));
+
+               if (options.num_send_env == 0 || environ == NULL) {
+                       buffer_put_int(&m, 0);
+               } else {
+                       /* Pass environment */
+                       num_env = 0;
+                       for (i = 0; environ[i] != NULL; i++) {
+                               if (env_permitted(environ[i]))
+                                       num_env++; /* Count */
+                       }
+                       buffer_put_int(&m, num_env);
+               for (i = 0; environ[i] != NULL && num_env >= 0; i++) {
+                               if (env_permitted(environ[i])) {
+                                       num_env--;
+                                       buffer_put_cstring(&m, environ[i]);
+                               }
+                       }
+               }
+               break;
+       default:
+               fatal("unrecognised muxclient_command %d", muxclient_command);
+       }
+
+       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
+               error("%s: msg_send", __func__);
+               goto muxerr;
+       }
+
+       if (mm_send_fd(sock, STDIN_FILENO) == -1 ||
+           mm_send_fd(sock, STDOUT_FILENO) == -1 ||
+           mm_send_fd(sock, STDERR_FILENO) == -1) {
+               error("%s: send fds failed", __func__);
+               goto muxerr;
+       }
+
+       /*
+        * Mux errors are non-recoverable from this point as the master
+        * has ownership of the session now.
+        */
+
+       /* Wait for reply, so master has a chance to gather ttymodes */
+       buffer_clear(&m);
+       if (ssh_msg_recv(sock, &m) == -1)
+               fatal("%s: msg_recv", __func__);
+       if (buffer_get_char(&m) != SSHMUX_VER)
+               fatal("%s: wrong version", __func__);
+       buffer_free(&m);
+
+       signal(SIGHUP, control_client_sighandler);
+       signal(SIGINT, control_client_sighandler);
+       signal(SIGTERM, control_client_sighandler);
+       signal(SIGWINCH, control_client_sigrelay);
+
+       if (tty_flag)
+               enter_raw_mode();
+
+       /*
+        * Stick around until the controlee closes the client_fd.
+        * Before it does, it is expected to write this process' exit
+        * value (one int). This process must read the value and wait for
+        * the closure of the client_fd; if this one closes early, the 
+        * multiplex master will terminate early too (possibly losing data).
+        */
+       exitval[0] = 0;
+       for (i = 0; !muxclient_terminate && i < (int)sizeof(exitval);) {
+               r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
+               if (r == 0) {
+                       debug2("Received EOF from master");
+                       break;
+               }
+               if (r == -1) {
+                       if (errno == EINTR)
+                               continue;
+                       fatal("%s: read %s", __func__, strerror(errno));
+               }
+               i += r;
+       }
+
+       close(sock);
+       leave_raw_mode();
+       if (i > (int)sizeof(int))
+               fatal("%s: master returned too much data (%d > %lu)",
+                   __func__, i, (u_long)sizeof(int));
+       if (muxclient_terminate) {
+               debug2("Exiting on signal %d", muxclient_terminate);
+               exitval[0] = 255;
+       } else if (i < (int)sizeof(int)) {
+               debug2("Control master terminated unexpectedly");
+               exitval[0] = 255;
+       } else
+               debug2("Received exit status from master %d", exitval[0]);
+
+       if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
+               fprintf(stderr, "Shared connection to %s closed.\r\n", host);
+
+       exit(exitval[0]);
+}
index ad461f4af6a36c57362a773601e2f4ea8645653e..e0ebf43f151c74ba7049c2199f89dee62a13f52e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: nchan.c,v 1.57 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: nchan.c,v 1.60 2008/06/30 12:16:02 djm Exp $ */
 /*
  * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl.  All rights reserved.
  *
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <stdarg.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "ssh1.h"
 #include "ssh2.h"
 #include "buffer.h"
@@ -77,6 +78,7 @@ static void   chan_send_ieof1(Channel *);
 static void    chan_send_oclose1(Channel *);
 static void    chan_send_close2(Channel *);
 static void    chan_send_eof2(Channel *);
+static void    chan_send_eow2(Channel *);
 
 /* helper */
 static void    chan_shutdown_write(Channel *);
@@ -305,6 +307,17 @@ chan_rcvd_close2(Channel *c)
                break;
        }
 }
+void
+chan_rcvd_eow(Channel *c)
+{
+       debug2("channel %d: rcvd eow", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_OPEN:
+               chan_shutdown_read(c);
+               chan_set_istate(c, CHAN_INPUT_CLOSED);
+               break;
+       }
+}
 static void
 chan_rcvd_eof2(Channel *c)
 {
@@ -321,6 +334,8 @@ chan_write_failed2(Channel *c)
        case CHAN_OUTPUT_OPEN:
        case CHAN_OUTPUT_WAIT_DRAIN:
                chan_shutdown_write(c);
+               if (strcmp(c->ctype, "session") == 0)
+                       chan_send_eow2(c);
                chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
                break;
        default:
@@ -363,6 +378,21 @@ chan_send_close2(Channel *c)
                c->flags |= CHAN_CLOSE_SENT;
        }
 }
+static void
+chan_send_eow2(Channel *c)
+{
+       debug2("channel %d: send eow", c->self);
+       if (c->ostate == CHAN_OUTPUT_CLOSED) {
+               error("channel %d: must not sent eow on closed output",
+                   c->self);
+               return;
+       }
+       packet_start(SSH2_MSG_CHANNEL_REQUEST);
+       packet_put_int(c->remote_id);
+       packet_put_cstring("eow@openssh.com");
+       packet_put_char(0);
+       packet_send();
+}
 
 /* shared */
 
index a7a67b12701e9ede5b5671c4122a3ca9fc8ac391..700150450adc06255361614dd7b06e7948dee037 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: nchan2.ms,v 1.3 2003/11/21 11:57:03 djm Exp $
+.\"    $OpenBSD: nchan2.ms,v 1.4 2008/05/15 23:52:24 djm Exp $
 .\"
 .\" Copyright (c) 2000 Markus Friedl.  All rights reserved.
 .\"
@@ -44,7 +44,7 @@ arrow from S1.e to S4.n
 box invis "rcvd CLOSE/" "shutdown_read" with .sw at last arrow.c
 arrow "ibuf_empty ||" "rcvd CLOSE/" "send EOF" "" from S2.e to S4.w
 arrow from S1.s to S2.n
-box invis "read_failed/" "shutdown_read" with .e at last arrow.c
+box invis "read_failed ||" "rcvd EOW/" "shutdown_read" with .e at last arrow.c
 ellipse wid .9*ellipsewid ht .9*ellipseht at S4
 arrow "start" "" from S1.w+(-0.5,0) to S1.w
 .PE
@@ -59,7 +59,7 @@ S4: ellipse "OUTPUT" "CLOSED"
 move down l from 1st ellipse.s
 S2: ellipse "OUTPUT" "WAIT" "DRAIN"
 arrow from S1.e to S4.n
-box invis "write_failed/" "shutdown_write" with .sw at last arrow.c
+box invis "write_failed/" "shutdown_write" "send EOW" with .sw at last arrow.c
 arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w
 arrow from S1.s to S2.n
 box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e at last arrow.c
index 1e13be7e1bbb3ddb65c52cdab56c9304f3de3e65..5668dc337a2be17d37fc51c188f1cef8cfcbd4bd 100644 (file)
@@ -16,9 +16,9 @@ RANLIB=@RANLIB@
 INSTALL=@INSTALL@
 LDFLAGS=-L. @LDFLAGS@
 
-OPENBSD=base64.o basename.o bindresvport.o daemon.o dirname.o getcwd.o getgrouplist.o getopt.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strsep.o strtonum.o strtoll.o strtoul.o vis.o
+OPENBSD=base64.o basename.o bindresvport.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strsep.o strtonum.o strtoll.o strtoul.o vis.o
 
-COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-snprintf.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
 
 PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
 
index 08a53b8cd4863898f1f1338fc9705716be70e676..c0d5bdb5c33518bbac44ecd1ec8d5208a5f4c107 100644 (file)
@@ -54,8 +54,8 @@ bindresvport_sa(int sd, struct sockaddr *sa)
 {
        int error, af;
        struct sockaddr_storage myaddr;
-       struct sockaddr_in *sin;
-       struct sockaddr_in6 *sin6;
+       struct sockaddr_in *in;
+       struct sockaddr_in6 *in6;
        u_int16_t *portp;
        u_int16_t port;
        socklen_t salen;
@@ -74,13 +74,13 @@ bindresvport_sa(int sd, struct sockaddr *sa)
                af = sa->sa_family;
 
        if (af == AF_INET) {
-               sin = (struct sockaddr_in *)sa;
+               in = (struct sockaddr_in *)sa;
                salen = sizeof(struct sockaddr_in);
-               portp = &sin->sin_port;
+               portp = &in->sin_port;
        } else if (af == AF_INET6) {
-               sin6 = (struct sockaddr_in6 *)sa;
+               in6 = (struct sockaddr_in6 *)sa;
                salen = sizeof(struct sockaddr_in6);
-               portp = &sin6->sin6_port;
+               portp = &in6->sin6_port;
        } else {
                errno = EPFNOSUPPORT;
                return (-1);
index d45fb182a6fb9725bb8794d7f7b947a8bf2f6c7a..9d4c8690eb18b37d7549011c0cafc504ba7ea9fb 100644 (file)
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 
 #include <string.h>
+#include <stdlib.h>
 #include <stdarg.h>
 
 #include "log.h"
@@ -82,3 +83,68 @@ arc4random_stir(void)
        rc4_ready = REKEY_BYTES;
 }
 #endif /* !HAVE_ARC4RANDOM */
+
+#ifndef ARC4RANDOM_BUF
+void
+arc4random_buf(void *_buf, size_t n)
+{
+       size_t i;
+       u_int32_t r = 0;
+       char *buf = (char *)_buf;
+
+       for (i = 0; i < n; i++) {
+               if (i % 4 == 0)
+                       r = arc4random();
+               buf[i] = r & 0xff;
+               r >>= 8;
+       }
+       i = r = 0;
+}
+#endif /* !HAVE_ARC4RANDOM_BUF */
+
+#ifndef ARC4RANDOM_UNIFORM
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound).  This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+u_int32_t
+arc4random_uniform(u_int32_t upper_bound)
+{
+       u_int32_t r, min;
+
+       if (upper_bound < 2)
+               return 0;
+
+#if (ULONG_MAX > 0xffffffffUL)
+       min = 0x100000000UL % upper_bound;
+#else
+       /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+       if (upper_bound > 0x80000000)
+               min = 1 + ~upper_bound;         /* 2**32 - upper_bound */
+       else {
+               /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
+               min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
+       }
+#endif
+
+       /*
+        * This could theoretically loop forever but each retry has
+        * p > 0.5 (worst case, usually far better) of selecting a
+        * number inside the range we need, so it should rarely need
+        * to re-roll.
+        */
+       for (;;) {
+               r = arc4random();
+               if (r >= min)
+                       break;
+       }
+
+       return r % upper_bound;
+}
+#endif /* !HAVE_ARC4RANDOM_UNIFORM */
index dbf8176b6225f12beb576f1c6feeebd72137447c..38be7e350ae25fb18bcaa3161a7c8f05e430e97e 100644 (file)
@@ -175,45 +175,7 @@ check_nt_auth(int pwd_authenticated, struct passwd *pw)
 int
 check_ntsec(const char *filename)
 {
-       char *cygwin;
-       int allow_ntea = 0, allow_ntsec = 0;
-       struct statfs fsstat;
-
-       /* Windows 95/98/ME don't support file system security at all. */
-       if (!is_winnt)
-               return (0);
-
-       /* Evaluate current CYGWIN settings. */
-       cygwin = getenv("CYGWIN");
-       allow_ntea = ntea_on(cygwin);
-       allow_ntsec = ntsec_on(cygwin) ||
-           (has_capability(HAS_NTSEC_BY_DEFAULT) && !ntsec_off(cygwin));
-
-       /*
-        * `ntea' is an emulation of POSIX attributes. It doesn't support
-        * real file level security as ntsec on NTFS file systems does
-        * but it supports FAT filesystems. `ntea' is minimum requirement
-        * for security checks.
-        */
-       if (allow_ntea)
-               return (1);
-
-       /*
-        * Retrieve file system flags. In Cygwin, file system flags are
-        * copied to f_type which has no meaning in Win32 itself.
-        */
-       if (statfs(filename, &fsstat))
-               return (1);
-
-       /*
-        * Only file systems supporting ACLs are able to set permissions.
-        * `ntsec' is the setting in Cygwin which switches using of NTFS
-        * ACLs to support POSIX permissions on files.
-        */
-       if (fsstat.f_type & FS_PERSISTENT_ACLS)
-               return (allow_ntsec);
-
-       return (0);
+       return (pathconf(filename, _PC_POSIX_PERMISSIONS));
 }
 
 void
index 7a44a5a7916347405790594f1b9ab67239af60a6..a3654952eeef4ce70e90896a53c8c4d71cefcd65 100644 (file)
@@ -23,6 +23,7 @@
 # include <sys/select.h>
 #endif
 
+#include <stdlib.h>
 #include <errno.h>
 #include "bsd-poll.h"
 
diff --git a/openssh/openbsd-compat/bsd-statvfs.c b/openssh/openbsd-compat/bsd-statvfs.c
new file mode 100644 (file)
index 0000000..b870b6a
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2008 Darren Tucker <dtucker@zip.com.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <errno.h>
+
+#ifndef HAVE_STATVFS
+int statvfs(const char *path, struct statvfs *buf)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
+
+#ifndef HAVE_FSTATVFS
+int fstatvfs(int fd, struct statvfs *buf)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
diff --git a/openssh/openbsd-compat/bsd-statvfs.h b/openssh/openbsd-compat/bsd-statvfs.h
new file mode 100644 (file)
index 0000000..3009fc7
--- /dev/null
@@ -0,0 +1,68 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 2008 Darren Tucker <dtucker@zip.com.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+
+#ifndef HAVE_STATVFS
+
+#ifndef HAVE_FSBLKCNT_T
+typedef unsigned long fsblkcnt_t;
+#endif
+#ifndef HAVE_FSFILCNT_T
+typedef unsigned long fsfilcnt_t;
+#endif
+
+#ifndef ST_RDONLY
+#define ST_RDONLY      1
+#endif
+#ifndef ST_NOSUID
+#define ST_NOSUID      2
+#endif
+
+       /* as defined in IEEE Std 1003.1, 2004 Edition */
+struct statvfs {
+       unsigned long f_bsize;  /* File system block size. */
+       unsigned long f_frsize; /* Fundamental file system block size. */
+       fsblkcnt_t f_blocks;    /* Total number of blocks on file system in */
+                               /* units of f_frsize. */
+       fsblkcnt_t    f_bfree;  /* Total number of free blocks. */
+       fsblkcnt_t    f_bavail; /* Number of free blocks available to  */
+                               /* non-privileged process.  */
+       fsfilcnt_t    f_files;  /* Total number of file serial numbers. */
+       fsfilcnt_t    f_ffree;  /* Total number of free file serial numbers. */
+       fsfilcnt_t    f_favail; /* Number of file serial numbers available to */
+                               /* non-privileged process. */
+       unsigned long f_fsid;   /* File system ID. */
+       unsigned long f_flag;   /* BBit mask of f_flag values. */
+       unsigned long f_namemax;/*  Maximum filename length. */
+};
+#endif
+
+#ifndef HAVE_STATVFS
+int statvfs(const char *, struct statvfs *);
+#endif
+
+#ifndef HAVE_FSTATVFS
+int fstatvfs(int, struct statvfs *);
+#endif
index b6ea3d21e3425c2a2a070e2ea006e1a562895fff..096d9e092e29a9b7dc6219698d0f1d2a93bcfe82 100644 (file)
@@ -51,6 +51,8 @@ int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
        struct hostent *hp;
        char tmpserv[16];
 
+       if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
+               return (EAI_FAMILY);
        if (serv != NULL) {
                snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
                if (strlcpy(serv, tmpserv, servlen) >= servlen)
@@ -95,6 +97,8 @@ gai_strerror(int err)
                return ("memory allocation failure.");
        case EAI_NONAME:
                return ("nodename nor servname provided, or not known");
+       case EAI_FAMILY:
+               return ("ai_family not supported");
        default:
                return ("unknown/invalid error.");
        }
@@ -159,6 +163,9 @@ getaddrinfo(const char *hostname, const char *servname,
        u_long addr;
 
        port = 0;
+       if (hints && hints->ai_family != AF_UNSPEC &&
+           hints->ai_family != AF_INET)
+               return (EAI_FAMILY);
        if (servname != NULL) {
                char *cp;
 
index 60212b4044f2d26c7abeab12ae2f342fb8137dad..376009d4f08e4373746b3dc3de5300baf79c2589 100644 (file)
@@ -77,6 +77,7 @@ struct sockaddr_in6 {
        u_int16_t       sin6_port;
        u_int32_t       sin6_flowinfo;
        struct in6_addr sin6_addr;
+       u_int32_t       sin6_scope_id;
 };
 #endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
 
@@ -128,6 +129,9 @@ struct sockaddr_in6 {
 #ifndef EAI_SYSTEM
 # define EAI_SYSTEM    (INT_MAX - 4)
 #endif
+#ifndef EAI_FAMILY
+# define EAI_FAMILY    (INT_MAX - 5)
+#endif
 
 #ifndef HAVE_STRUCT_ADDRINFO
 struct addrinfo {
diff --git a/openssh/openbsd-compat/fmt_scaled.c b/openssh/openbsd-compat/fmt_scaled.c
new file mode 100644 (file)
index 0000000..edd682a
--- /dev/null
@@ -0,0 +1,274 @@
+/*     $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $     */
+
+/*
+ * Copyright (c) 2001, 2002, 2003 Ian F. Darwin.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libutil/fmt_scaled.c */
+
+/*
+ * fmt_scaled: Format numbers scaled for human comprehension
+ * scan_scaled: Scan numbers in this format.
+ *
+ * "Human-readable" output uses 4 digits max, and puts a unit suffix at
+ * the end.  Makes output compact and easy-to-read esp. on huge disks.
+ * Formatting code was originally in OpenBSD "df", converted to library routine.
+ * Scanning code written for OpenBSD libutil.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_FMT_SCALED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+typedef enum {
+       NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6
+} unit_type;
+
+/* These three arrays MUST be in sync!  XXX make a struct */
+static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA };
+static char scale_chars[] = "BKMGTPE";
+static long long scale_factors[] = {
+       1LL,
+       1024LL,
+       1024LL*1024,
+       1024LL*1024*1024,
+       1024LL*1024*1024*1024,
+       1024LL*1024*1024*1024*1024,
+       1024LL*1024*1024*1024*1024*1024,
+};
+#define        SCALE_LENGTH (sizeof(units)/sizeof(units[0]))
+
+#define MAX_DIGITS (SCALE_LENGTH * 3)  /* XXX strlen(sprintf("%lld", -1)? */
+
+/** Convert the given input string "scaled" into numeric in "result".
+ * Return 0 on success, -1 and errno set on error.
+ */
+int
+scan_scaled(char *scaled, long long *result)
+{
+       char *p = scaled;
+       int sign = 0;
+       unsigned int i, ndigits = 0, fract_digits = 0;
+       long long scale_fact = 1, whole = 0, fpart = 0;
+
+       /* Skip leading whitespace */
+       while (isascii(*p) && isspace(*p))
+               ++p;
+
+       /* Then at most one leading + or - */
+       while (*p == '-' || *p == '+') {
+               if (*p == '-') {
+                       if (sign) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       sign = -1;
+                       ++p;
+               } else if (*p == '+') {
+                       if (sign) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       sign = +1;
+                       ++p;
+               }
+       }
+
+       /* Main loop: Scan digits, find decimal point, if present.
+        * We don't allow exponentials, so no scientific notation
+        * (but note that E for Exa might look like e to some!).
+        * Advance 'p' to end, to get scale factor.
+        */
+       for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) {
+               if (*p == '.') {
+                       if (fract_digits > 0) { /* oops, more than one '.' */
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       fract_digits = 1;
+                       continue;
+               }
+
+               i = (*p) - '0';                 /* whew! finally a digit we can use */
+               if (fract_digits > 0) {
+                       if (fract_digits >= MAX_DIGITS-1)
+                               /* ignore extra fractional digits */
+                               continue;
+                       fract_digits++;         /* for later scaling */
+                       fpart *= 10;
+                       fpart += i;
+               } else {                                /* normal digit */
+                       if (++ndigits >= MAX_DIGITS) {
+                               errno = ERANGE;
+                               return -1;
+                       }
+                       whole *= 10;
+                       whole += i;
+               }
+       }
+
+       if (sign) {
+               whole *= sign;
+               fpart *= sign;
+       }
+
+       /* If no scale factor given, we're done. fraction is discarded. */
+       if (!*p) {
+               *result = whole;
+               return 0;
+       }
+
+       /* Validate scale factor, and scale whole and fraction by it. */
+       for (i = 0; i < SCALE_LENGTH; i++) {
+
+               /** Are we there yet? */
+               if (*p == scale_chars[i] ||
+                       *p == tolower(scale_chars[i])) {
+
+                       /* If it ends with alphanumerics after the scale char, bad. */
+                       if (isalnum(*(p+1))) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       scale_fact = scale_factors[i];
+
+                       /* scale whole part */
+                       whole *= scale_fact;
+
+                       /* truncate fpart so it does't overflow.
+                        * then scale fractional part.
+                        */
+                       while (fpart >= LLONG_MAX / scale_fact) {
+                               fpart /= 10;
+                               fract_digits--;
+                       }
+                       fpart *= scale_fact;
+                       if (fract_digits > 0) {
+                               for (i = 0; i < fract_digits -1; i++)
+                                       fpart /= 10;
+                       }
+                       whole += fpart;
+                       *result = whole;
+                       return 0;
+               }
+       }
+       errno = ERANGE;
+       return -1;
+}
+
+/* Format the given "number" into human-readable form in "result".
+ * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE.
+ * Return 0 on success, -1 and errno set if error.
+ */
+int
+fmt_scaled(long long number, char *result)
+{
+       long long abval, fract = 0;
+       unsigned int i;
+       unit_type unit = NONE;
+
+       abval = (number < 0LL) ? -number : number;      /* no long long_abs yet */
+
+       /* Not every negative long long has a positive representation.
+        * Also check for numbers that are just too darned big to format
+        */
+       if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) {
+               errno = ERANGE;
+               return -1;
+       }
+
+       /* scale whole part; get unscaled fraction */
+       for (i = 0; i < SCALE_LENGTH; i++) {
+               if (abval/1024 < scale_factors[i]) {
+                       unit = units[i];
+                       fract = (i == 0) ? 0 : abval % scale_factors[i];
+                       number /= scale_factors[i];
+                       if (i > 0)
+                               fract /= scale_factors[i - 1];
+                       break;
+               }
+       }
+
+       fract = (10 * fract + 512) / 1024;
+       /* if the result would be >= 10, round main number */
+       if (fract == 10) {
+               if (number >= 0)
+                       number++;
+               else
+                       number--;
+               fract = 0;
+       }
+
+       if (number == 0)
+               strlcpy(result, "0B", FMT_SCALED_STRSIZE);
+       else if (unit == NONE || number >= 100 || number <= -100) {
+               if (fract >= 5) {
+                       if (number >= 0)
+                               number++;
+                       else
+                               number--;
+               }
+               (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c",
+                       number, scale_chars[unit]);
+       } else
+               (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c",
+                       number, fract, scale_chars[unit]);
+
+       return 0;
+}
+
+#ifdef MAIN
+/*
+ * This is the original version of the program in the man page.
+ * Copy-and-paste whatever you need from it.
+ */
+int
+main(int argc, char **argv)
+{
+       char *cinput = "1.5K", buf[FMT_SCALED_STRSIZE];
+       long long ninput = 10483892, result;
+
+       if (scan_scaled(cinput, &result) == 0)
+               printf("\"%s\" -> %lld\n", cinput, result);
+       else
+               perror(cinput);
+
+       if (fmt_scaled(ninput, buf) == 0)
+               printf("%lld -> \"%s\"\n", ninput, buf);
+       else
+               fprintf(stderr, "%lld invalid (%s)\n", ninput, strerror(errno));
+
+       return 0;
+}
+#endif
+
+#endif /* HAVE_FMT_SCALED */
index edf4b9dc255b820b6760e045ebc61f38f3a55b3c..fb63bcef497f4ee20f66d78f260938459af9edde 100644 (file)
@@ -101,6 +101,11 @@ int daemon(int nochdir, int noclose);
 char *dirname(const char *path);
 #endif
 
+#ifndef HAVE_FMT_SCALED
+#define        FMT_SCALED_STRSIZE      7
+int    fmt_scaled(long long number, char *result);
+#endif
+
 #if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA)
 char *inet_ntoa(struct in_addr in);
 #endif
@@ -139,6 +144,7 @@ int writev(int, struct iovec *, int);
 
 /* Home grown routines */
 #include "bsd-misc.h"
+#include "bsd-statvfs.h"
 #include "bsd-waitpid.h"
 #include "bsd-poll.h"
 
@@ -151,6 +157,14 @@ unsigned int arc4random(void);
 void arc4random_stir(void);
 #endif /* !HAVE_ARC4RANDOM */
 
+#ifndef HAVE_ARC4RANDOM_BUF
+void arc4random_buf(void *, size_t);
+#endif
+
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+u_int32_t arc4random_uniform(u_int32_t);
+#endif
+
 #ifndef HAVE_ASPRINTF
 int asprintf(char **, const char *, ...);
 #endif 
index 276474db87cd970400d15b5731393172b892ed18..ddc92d0f3f5562bbf36c274d2b86f950025632f7 100644 (file)
@@ -29,6 +29,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "log.h"
 #include "misc.h"
 #include "buffer.h"
index 5b0275ce06320e008cac39f0cc12a28ea35ca6af..1cd61e58dbad7ae6ec27046e2b76d5d4ce7b3454 100644 (file)
@@ -44,6 +44,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #if 0
 int
index b52a99c2ccd2356bbde868a6bdf5b6708924a89c..e2a8b6dd3ca972e76eb324caac9e8e2146ac8e0a 100644 (file)
@@ -47,7 +47,7 @@ extern char **environ;
  *     Explicitly removes '=' in argument name.
  */
 static char *
-__findenv(const char *name, int *offset)
+__findenv(const char *name, size_t *offset)
 {
        extern char **environ;
        int len, i;
@@ -82,7 +82,7 @@ setenv(const char *name, const char *value, int rewrite)
 {
        static char **lastenv;                  /* last value of environ */
        char *C;
-       int l_value, offset;
+       size_t l_value, offset;
 
        if (*value == '=')                      /* no `=' in value */
                ++value;
@@ -133,7 +133,7 @@ void
 unsetenv(const char *name)
 {
        char **P;
-       int offset;
+       size_t offset;
 
        while (__findenv(name, &offset))        /* if set multiple times */
                for (P = &environ[offset];; ++P)
index b511f6649650084d12d025a0801479f9ec8835a3..2965f689e702f9545bc2401fe5add5f2bbd43405 100644 (file)
@@ -43,6 +43,8 @@
 #endif
 #include <string.h>
 
+#include <vis.h>
+
 #define SPT_NONE       0       /* don't use it at all */
 #define SPT_PSTAT      1       /* use pstat(PSTAT_SETCMD, ...) */
 #define SPT_REUSEARGV  2       /* cover argv with title information */
@@ -121,7 +123,7 @@ setproctitle(const char *fmt, ...)
 {
 #if SPT_TYPE != SPT_NONE
        va_list ap;
-       char buf[1024];
+       char buf[1024], ptitle[1024];
        size_t len;
        extern char *__progname;
 #if SPT_TYPE == SPT_PSTAT
@@ -142,14 +144,16 @@ setproctitle(const char *fmt, ...)
                        vsnprintf(buf + len, sizeof(buf) - len , fmt, ap);
        }
        va_end(ap);
+       strnvis(ptitle, buf, sizeof(ptitle),
+           VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL);
 
 #if SPT_TYPE == SPT_PSTAT
-       pst.pst_command = buf;
-       pstat(PSTAT_SETCMD, pst, strlen(buf), 0, 0);
+       pst.pst_command = ptitle;
+       pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0);
 #elif SPT_TYPE == SPT_REUSEARGV
 /*     debug("setproctitle: copy \"%s\" into len %d", 
            buf, argv_env_len); */
-       len = strlcpy(argv_start, buf, argv_env_len);
+       len = strlcpy(argv_start, ptitle, argv_env_len);
        for(; len < argv_env_len; len++)
                argv_start[len] = SPT_PADCHAR;
 #endif
index 8b8e4dd2c461878586b855b5aa6fd59f4aab4d0c..d67845cf1a5466803b4357e2d71e89aecc3597a6 100644 (file)
@@ -36,6 +36,7 @@
 /* OPENBSD ORIGINAL: lib/libcurses/base/sigaction.c */
 
 #include "includes.h"
+#include <errno.h>
 #include <signal.h>
 #include "sigact.h"
 
 int
 sigaction(int sig, struct sigaction *sigact, struct sigaction *osigact)
 {
-       return sigvec(sig, &(sigact->sv), &(osigact->sv));
+       return sigvec(sig, sigact ? &sigact->sv : NULL,
+           osigact ? &osigact->sv : NULL);
 }
 
 int
-sigemptyset (sigset_t * mask)
+sigemptyset (sigset_t *mask)
 {
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
        *mask = 0;
        return 0;
 }
 
 int
-sigprocmask (int mode, sigset_t * mask, sigset_t * omask)
+sigprocmask (int mode, sigset_t *mask, sigset_t *omask)
 {
        sigset_t current = sigsetmask(0);
 
-       if (omask) *omask = current;
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
 
-       if (mode==SIG_BLOCK)
+       if (omask)
+               *omask = current;
+
+       if (mode == SIG_BLOCK)
                current |= *mask;
-       else if (mode==SIG_UNBLOCK)
+       else if (mode == SIG_UNBLOCK)
                current &= ~*mask;
-       else if (mode==SIG_SETMASK)
+       else if (mode == SIG_SETMASK)
        current = *mask;
 
        sigsetmask(current);
@@ -76,28 +88,44 @@ sigprocmask (int mode, sigset_t * mask, sigset_t * omask)
 }
 
 int
-sigsuspend (sigset_t * mask)
+sigsuspend (sigset_t *mask)
 {
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
        return sigpause(*mask);
 }
 
 int
-sigdelset (sigset_t * mask, int sig)
+sigdelset (sigset_t *mask, int sig)
 {
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
        *mask &= ~sigmask(sig);
        return 0;
 }
 
 int
-sigaddset (sigset_t * mask, int sig)
+sigaddset (sigset_t *mask, int sig)
 {
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
        *mask |= sigmask(sig);
        return 0;
 }
 
 int
-sigismember (sigset_t * mask, int sig)
+sigismember (sigset_t *mask, int sig)
 {
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
        return (*mask & sigmask(sig)) != 0;
 }
 
index 6afe24b9fe4fa7680e374ba9e8d232444d2ab448..8abd43eb461946a1208b435a2abcf5c576283a43 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.151 2008/02/22 20:44:02 dtucker Exp $ */
+/* $OpenBSD: packet.c,v 1.157 2008/07/10 18:08:11 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -138,12 +138,16 @@ static int after_authentication = 0;
 
 int keep_alive_timeouts = 0;
 
+/* Set to the maximum time that we will wait to send or receive a packet */
+static int packet_timeout_ms = -1;
+
 /* Session key information for Encryption and MAC */
 Newkeys *newkeys[MODE_MAX];
 static struct packet_state {
        u_int32_t seqnr;
        u_int32_t packets;
        u_int64_t blocks;
+       u_int64_t bytes;
 } p_read, p_send;
 
 static u_int64_t max_blocks_in, max_blocks_out;
@@ -188,7 +192,21 @@ packet_set_connection(int fd_in, int fd_out)
                buffer_init(&outgoing_packet);
                buffer_init(&incoming_packet);
                TAILQ_INIT(&outgoing);
+               p_send.packets = p_read.packets = 0;
+       }
+}
+
+void
+packet_set_timeout(int timeout, int count)
+{
+       if (timeout == 0 || count == 0) {
+               packet_timeout_ms = -1;
+               return;
        }
+       if ((INT_MAX / 1000) / count < timeout)
+               packet_timeout_ms = INT_MAX;
+       else
+               packet_timeout_ms = timeout * count * 1000;
 }
 
 /* Returns 1 if remote host is connected via socket, 0 if not. */
@@ -295,18 +313,25 @@ packet_get_ssh1_cipher(void)
 }
 
 void
-packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets)
+packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets,
+    u_int64_t *bytes)
 {
        struct packet_state *state;
 
        state = (mode == MODE_IN) ? &p_read : &p_send;
-       *seqnr = state->seqnr;
-       *blocks = state->blocks;
-       *packets = state->packets;
+       if (seqnr)
+               *seqnr = state->seqnr;
+       if (blocks)
+               *blocks = state->blocks;
+       if (packets)
+               *packets = state->packets;
+       if (bytes)
+               *bytes = state->bytes;
 }
 
 void
-packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets)
+packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets,
+    u_int64_t bytes)
 {
        struct packet_state *state;
 
@@ -314,6 +339,7 @@ packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets)
        state->seqnr = seqnr;
        state->blocks = blocks;
        state->packets = packets;
+       state->bytes = bytes;
 }
 
 /* returns 1 if connection is via ipv4 */
@@ -592,7 +618,8 @@ packet_send1(void)
        fprintf(stderr, "encrypted: ");
        buffer_dump(&output);
 #endif
-
+       p_send.packets++;
+       p_send.bytes += len + buffer_len(&outgoing_packet);
        buffer_clear(&outgoing_packet);
 
        /*
@@ -818,6 +845,7 @@ packet_send2_wrapped(void)
                if (!(datafellows & SSH_BUG_NOREKEY))
                        fatal("XXX too many packets with same key");
        p_send.blocks += (packet_length + 4) / block_size;
+       p_send.bytes += packet_length + 4;
        buffer_clear(&outgoing_packet);
 
        if (type == SSH2_MSG_NEWKEYS)
@@ -891,9 +919,11 @@ packet_send(void)
 int
 packet_read_seqnr(u_int32_t *seqnr_p)
 {
-       int type, len;
+       int type, len, ret, ms_remain;
        fd_set *setp;
        char buf[8192];
+       struct timeval timeout, start, *timeoutp = NULL;
+
        DBG(debug("packet_read()"));
 
        setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS),
@@ -925,11 +955,35 @@ packet_read_seqnr(u_int32_t *seqnr_p)
                    sizeof(fd_mask));
                FD_SET(connection_in, setp);
 
+               if (packet_timeout_ms > 0) {
+                       ms_remain = packet_timeout_ms;
+                       timeoutp = &timeout;
+               }
                /* Wait for some data to arrive. */
-               while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
-                   (errno == EAGAIN || errno == EINTR))
-                       ;
-
+               for (;;) {
+                       if (packet_timeout_ms != -1) {
+                               ms_to_timeval(&timeout, ms_remain);
+                               gettimeofday(&start, NULL);
+                       }
+                       if ((ret = select(connection_in + 1, setp, NULL,
+                           NULL, timeoutp)) >= 0)
+                               break;
+                       if (errno != EAGAIN && errno != EINTR &&
+                           errno != EWOULDBLOCK)
+                               break;
+                       if (packet_timeout_ms == -1)
+                               continue;
+                       ms_subtract_diff(&start, &ms_remain);
+                       if (ms_remain <= 0) {
+                               ret = 0;
+                               break;
+                       }
+               }
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out while "
+                           "waiting to read", get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
                /* Read data from the socket. */
                len = read(connection_in, buf, sizeof(buf));
                if (len == 0) {
@@ -1054,6 +1108,8 @@ packet_read_poll1(void)
                buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
                    buffer_len(&compression_buffer));
        }
+       p_read.packets++;
+       p_read.bytes += padded_len + 4;
        type = buffer_get_char(&incoming_packet);
        if (type < SSH_MSG_MIN || type > SSH_MSG_MAX)
                packet_disconnect("Invalid ssh1 packet type: %d", type);
@@ -1142,6 +1198,7 @@ packet_read_poll2(u_int32_t *seqnr_p)
                if (!(datafellows & SSH_BUG_NOREKEY))
                        fatal("XXX too many packets with same key");
        p_read.blocks += (packet_length + 4) / block_size;
+       p_read.bytes += packet_length + 4;
 
        /* get padlen */
        cp = buffer_ptr(&incoming_packet);
@@ -1194,9 +1251,10 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p)
        for (;;) {
                if (compat20) {
                        type = packet_read_poll2(seqnr_p);
-                       keep_alive_timeouts = 0;
-                       if (type)
+                       if (type) {
+                               keep_alive_timeouts = 0;
                                DBG(debug("received packet type %d", type));
+                       }
                        switch (type) {
                        case SSH2_MSG_IGNORE:
                                debug3("Received SSH2_MSG_IGNORE");
@@ -1332,6 +1390,12 @@ packet_get_string(u_int *length_ptr)
        return buffer_get_string(&incoming_packet, length_ptr);
 }
 
+void *
+packet_get_string_ptr(u_int *length_ptr)
+{
+       return buffer_get_string_ptr(&incoming_packet, length_ptr);
+}
+
 /*
  * Sends a diagnostic message from the server to the client.  This message
  * can be sent at any time (but not while constructing another message). The
@@ -1426,16 +1490,19 @@ packet_write_poll(void)
 
        if (len > 0) {
                len = write(connection_out, buffer_ptr(&output), len);
-               if (len <= 0) {
-                       if (errno == EAGAIN)
+               if (len == -1) {
+                       if (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK)
                                return;
-                       else
-                               fatal("Write failed: %.100s", strerror(errno));
+                       fatal("Write failed: %.100s", strerror(errno));
                }
+               if (len == 0)
+                       fatal("Write connection closed");
                buffer_consume(&output, len);
        }
 }
 
+
 /*
  * Calls packet_write_poll repeatedly until all pending output data has been
  * written.
@@ -1445,6 +1512,8 @@ void
 packet_write_wait(void)
 {
        fd_set *setp;
+       int ret, ms_remain;
+       struct timeval start, timeout, *timeoutp = NULL;
 
        setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS),
            sizeof(fd_mask));
@@ -1453,9 +1522,35 @@ packet_write_wait(void)
                memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
                    sizeof(fd_mask));
                FD_SET(connection_out, setp);
-               while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
-                   (errno == EAGAIN || errno == EINTR))
-                       ;
+
+               if (packet_timeout_ms > 0) {
+                       ms_remain = packet_timeout_ms;
+                       timeoutp = &timeout;
+               }
+               for (;;) {
+                       if (packet_timeout_ms != -1) {
+                               ms_to_timeval(&timeout, ms_remain);
+                               gettimeofday(&start, NULL);
+                       }
+                       if ((ret = select(connection_out + 1, NULL, setp,
+                           NULL, timeoutp)) >= 0)
+                               break;
+                       if (errno != EAGAIN && errno != EINTR &&
+                           errno != EWOULDBLOCK)
+                               break;
+                       if (packet_timeout_ms == -1)
+                               continue;
+                       ms_subtract_diff(&start, &ms_remain);
+                       if (ms_remain <= 0) {
+                               ret = 0;
+                               break;
+                       }
+               }
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out while "
+                           "waiting to write", get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
                packet_write_poll();
        }
        xfree(setp);
index c1b9b3bd190c2b778ce021c64ddf29dc9ebb468d..03bb87c9beed95408721ac770baa52f2f8ea971f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.h,v 1.46 2008/02/22 20:44:02 dtucker Exp $ */
+/* $OpenBSD: packet.h,v 1.49 2008/07/10 18:08:11 markus Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -21,6 +21,7 @@
 #include <openssl/bn.h>
 
 void     packet_set_connection(int, int);
+void     packet_set_timeout(int, int);
 void     packet_set_nonblocking(void);
 int      packet_get_connection_in(void);
 int      packet_get_connection_out(void);
@@ -58,6 +59,7 @@ void     packet_get_bignum(BIGNUM * value);
 void     packet_get_bignum2(BIGNUM * value);
 void   *packet_get_raw(u_int *length_ptr);
 void   *packet_get_string(u_int *length_ptr);
+void   *packet_get_string_ptr(u_int *length_ptr);
 void     packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
 void     packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
 
@@ -66,8 +68,8 @@ int    packet_get_keyiv_len(int);
 void    packet_get_keyiv(int, u_char *, u_int);
 int     packet_get_keycontext(int, u_char *);
 void    packet_set_keycontext(int, u_char *);
-void    packet_get_state(int, u_int32_t *, u_int64_t *, u_int32_t *);
-void    packet_set_state(int, u_int32_t, u_int64_t, u_int32_t);
+void    packet_get_state(int, u_int32_t *, u_int64_t *, u_int32_t *, u_int64_t *);
+void    packet_set_state(int, u_int32_t, u_int64_t, u_int32_t, u_int64_t);
 int     packet_get_ssh1_cipher(void);
 void    packet_set_iv(int, u_char *);
 
index 3ddb4d392c55d668606f6f795df7651ee0e4e87a..73f6eb361e7fed7775f6a9a67fc3bd795f2ca390 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.165 2008/01/19 23:09:49 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.167 2008/06/26 11:46:31 grunk Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -130,6 +130,7 @@ typedef enum {
        oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
        oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
        oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
+       oVisualHostKey,
        oDeprecated, oUnsupported
 } OpCodes;
 
@@ -226,6 +227,7 @@ static struct {
        { "tunneldevice", oTunnelDevice },
        { "localcommand", oLocalCommand },
        { "permitlocalcommand", oPermitLocalCommand },
+       { "visualhostkey", oVisualHostKey },
        { NULL, oBadOption }
 };
 
@@ -915,6 +917,10 @@ parse_int:
                intptr = &options->permit_local_command;
                goto parse_flag;
 
+       case oVisualHostKey:
+               intptr = &options->visual_host_key;
+               goto parse_flag;
+
        case oDeprecated:
                debug("%s line %d: Deprecated option \"%s\"",
                    filename, linenum, keyword);
@@ -1065,6 +1071,7 @@ initialize_options(Options * options)
        options->tun_remote = -1;
        options->local_command = NULL;
        options->permit_local_command = -1;
+       options->visual_host_key = -1;
 }
 
 /*
@@ -1199,6 +1206,8 @@ fill_default_options(Options * options)
                options->tun_remote = SSH_TUNID_ANY;
        if (options->permit_local_command == -1)
                options->permit_local_command = 0;
+       if (options->visual_host_key == -1)
+               options->visual_host_key = 0;
        /* options->local_command should not be set by default */
        /* options->proxy_command should not be set by default */
        /* options->user will be set in the main program if appropriate */
index 6257f4b2f522415ff9dc3b127fbc140d3928c9cd..47c7aef4e046dc63d900227312c484f4e3f15352 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.72 2008/01/19 23:09:49 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.74 2008/06/26 11:46:31 grunk Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -120,6 +120,7 @@ typedef struct {
 
        char    *local_command;
        int     permit_local_command;
+       int     visual_host_key;
 
 }       Options;
 
index b229fca4832731314c8f07782969154ec43fc32a..3b8ea245bbec7914849ab7b1c03e314302824036 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: Makefile,v 1.44 2007/12/21 04:13:53 djm Exp $
+#      $OpenBSD: Makefile,v 1.48 2008/06/28 13:57:25 djm Exp $
 
 REGRESS_TARGETS=       t1 t2 t3 t4 t5 t6 t7 t-exec
 tests:         $(REGRESS_TARGETS)
@@ -34,6 +34,7 @@ LTESTS=       connect \
                agent-ptrace \
                keyscan \
                keygen-change \
+               key-options \
                scp \
                sftp \
                sftp-cmds \
@@ -47,10 +48,11 @@ LTESTS=     connect \
                reexec \
                brokenkeys \
                cfgmatch \
+               addrmatch \
                localcommand \
                forcecommand
 
-INTEROP_TESTS= putty-transfer putty-ciphers putty-kex
+INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
 #INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp
 
 USER!=         id -un
diff --git a/openssh/regress/addrmatch.sh b/openssh/regress/addrmatch.sh
new file mode 100644 (file)
index 0000000..a258f7b
--- /dev/null
@@ -0,0 +1,42 @@
+#      $OpenBSD: addrmatch.sh,v 1.1 2008/06/10 05:23:32 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="address match"
+
+mv $OBJ/sshd_proxy $OBJ/sshd_proxy_orig
+
+run_trial()
+{
+       user="$1"; addr="$2"; host="$3"; expected="$4"; descr="$5"
+
+       verbose "test $descr for $user $addr $host"
+       result=`${SSHD} -f $OBJ/sshd_proxy -T \
+           -C user=${user},addr=${addr},host=${host} | \
+           awk '/passwordauthentication/ {print $2}'`
+       if [ "$result" != "$expected" ]; then
+               fail "failed for $user $addr $host: expected $expected, got $result"
+       fi
+}
+
+cp $OBJ/sshd_proxy_orig $OBJ/sshd_proxy
+cat >>$OBJ/sshd_proxy <<EOD
+PasswordAuthentication no
+Match Address 192.168.0.0/16,!192.168.30.0/24,10.0.0.0/8,host.example.com
+       PasswordAuthentication yes
+Match Address 1.1.1.1,::1,!::3,2000::/16
+       PasswordAuthentication yes
+EOD
+
+run_trial user 192.168.0.1 somehost yes                "permit, first entry"
+run_trial user 192.168.30.1 somehost no                "deny, negative match"
+run_trial user 19.0.0.1 somehost no            "deny, no match"
+run_trial user 10.255.255.254 somehost yes     "permit, list middle"
+run_trial user 192.168.30.1 192.168.0.1 no     "deny, faked IP in hostname"
+run_trial user 1.1.1.1 somehost.example.com yes        "permit, bare IP4 address"
+test "$TEST_SSH_IPV6" = "no" && exit
+run_trial user ::1 somehost.example.com         yes    "permit, bare IP6 address"
+run_trial user ::2 somehost.exaple.com no      "deny IPv6"
+run_trial user ::3 somehost no                 "deny IP6 negated"
+run_trial user ::4 somehost no                 "deny, IP6 no match"
+run_trial user 2000::1 somehost yes            "permit, IP6 network"
+run_trial user 2001::1 somehost no             "deny, IP6 network"
diff --git a/openssh/regress/conch-ciphers.sh b/openssh/regress/conch-ciphers.sh
new file mode 100644 (file)
index 0000000..84b1906
--- /dev/null
@@ -0,0 +1,30 @@
+#      $OpenBSD: conch-ciphers.sh,v 1.2 2008/06/30 10:43:03 djm Exp $
+#      Placed in the Public Domain.
+
+tid="conch ciphers"
+
+DATA=/bin/ls
+COPY=${OBJ}/copy
+
+if test "x$REGRESS_INTEROP_CONCH" != "xyes" ; then
+       fatal "conch interop tests not enabled"
+fi
+
+start_sshd
+
+for c in aes256-ctr aes256-cbc aes192-ctr aes192-cbc aes128-ctr aes128-cbc \
+         cast128-cbc blowfish 3des-cbc ; do
+       verbose "$tid: cipher $c"
+       rm -f ${COPY}
+       # XXX the 2nd "cat" seems to be needed because of buggy FD handling
+       # in conch
+       ${CONCH} --identity $OBJ/rsa --port $PORT --user $USER  -e none \
+           --known-hosts $OBJ/known_hosts --notty --noagent --nox11 -n \
+           127.0.0.1 "cat ${DATA}" 2>/dev/null | cat > ${COPY}
+       if [ $? -ne 0 ]; then
+               fail "ssh cat $DATA failed"
+       fi
+       cmp ${DATA} ${COPY}             || fail "corrupted copy"
+done
+rm -f ${COPY}
+
diff --git a/openssh/regress/key-options.sh b/openssh/regress/key-options.sh
new file mode 100644 (file)
index 0000000..f98d78b
--- /dev/null
@@ -0,0 +1,71 @@
+#      $OpenBSD: key-options.sh,v 1.2 2008/06/30 08:07:34 djm Exp $
+#      Placed in the Public Domain.
+
+tid="key options"
+
+origkeys="$OBJ/authkeys_orig"
+authkeys="$OBJ/authorized_keys_${USER}"
+cp $authkeys $origkeys
+
+# Test command= forced command
+for p in 1 2; do
+    for c in 'command="echo bar"' 'no-pty,command="echo bar"'; do
+       sed "s/.*/$c &/" $origkeys >$authkeys
+       verbose "key option proto $p $c"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost echo foo`
+       if [ "$r" = "foo" ]; then
+               fail "key option forced command not restricted"
+       fi
+       if [ "$r" != "bar" ]; then
+               fail "key option forced command not executed"
+       fi
+    done
+done
+
+# Test no-pty
+sed 's/.*/no-pty &/' $origkeys >$authkeys
+for p in 1 2; do
+       verbose "key option proto $p no-pty"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost tty`
+       if [ -f "$r" ]; then
+               fail "key option failed proto $p no-pty (pty $r)"
+       fi
+done
+
+# Test environment=
+echo 'PermitUserEnvironment yes' >> $OBJ/sshd_proxy
+sed 's/.*/environment="FOO=bar" &/' $origkeys >$authkeys
+for p in 1 2; do
+       verbose "key option proto $p environment"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost 'echo $FOO'`
+       if [ "$r" != "bar" ]; then
+               fail "key option environment not set"
+       fi
+done
+
+# Test from= restriction
+start_sshd
+for p in 1 2; do
+    for f in 127.0.0.1 '127.0.0.0\/8'; do
+       cat  $origkeys >$authkeys
+       ${SSH} -$p -q -F $OBJ/ssh_proxy somehost true
+       if [ $? -ne 0 ]; then
+               fail "key option proto $p failed without restriction"
+       fi
+
+       sed 's/.*/from="'"$f"'" &/' $origkeys >$authkeys
+       from=`head -1 $authkeys | cut -f1 -d ' '`
+       verbose "key option proto $p $from"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost 'echo true'`
+       if [ "$r" = "true" ]; then
+               fail "key option proto $p $from not restricted"
+       fi
+
+       r=`${SSH} -$p -q -F $OBJ/ssh_config somehost 'echo true'`
+       if [ "$r" != "true" ]; then
+               fail "key option proto $p $from not allowed but should be"
+       fi
+    done
+done
+
+rm -f "$origkeys"
index e9196d621488acaa9b62cfbfb1e93f2fb5ab79c0..40435ef41a65f3d530ee8db52e9db9624c5dcb77 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: putty-ciphers.sh,v 1.1 2007/12/21 04:13:53 djm Exp $
+#      $OpenBSD: putty-ciphers.sh,v 1.2 2008/06/30 10:31:11 djm Exp $
 #      Placed in the Public Domain.
 
 tid="putty ciphers"
@@ -6,8 +6,6 @@ tid="putty ciphers"
 DATA=/bin/ls
 COPY=${OBJ}/copy
 
-set -e
-
 if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
        fatal "putty interop tests not enabled"
 fi
index d0437c6d5685aeaee576e0b05f44c37fe676e81c..2534b857532d6d1b01de3a8da2d03fba3d441873 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: putty-kex.sh,v 1.1 2007/12/21 04:13:53 djm Exp $
+#      $OpenBSD: putty-kex.sh,v 1.2 2008/06/30 10:31:11 djm Exp $
 #      Placed in the Public Domain.
 
 tid="putty KEX"
@@ -6,8 +6,6 @@ tid="putty KEX"
 DATA=/bin/ls
 COPY=${OBJ}/copy
 
-set -e
-
 if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
        fatal "putty interop tests not enabled"
 fi
index 0a4f34ee6dcedff7edbe7d37def28365767137ee..6b21f3be72b44aba2ad206dc24b27a6440affafc 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: putty-transfer.sh,v 1.1 2007/12/21 04:13:53 djm Exp $
+#      $OpenBSD: putty-transfer.sh,v 1.2 2008/06/30 10:31:11 djm Exp $
 #      Placed in the Public Domain.
 
 tid="putty transfer data"
@@ -6,8 +6,6 @@ tid="putty transfer data"
 DATA=/bin/ls
 COPY=${OBJ}/copy
 
-set -e
-
 if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
        fatal "putty interop tests not enabled"
 fi
index e67dd7b5d62f7d72d84c5dc77f5e915a55a71e90..b544489121719ea3edfd16886b065465ec79f9fd 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: test-exec.sh,v 1.31 2007/12/21 04:13:53 djm Exp $
+#      $OpenBSD: test-exec.sh,v 1.35 2008/06/28 13:57:25 djm Exp $
 #      Placed in the Public Domain.
 
 #SUDO=sudo
@@ -70,8 +70,9 @@ SFTPSERVER=/usr/libexec/openssh/sftp-server
 SCP=scp
 
 # Interop testing
-PLINK=/usr/local/bin/plink
-PUTTYGEN=/usr/local/bin/puttygen
+PLINK=plink
+PUTTYGEN=puttygen
+CONCH=conch
 
 if [ "x$TEST_SSH_SSH" != "x" ]; then
        SSH="${TEST_SSH_SSH}"
@@ -114,6 +115,13 @@ if [ "x$TEST_SSH_PUTTYGEN" != "x" ]; then
        *) PUTTYGEN=`which ${TEST_SSH_PUTTYGEN} 2>/dev/null` ;;
        esac
 fi
+if [ "x$TEST_SSH_CONCH" != "x" ]; then
+       # Find real binary, if it exists
+       case "${TEST_SSH_CONCH}" in
+       /*) CONCH="${TEST_SSH_CONCH}" ;;
+       *) CONCH=`which ${TEST_SSH_CONCH} 2>/dev/null` ;;
+       esac
+fi
 
 # Path to sshd must be absolute for rexec
 case "$SSHD" in
@@ -287,9 +295,24 @@ for t in rsa rsa1; do
 done
 chmod 644 $OBJ/authorized_keys_$USER
 
-# If PuTTY is present, prepare keys and configuration
+# Activate Twisted Conch tests if the binary is present
+REGRESS_INTEROP_CONCH=no
+if test -x "$CONCH" ; then
+       REGRESS_INTEROP_CONCH=yes
+fi
+
+# If PuTTY is present and we are running a PuTTY test, prepare keys and
+# configuration
 REGRESS_INTEROP_PUTTY=no
 if test -x "$PUTTYGEN" -a -x "$PLINK" ; then
+       REGRESS_INTEROP_PUTTY=yes
+fi
+case "$SCRIPT" in
+*putty*)       ;;
+*)             REGRESS_INTEROP_PUTTY=no ;;
+esac
+
+if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then
        mkdir -p ${OBJ}/.putty
 
        # Add a PuTTY key to authorized_keys
index a8bd97f21a786e60476544a80e56a96100dccddb..5033d84f2227bb9eb7d4fd78757f963d63379be1 100644 (file)
@@ -9,9 +9,9 @@
 .\"
 .\" Created: Sun May  7 00:14:37 1995 ylo
 .\"
-.\" $OpenBSD: scp.1,v 1.44 2008/01/31 20:06:50 jmc Exp $
+.\" $OpenBSD: scp.1,v 1.46 2008/07/12 05:33:41 djm Exp $
 .\"
-.Dd $Mdocdate: February 10 2008 $
+.Dd $Mdocdate: July 12 2008 $
 .Dt SCP 1
 .Os
 .Sh NAME
@@ -104,7 +104,7 @@ per-user configuration file for
 This option is directly passed to
 .Xr ssh 1 .
 .It Fl i Ar identity_file
-Selects the file from which the identity (private key) for RSA
+Selects the file from which the identity (private key) for public key
 authentication is read.
 This option is directly passed to
 .Xr ssh 1 .
@@ -189,6 +189,9 @@ messages from
 .Xr ssh 1 .
 .It Fl r
 Recursively copy entire directories.
+Note that
+.Nm
+follows symbolic links encountered in the tree traversal.
 .It Fl S Ar program
 Name of
 .Ar program
index c047864aa9c76f478fe6676c6dc6ef97f026b3ff..9f8b7a192ac6702dd9f4fe9e43a14e81a9a1370f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: scp.c,v 1.162 2008/01/01 09:06:39 dtucker Exp $ */
+/* $OpenBSD: scp.c,v 1.163 2008/06/13 18:55:22 dtucker Exp $ */
 /*
  * scp - secure remote copy.  This is basically patched BSD rcp which
  * uses ssh to do the data transfer (instead of using rcmd).
@@ -474,7 +474,7 @@ scpio(ssize_t (*f)(int, void *, size_t), int fd, void *_p, size_t l, off_t *c)
                if (r < 0) {
                        if (errno == EINTR)
                                continue;
-                       if (errno == EAGAIN) {
+                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                (void)poll(&pfd, 1, -1); /* Ignore errors */
                                continue;
                        }
@@ -629,7 +629,8 @@ source(int argc, char **argv)
        struct stat stb;
        static BUF buffer;
        BUF *bp;
-       off_t i, amt, statbytes;
+       off_t i, statbytes;
+       size_t amt;
        int fd = -1, haderr, indx;
        char *last, *name, buf[2048], encname[MAXPATHLEN];
        int len;
@@ -650,6 +651,10 @@ source(int argc, char **argv)
 syserr:                        run_err("%s: %s", name, strerror(errno));
                        goto next;
                }
+               if (stb.st_size < 0) {
+                       run_err("%s: %s", name, "Negative file size");
+                       goto next;
+               }
                unset_nonblock(fd);
                switch (stb.st_mode & S_IFMT) {
                case S_IFREG:
@@ -709,7 +714,7 @@ next:                       if (fd != -1) {
                set_nonblock(remout);
                for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
                        amt = bp->cnt;
-                       if (i + amt > stb.st_size)
+                       if (i + (off_t)amt > stb.st_size)
                                amt = stb.st_size - i;
                        if (!haderr) {
                                if (atomicio(read, fd, bp->buf, amt) != amt)
index 9add96ca1ad094734b74f44804a5322f6bd153cc..66e22979f926eec8c6ae490f408edeeac522deef 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.c,v 1.177 2008/02/10 10:54:28 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.186 2008/07/04 03:44:59 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -23,7 +23,9 @@
 #include <signal.h>
 #include <unistd.h>
 #include <stdarg.h>
+#include <errno.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
 #include "log.h"
@@ -99,6 +101,7 @@ initialize_server_options(ServerOptions *options)
        options->use_login = -1;
        options->compression = -1;
        options->allow_tcp_forwarding = -1;
+       options->allow_agent_forwarding = -1;
        options->num_allow_users = 0;
        options->num_deny_users = 0;
        options->num_allow_groups = 0;
@@ -112,6 +115,7 @@ initialize_server_options(ServerOptions *options)
        options->max_startups_rate = -1;
        options->max_startups = -1;
        options->max_authtries = -1;
+       options->max_sessions = -1;
        options->banner = NULL;
        options->use_dns = -1;
        options->client_alive_interval = -1;
@@ -154,7 +158,7 @@ fill_default_server_options(ServerOptions *options)
        if (options->pid_file == NULL)
                options->pid_file = _PATH_SSH_DAEMON_PID_FILE;
        if (options->server_key_bits == -1)
-               options->server_key_bits = 768;
+               options->server_key_bits = 1024;
        if (options->login_grace_time == -1)
                options->login_grace_time = 120;
        if (options->key_regeneration_time == -1)
@@ -223,6 +227,8 @@ fill_default_server_options(ServerOptions *options)
                options->compression = COMP_DELAYED;
        if (options->allow_tcp_forwarding == -1)
                options->allow_tcp_forwarding = 1;
+       if (options->allow_agent_forwarding == -1)
+               options->allow_agent_forwarding = 1;
        if (options->gateway_ports == -1)
                options->gateway_ports = 0;
        if (options->max_startups == -1)
@@ -233,6 +239,8 @@ fill_default_server_options(ServerOptions *options)
                options->max_startups_begin = options->max_startups;
        if (options->max_authtries == -1)
                options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
+       if (options->max_sessions == -1)
+               options->max_sessions = DEFAULT_SESSIONS_MAX;
        if (options->use_dns == -1)
                options->use_dns = 1;
        if (options->client_alive_interval == -1)
@@ -287,13 +295,13 @@ typedef enum {
        sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
        sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
        sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
-       sMaxStartups, sMaxAuthTries,
+       sMaxStartups, sMaxAuthTries, sMaxSessions,
        sBanner, sUseDNS, sHostbasedAuthentication,
        sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
        sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
        sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
        sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
-       sUsePrivilegeSeparation,
+       sUsePrivilegeSeparation, sAllowAgentForwarding,
        sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -379,6 +387,7 @@ static struct {
        { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
        { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },  /* obsolete alias */
        { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
+       { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
        { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
        { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
        { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
@@ -389,7 +398,8 @@ static struct {
        { "gatewayports", sGatewayPorts, SSHCFG_ALL },
        { "subsystem", sSubsystem, SSHCFG_GLOBAL },
        { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
-       { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
+       { "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
+       { "maxsessions", sMaxSessions, SSHCFG_ALL },
        { "banner", sBanner, SSHCFG_ALL },
        { "usedns", sUseDNS, SSHCFG_GLOBAL },
        { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
@@ -408,6 +418,17 @@ static struct {
        { NULL, sBadOption, 0 }
 };
 
+static struct {
+       int val;
+       char *text;
+} tunmode_desc[] = {
+       { SSH_TUNMODE_NO, "no" },
+       { SSH_TUNMODE_POINTOPOINT, "point-to-point" },
+       { SSH_TUNMODE_ETHERNET, "ethernet" },
+       { SSH_TUNMODE_YES, "yes" },
+       { -1, NULL }
+};
+
 /*
  * Returns the number of the token pointed to by cp or sBadOption.
  */
@@ -504,24 +525,8 @@ static int
 match_cfg_line_group(const char *grps, int line, const char *user)
 {
        int result = 0;
-       u_int ngrps = 0;
-       char *arg, *p, *cp, *grplist[MAX_MATCH_GROUPS];
        struct passwd *pw;
 
-       /*
-        * Even if we do not have a user yet, we still need to check for
-        * valid syntax.
-        */
-       arg = cp = xstrdup(grps);
-       while ((p = strsep(&cp, ",")) != NULL && *p != '\0') {
-               if (ngrps >= MAX_MATCH_GROUPS) {
-                       error("line %d: too many groups in Match Group", line);
-                       result = -1;
-                       goto out;
-               }
-               grplist[ngrps++] = p;
-       }
-
        if (user == NULL)
                goto out;
 
@@ -531,17 +536,16 @@ match_cfg_line_group(const char *grps, int line, const char *user)
        } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
                debug("Can't Match group because user %.100s not in any group "
                    "at line %d", user, line);
-       } else if (ga_match(grplist, ngrps) != 1) {
-               debug("user %.100s does not match group %.100s at line %d",
-                   user, arg, line);
+       } else if (ga_match_pattern_list(grps) != 1) {
+               debug("user %.100s does not match group list %.100s at line %d",
+                   user, grps, line);
        } else {
-               debug("user %.100s matched group %.100s at line %d", user,
-                   arg, line);
+               debug("user %.100s matched group list %.100s at line %d", user,
+                   grps, line);
                result = 1;
        }
 out:
        ga_free();
-       xfree(arg);
        return result;
 }
 
@@ -594,15 +598,18 @@ match_cfg_line(char **condition, int line, const char *user, const char *host,
                                debug("connection from %.100s matched 'Host "
                                    "%.100s' at line %d", host, arg, line);
                } else if (strcasecmp(attrib, "address") == 0) {
-                       if (!address) {
-                               result = 0;
-                               continue;
-                       }
-                       if (match_hostname(address, arg, len) != 1)
-                               result = 0;
-                       else
+                       switch (addr_match_list(address, arg)) {
+                       case 1:
                                debug("connection from %.100s matched 'Address "
                                    "%.100s' at line %d", address, arg, line);
+                               break;
+                       case 0:
+                       case -1:
+                               result = 0;
+                               break;
+                       case -2:
+                               return -1;
+                       }
                } else {
                        error("Unsupported Match attribute %s", attrib);
                        return -1;
@@ -690,7 +697,7 @@ process_server_config_line(ServerOptions *options, char *line,
 
        case sServerKeyBits:
                intptr = &options->server_key_bits;
-parse_int:
+ parse_int:
                arg = strdelim(&cp);
                if (!arg || *arg == '\0')
                        fatal("%s line %d: missing integer value.",
@@ -702,7 +709,7 @@ parse_int:
 
        case sLoginGraceTime:
                intptr = &options->login_grace_time;
-parse_time:
+ parse_time:
                arg = strdelim(&cp);
                if (!arg || *arg == '\0')
                        fatal("%s line %d: missing time value.",
@@ -771,7 +778,7 @@ parse_time:
                        fatal("%s line %d: too many host keys specified (max %d).",
                            filename, linenum, MAX_HOSTKEYS);
                charptr = &options->host_key_files[*intptr];
-parse_filename:
+ parse_filename:
                arg = strdelim(&cp);
                if (!arg || *arg == '\0')
                        fatal("%s line %d: missing file name.",
@@ -814,7 +821,7 @@ parse_filename:
 
        case sIgnoreRhosts:
                intptr = &options->ignore_rhosts;
-parse_flag:
+ parse_flag:
                arg = strdelim(&cp);
                if (!arg || *arg == '\0')
                        fatal("%s line %d: missing yes/no argument.",
@@ -1005,6 +1012,10 @@ parse_flag:
                intptr = &options->allow_tcp_forwarding;
                goto parse_flag;
 
+       case sAllowAgentForwarding:
+               intptr = &options->allow_agent_forwarding;
+               goto parse_flag;
+
        case sUsePrivilegeSeparation:
                intptr = &use_privsep;
                goto parse_flag;
@@ -1146,6 +1157,10 @@ parse_flag:
                intptr = &options->max_authtries;
                goto parse_int;
 
+       case sMaxSessions:
+               intptr = &options->max_sessions;
+               goto parse_int;
+
        case sBanner:
                charptr = &options->banner;
                goto parse_filename;
@@ -1192,16 +1207,13 @@ parse_flag:
                if (!arg || *arg == '\0')
                        fatal("%s line %d: Missing yes/point-to-point/"
                            "ethernet/no argument.", filename, linenum);
-               value = 0;      /* silence compiler */
-               if (strcasecmp(arg, "ethernet") == 0)
-                       value = SSH_TUNMODE_ETHERNET;
-               else if (strcasecmp(arg, "point-to-point") == 0)
-                       value = SSH_TUNMODE_POINTOPOINT;
-               else if (strcasecmp(arg, "yes") == 0)
-                       value = SSH_TUNMODE_YES;
-               else if (strcasecmp(arg, "no") == 0)
-                       value = SSH_TUNMODE_NO;
-               else
+               value = -1;
+               for (i = 0; tunmode_desc[i].val != -1; i++)
+                       if (strcmp(tunmode_desc[i].text, arg) == 0) {
+                               value = tunmode_desc[i].val;
+                               break;
+                       }
+               if (value == -1)
                        fatal("%s line %d: Bad yes/point-to-point/ethernet/"
                            "no argument: %s", filename, linenum, arg);
                if (*intptr == -1)
@@ -1368,10 +1380,13 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
        M_CP_INTOPT(permit_root_login);
 
        M_CP_INTOPT(allow_tcp_forwarding);
+       M_CP_INTOPT(allow_agent_forwarding);
        M_CP_INTOPT(gateway_ports);
        M_CP_INTOPT(x11_display_offset);
        M_CP_INTOPT(x11_forwarding);
        M_CP_INTOPT(x11_use_localhost);
+       M_CP_INTOPT(max_sessions);
+       M_CP_INTOPT(max_authtries);
 
        M_CP_STROPT(banner);
        if (preauth)
@@ -1405,3 +1420,213 @@ parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
                fatal("%s: terminating, %d bad configuration options",
                    filename, bad_options);
 }
+
+static const char *
+fmt_intarg(ServerOpCodes code, int val)
+{
+       if (code == sAddressFamily) {
+               switch (val) {
+               case AF_INET:
+                       return "inet";
+               case AF_INET6:
+                       return "inet6";
+               case AF_UNSPEC:
+                       return "any";
+               default:
+                       return "UNKNOWN";
+               }
+       }
+       if (code == sPermitRootLogin) {
+               switch (val) {
+               case PERMIT_NO_PASSWD:
+                       return "without-passord";
+               case PERMIT_FORCED_ONLY:
+                       return "forced-commands-only";
+               case PERMIT_YES:
+                       return "yes";
+               }
+       }
+       if (code == sProtocol) {
+               switch (val) {
+               case SSH_PROTO_1:
+                       return "1";
+               case SSH_PROTO_2:
+                       return "2";
+               case (SSH_PROTO_1|SSH_PROTO_2):
+                       return "2,1";
+               default:
+                       return "UNKNOWN";
+               }
+       }
+       if (code == sGatewayPorts && val == 2)
+               return "clientspecified";
+       if (code == sCompression && val == COMP_DELAYED)
+               return "delayed";
+       switch (val) {
+       case -1:
+               return "unset";
+       case 0:
+               return "no";
+       case 1:
+               return "yes";
+       }
+       return "UNKNOWN";
+}
+
+static const char *
+lookup_opcode_name(ServerOpCodes code)
+{
+       u_int i;
+
+       for (i = 0; keywords[i].name != NULL; i++)
+               if (keywords[i].opcode == code)
+                       return(keywords[i].name);
+       return "UNKNOWN";
+}
+
+static void
+dump_cfg_int(ServerOpCodes code, int val)
+{
+       printf("%s %d\n", lookup_opcode_name(code), val);
+}
+
+static void
+dump_cfg_fmtint(ServerOpCodes code, int val)
+{
+       printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
+}
+
+static void
+dump_cfg_string(ServerOpCodes code, const char *val)
+{
+       if (val == NULL)
+               return;
+       printf("%s %s\n", lookup_opcode_name(code), val);
+}
+
+static void
+dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
+{
+       u_int i;
+
+       for (i = 0; i < count; i++)
+               printf("%s %s\n", lookup_opcode_name(code),  vals[i]);
+}
+
+void
+dump_config(ServerOptions *o)
+{
+       u_int i;
+       int ret;
+       struct addrinfo *ai;
+       char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
+
+       /* these are usually at the top of the config */
+       for (i = 0; i < o->num_ports; i++)
+               printf("port %d\n", o->ports[i]);
+       dump_cfg_fmtint(sProtocol, o->protocol);
+       dump_cfg_fmtint(sAddressFamily, o->address_family);
+
+       /* ListenAddress must be after Port */
+       for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
+               if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
+                   sizeof(addr), port, sizeof(port),
+                   NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
+                       error("getnameinfo failed: %.100s",
+                           (ret != EAI_SYSTEM) ? gai_strerror(ret) :
+                           strerror(errno));
+               } else {
+                       if (ai->ai_family == AF_INET6)
+                               printf("listenaddress [%s]:%s\n", addr, port);
+                       else
+                               printf("listenaddress %s:%s\n", addr, port);
+               }
+       }
+
+       /* integer arguments */
+       dump_cfg_int(sServerKeyBits, o->server_key_bits);
+       dump_cfg_int(sLoginGraceTime, o->login_grace_time);
+       dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
+       dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
+       dump_cfg_int(sMaxAuthTries, o->max_authtries);
+       dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
+       dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
+
+       /* formatted integer arguments */
+       dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
+       dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
+       dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
+       dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
+       dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
+       dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
+           o->hostbased_uses_name_from_packet_only);
+       dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
+       dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
+       dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
+       dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
+       dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
+       dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
+       dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
+       dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
+       dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
+       dump_cfg_fmtint(sKbdInteractiveAuthentication,
+           o->kbd_interactive_authentication);
+       dump_cfg_fmtint(sChallengeResponseAuthentication,
+           o->challenge_response_authentication);
+       dump_cfg_fmtint(sPrintMotd, o->print_motd);
+       dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
+       dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
+       dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
+       dump_cfg_fmtint(sStrictModes, o->strict_modes);
+       dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
+       dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
+       dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
+       dump_cfg_fmtint(sUseLogin, o->use_login);
+       dump_cfg_fmtint(sCompression, o->compression);
+       dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
+       dump_cfg_fmtint(sUseDNS, o->use_dns);
+       dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+       dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
+
+       /* string arguments */
+       dump_cfg_string(sPidFile, o->pid_file);
+       dump_cfg_string(sXAuthLocation, o->xauth_location);
+       dump_cfg_string(sCiphers, o->ciphers);
+       dump_cfg_string(sMacs, o->macs);
+       dump_cfg_string(sBanner, o->banner);
+       dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
+       dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
+       dump_cfg_string(sForceCommand, o->adm_forced_command);
+
+       /* string arguments requiring a lookup */
+       dump_cfg_string(sLogLevel, log_level_name(o->log_level));
+       dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
+
+       /* string array arguments */
+       dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
+            o->host_key_files);
+       dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
+       dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
+       dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
+       dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
+       dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
+
+       /* other arguments */
+       for (i = 0; i < o->num_subsystems; i++)
+               printf("subsystem %s %s\n", o->subsystem_name[i],
+                   o->subsystem_args[i]);
+
+       printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
+           o->max_startups_rate, o->max_startups);
+
+       for (i = 0; tunmode_desc[i].val != -1; i++)
+               if (tunmode_desc[i].val == o->permit_tun) {
+                       s = tunmode_desc[i].text;
+                       break;
+               }
+       dump_cfg_string(sPermitTunnel, s);
+
+       printf("permitopen");
+       channel_print_adm_permitted_opens();
+       printf("\n");
+}
index 5b88067dbc54c36734bf3b491f71df7879afe010..40ac64f135094b0afd95804b61eaf7b71082ded8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.82 2008/02/13 22:38:17 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.85 2008/06/10 04:50:25 dtucker Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -35,6 +35,7 @@
 #define        PERMIT_YES              3
 
 #define DEFAULT_AUTH_FAIL_MAX  6       /* Default for MaxAuthTries */
+#define DEFAULT_SESSIONS_MAX   10      /* Default for MaxSessions */
 
 /* Magic name for internal sftp-server */
 #define INTERNAL_SFTP_NAME     "internal-sftp"
@@ -101,6 +102,7 @@ typedef struct {
        int     use_login;      /* If true, login(1) is used */
        int     compression;    /* If true, compression is allowed */
        int     allow_tcp_forwarding;
+       int     allow_agent_forwarding;
        u_int num_allow_users;
        char   *allow_users[MAX_ALLOW_USERS];
        u_int num_deny_users;
@@ -122,6 +124,7 @@ typedef struct {
        int     max_startups_rate;
        int     max_startups;
        int     max_authtries;
+       int     max_sessions;
        char   *banner;                 /* SSH-2 banner message */
        int     use_dns;
        int     client_alive_interval;  /*
@@ -158,5 +161,6 @@ void         parse_server_config(ServerOptions *, const char *, Buffer *,
 void    parse_server_match_config(ServerOptions *, const char *, const char *,
             const char *);
 void    copy_set_server_options(ServerOptions *, ServerOptions *, int);
+void    dump_config(ServerOptions *);
 
 #endif                         /* SERVCONF_H */
index bf3f9c9f0af67b53c45b394dc52bc68d02025204..77d9dee75ceb9c26de8b1b04f3d00d6b6b939b4b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.148 2008/02/22 20:44:02 dtucker Exp $ */
+/* $OpenBSD: serverloop.c,v 1.153 2008/06/30 12:15:39 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -56,6 +56,7 @@
 #include <unistd.h>
 #include <stdarg.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "packet.h"
 #include "buffer.h"
@@ -104,6 +105,7 @@ static int connection_in;   /* Connection to client (input). */
 static int connection_out;     /* Connection to client (output). */
 static int connection_closed = 0;      /* Connection to client closed. */
 static u_int buffer_high;      /* "Soft" max buffer size. */
+static int no_more_sessions = 0; /* Disallow further sessions. */
 
 /*
  * This SIGCHLD kludge is used to detect when the child exits.  The server
@@ -398,7 +400,8 @@ process_input(fd_set *readset)
                                return;
                        cleanup_exit(255);
                } else if (len < 0) {
-                       if (errno != EINTR && errno != EAGAIN) {
+                       if (errno != EINTR && errno != EAGAIN &&
+                           errno != EWOULDBLOCK) {
                                verbose("Read error from remote host "
                                    "%.100s: %.100s",
                                    get_remote_ipaddr(), strerror(errno));
@@ -416,8 +419,8 @@ process_input(fd_set *readset)
        if (!fdout_eof && FD_ISSET(fdout, readset)) {
                errno = 0;
                len = read(fdout, buf, sizeof(buf));
-               if (len < 0 && (errno == EINTR ||
-                   (errno == EAGAIN && !child_terminated))) {
+               if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+                   errno == EWOULDBLOCK) && !child_terminated))) {
                        /* do nothing */
 #ifndef PTY_ZEROREAD
                } else if (len <= 0) {
@@ -435,8 +438,8 @@ process_input(fd_set *readset)
        if (!fderr_eof && FD_ISSET(fderr, readset)) {
                errno = 0;
                len = read(fderr, buf, sizeof(buf));
-               if (len < 0 && (errno == EINTR ||
-                   (errno == EAGAIN && !child_terminated))) {
+               if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+                   errno == EWOULDBLOCK) && !child_terminated))) {
                        /* do nothing */
 #ifndef PTY_ZEROREAD
                } else if (len <= 0) {
@@ -467,7 +470,8 @@ process_output(fd_set *writeset)
                data = buffer_ptr(&stdin_buffer);
                dlen = buffer_len(&stdin_buffer);
                len = write(fdin, data, dlen);
-               if (len < 0 && (errno == EINTR || errno == EAGAIN)) {
+               if (len < 0 &&
+                   (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
                        /* do nothing */
                } else if (len <= 0) {
                        if (fdin != fdout)
@@ -937,7 +941,6 @@ static Channel *
 server_request_direct_tcpip(void)
 {
        Channel *c;
-       int sock;
        char *target, *originator;
        int target_port, originator_port;
 
@@ -947,18 +950,16 @@ server_request_direct_tcpip(void)
        originator_port = packet_get_int();
        packet_check_eom();
 
-       debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
-           originator, originator_port, target, target_port);
+       debug("server_request_direct_tcpip: originator %s port %d, target %s "
+           "port %d", originator, originator_port, target, target_port);
 
        /* XXX check permission */
-       sock = channel_connect_to(target, target_port);
-       xfree(target);
+       c = channel_connect_to(target, target_port,
+           "direct-tcpip", "direct-tcpip");
+
        xfree(originator);
-       if (sock < 0)
-               return NULL;
-       c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING,
-           sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT,
-           CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1);
+       xfree(target);
+
        return c;
 }
 
@@ -999,7 +1000,7 @@ server_request_tun(void)
 #if defined(SSH_TUN_FILTER)
        if (mode == SSH_TUNMODE_POINTOPOINT)
                channel_register_filter(c->self, sys_tun_infilter,
-                   sys_tun_outfilter);
+                   sys_tun_outfilter, NULL, NULL);
 #endif
 
  done:
@@ -1015,6 +1016,12 @@ server_request_session(void)
 
        debug("input_session_request");
        packet_check_eom();
+
+       if (no_more_sessions) {
+               packet_disconnect("Possible attack: attempt to open a session "
+                   "after additional sessions disabled");
+       }
+
        /*
         * A server session has no fd to read or write until a
         * CHANNEL_REQUEST for a shell is made, so we set the type to
@@ -1135,6 +1142,9 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt)
                success = channel_cancel_rport_listener(cancel_address,
                    cancel_port);
                xfree(cancel_address);
+       } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
+               no_more_sessions = 1;
+               success = 1;
        }
        if (want_reply) {
                packet_start(success ?
@@ -1162,7 +1172,11 @@ server_input_channel_req(int type, u_int32_t seq, void *ctxt)
        if ((c = channel_lookup(id)) == NULL)
                packet_disconnect("server_input_channel_req: "
                    "unknown channel %d", id);
-       if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN)
+       if (!strcmp(rtype, "eow@openssh.com")) {
+               packet_check_eom();
+               chan_rcvd_eow(c);
+       } else if ((c->type == SSH_CHANNEL_LARVAL ||
+           c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
                success = session_input_channel_req(c, rtype);
        if (reply) {
                packet_start(success ?
@@ -1188,8 +1202,9 @@ server_init_dispatch_20(void)
        dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req);
        dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
        dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
+       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm);
+       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm);
        /* client_alive */
-       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive);
        dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive);
        dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive);
        /* rekeying */
index a77dde38f761ff9e4b35f432dfc359c5efd7332b..93babf95701a723398e098d8965c1579ac269dac 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.233 2008/03/26 21:28:14 djm Exp $ */
+/* $OpenBSD: session.c,v 1.241 2008/06/16 13:22:53 dtucker Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -59,6 +59,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
 /* func */
 
 Session *session_new(void);
-void   session_set_fds(Session *, int, int, int);
+void   session_set_fds(Session *, int, int, int, int);
 void   session_pty_cleanup(Session *);
 void   session_proctitle(Session *);
 int    session_setup_x11fwd(Session *);
-void   do_exec_pty(Session *, const char *);
-void   do_exec_no_pty(Session *, const char *);
-void   do_exec(Session *, const char *);
+int    do_exec_pty(Session *, const char *);
+int    do_exec_no_pty(Session *, const char *);
+int    do_exec(Session *, const char *);
 void   do_login(Session *, const char *);
 #ifdef LOGIN_NEEDS_UTMPX
 static void    do_pre_login(Session *s);
@@ -131,8 +132,9 @@ extern Buffer loginmsg;
 const char *original_command = NULL;
 
 /* data */
-#define MAX_SESSIONS 20
-Session        sessions[MAX_SESSIONS];
+static int sessions_first_unused = -1;
+static int sessions_nalloc = 0;
+static Session *sessions = NULL;
 
 #define SUBSYSTEM_NONE         0
 #define SUBSYSTEM_EXT          1
@@ -166,7 +168,7 @@ static int
 auth_input_request_forwarding(struct passwd * pw)
 {
        Channel *nc;
-       int sock;
+       int sock = -1;
        struct sockaddr_un sunaddr;
 
        if (auth_sock_name != NULL) {
@@ -178,43 +180,48 @@ auth_input_request_forwarding(struct passwd * pw)
        temporarily_use_uid(pw);
 
        /* Allocate a buffer for the socket name, and format the name. */
-       auth_sock_name = xmalloc(MAXPATHLEN);
-       auth_sock_dir = xmalloc(MAXPATHLEN);
-       strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
+       auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
 
        /* Create private directory for socket */
        if (mkdtemp(auth_sock_dir) == NULL) {
                packet_send_debug("Agent forwarding disabled: "
                    "mkdtemp() failed: %.100s", strerror(errno));
                restore_uid();
-               xfree(auth_sock_name);
                xfree(auth_sock_dir);
-               auth_sock_name = NULL;
                auth_sock_dir = NULL;
-               return 0;
+               goto authsock_err;
        }
-       snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",
-                auth_sock_dir, (long) getpid());
+
+       xasprintf(&auth_sock_name, "%s/agent.%ld",
+           auth_sock_dir, (long) getpid());
 
        /* Create the socket. */
        sock = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (sock < 0)
-               packet_disconnect("socket: %.100s", strerror(errno));
+       if (sock < 0) {
+               error("socket: %.100s", strerror(errno));
+               restore_uid();
+               goto authsock_err;
+       }
 
        /* Bind it to the name. */
        memset(&sunaddr, 0, sizeof(sunaddr));
        sunaddr.sun_family = AF_UNIX;
        strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
 
-       if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
-               packet_disconnect("bind: %.100s", strerror(errno));
+       if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
+               error("bind: %.100s", strerror(errno));
+               restore_uid();
+               goto authsock_err;
+       }
 
        /* Restore the privileged uid. */
        restore_uid();
 
        /* Start listening on the socket. */
-       if (listen(sock, SSH_LISTEN_BACKLOG) < 0)
-               packet_disconnect("listen: %.100s", strerror(errno));
+       if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
+               error("listen: %.100s", strerror(errno));
+               goto authsock_err;
+       }
 
        /* Allocate a channel for the authentication agent socket. */
        nc = channel_new("auth socket",
@@ -223,6 +230,19 @@ auth_input_request_forwarding(struct passwd * pw)
            0, "auth socket", 1);
        strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
        return 1;
+
+ authsock_err:
+       if (auth_sock_name != NULL)
+               xfree(auth_sock_name);
+       if (auth_sock_dir != NULL) {
+               rmdir(auth_sock_dir);
+               xfree(auth_sock_dir);
+       }
+       if (sock != -1)
+               close(sock);
+       auth_sock_name = NULL;
+       auth_sock_dir = NULL;
+       return 0;
 }
 
 static void
@@ -335,7 +355,8 @@ do_authenticated1(Authctxt *authctxt)
                        break;
 
                case SSH_CMSG_AGENT_REQUEST_FORWARDING:
-                       if (no_agent_forwarding_flag || compat13) {
+                       if (!options.allow_agent_forwarding ||
+                           no_agent_forwarding_flag || compat13) {
                                debug("Authentication agent forwarding not permitted for this authentication.");
                                break;
                        }
@@ -371,10 +392,14 @@ do_authenticated1(Authctxt *authctxt)
                        if (type == SSH_CMSG_EXEC_CMD) {
                                command = packet_get_string(&dlen);
                                debug("Exec command '%.500s'", command);
-                               do_exec(s, command);
+                               if (do_exec(s, command) != 0)
+                                       packet_disconnect(
+                                           "command execution failed");
                                xfree(command);
                        } else {
-                               do_exec(s, NULL);
+                               if (do_exec(s, NULL) != 0)
+                                       packet_disconnect(
+                                           "shell execution failed");
                        }
                        packet_check_eom();
                        session_close(s);
@@ -399,41 +424,84 @@ do_authenticated1(Authctxt *authctxt)
        }
 }
 
+#define USE_PIPES
 /*
  * This is called to fork and execute a command when we have no tty.  This
  * will call do_child from the child, and server_loop from the parent after
  * setting up file descriptors and such.
  */
-void
+int
 do_exec_no_pty(Session *s, const char *command)
 {
        pid_t pid;
 
 #ifdef USE_PIPES
        int pin[2], pout[2], perr[2];
+
        /* Allocate pipes for communicating with the program. */
-       if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
-               packet_disconnect("Could not create pipes: %.100s",
-                                 strerror(errno));
-#else /* USE_PIPES */
+       if (pipe(pin) < 0) {
+               error("%s: pipe in: %.100s", __func__, strerror(errno));
+               return -1;
+       }
+       if (pipe(pout) < 0) {
+               error("%s: pipe out: %.100s", __func__, strerror(errno));
+               close(pin[0]);
+               close(pin[1]);
+               return -1;
+       }
+       if (pipe(perr) < 0) {
+               error("%s: pipe err: %.100s", __func__, strerror(errno));
+               close(pin[0]);
+               close(pin[1]);
+               close(pout[0]);
+               close(pout[1]);
+               return -1;
+       }
+#else
        int inout[2], err[2];
+
        /* Uses socket pairs to communicate with the program. */
-       if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
-           socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
-               packet_disconnect("Could not create socket pairs: %.100s",
-                                 strerror(errno));
-#endif /* USE_PIPES */
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
+               error("%s: socketpair #1: %.100s", __func__, strerror(errno));
+               return -1;
+       }
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
+               error("%s: socketpair #2: %.100s", __func__, strerror(errno));
+               close(inout[0]);
+               close(inout[1]);
+               return -1;
+       }
+#endif
+
        if (s == NULL)
                fatal("do_exec_no_pty: no session");
 
        session_proctitle(s);
 
        /* Fork the child. */
-       if ((pid = fork()) == 0) {
+       switch ((pid = fork())) {
+       case -1:
+               error("%s: fork: %.100s", __func__, strerror(errno));
+#ifdef USE_PIPES
+               close(pin[0]);
+               close(pin[1]);
+               close(pout[0]);
+               close(pout[1]);
+               close(perr[0]);
+               close(perr[1]);
+#else
+               close(inout[0]);
+               close(inout[1]);
+               close(err[0]);
+               close(err[1]);
+#endif
+               return -1;
+       case 0:
                is_child = 1;
 
                /* Child.  Reinitialize the log since the pid has changed. */
-               log_init(__progname, options.log_level, options.log_facility, log_stderr);
+               log_init(__progname, options.log_level,
+                   options.log_facility, log_stderr);
 
                /*
                 * Create a new session and process group since the 4.4BSD
@@ -463,7 +531,7 @@ do_exec_no_pty(Session *s, const char *command)
                if (dup2(perr[1], 2) < 0)
                        perror("dup2 stderr");
                close(perr[1]);
-#else /* USE_PIPES */
+#else
                /*
                 * Redirect stdin, stdout, and stderr.  Stdin and stdout will
                 * use the same socket, as some programs (particularly rdist)
@@ -473,11 +541,14 @@ do_exec_no_pty(Session *s, const char *command)
                close(err[1]);
                if (dup2(inout[0], 0) < 0)      /* stdin */
                        perror("dup2 stdin");
-               if (dup2(inout[0], 1) < 0)      /* stdout.  Note: same socket as stdin. */
+               if (dup2(inout[0], 1) < 0)      /* stdout (same as stdin) */
                        perror("dup2 stdout");
+               close(inout[0]);
                if (dup2(err[0], 2) < 0)        /* stderr */
                        perror("dup2 stderr");
-#endif /* USE_PIPES */
+               close(err[0]);
+#endif
+
 
 #ifdef _UNICOS
                cray_init_job(s->pw); /* set up cray jid and tmpdir */
@@ -486,7 +557,10 @@ do_exec_no_pty(Session *s, const char *command)
                /* Do processing for the child (exec command etc). */
                do_child(s, command);
                /* NOTREACHED */
+       default:
+               break;
        }
+
 #ifdef _UNICOS
        signal(WJSIGNAL, cray_job_termination_handler);
 #endif /* _UNICOS */
@@ -494,11 +568,18 @@ do_exec_no_pty(Session *s, const char *command)
        if (is_winnt)
                cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
 #endif
-       if (pid < 0)
-               packet_disconnect("fork failed: %.100s", strerror(errno));
+
        s->pid = pid;
        /* Set interactive/non-interactive mode. */
        packet_set_interactive(s->display != NULL);
+
+       /*
+        * Clear loginmsg, since it's the child's responsibility to display
+        * it to the user, otherwise multiple sessions may accumulate
+        * multiple copies of the login messages.
+        */
+       buffer_clear(&loginmsg);
+
 #ifdef USE_PIPES
        /* We are the parent.  Close the child sides of the pipes. */
        close(pin[0]);
@@ -510,35 +591,32 @@ do_exec_no_pty(Session *s, const char *command)
                        close(perr[0]);
                        perr[0] = -1;
                }
-               session_set_fds(s, pin[1], pout[0], perr[0]);
+               session_set_fds(s, pin[1], pout[0], perr[0], 0);
        } else {
                /* Enter the interactive session. */
                server_loop(pid, pin[1], pout[0], perr[0]);
                /* server_loop has closed pin[1], pout[0], and perr[0]. */
        }
-#else /* USE_PIPES */
+#else
        /* We are the parent.  Close the child sides of the socket pairs. */
        close(inout[0]);
        close(err[0]);
 
-       /*
-        * Clear loginmsg, since it's the child's responsibility to display
-        * it to the user, otherwise multiple sessions may accumulate
-        * multiple copies of the login messages.
-        */
-       buffer_clear(&loginmsg);
-
        /*
         * Enter the interactive session.  Note: server_loop must be able to
         * handle the case that fdin and fdout are the same.
         */
        if (compat20) {
-               session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
+               session_set_fds(s, inout[1], inout[1],
+                   s->is_subsystem ? -1 : err[1], 0);
+               if (s->is_subsystem)
+                       close(err[1]);
        } else {
                server_loop(pid, inout[1], inout[1], err[1]);
                /* server_loop has closed inout[1] and err[1]. */
        }
-#endif /* USE_PIPES */
+#endif
+       return 0;
 }
 
 /*
@@ -547,7 +625,7 @@ do_exec_no_pty(Session *s, const char *command)
  * setting up file descriptors, controlling tty, updating wtmp, utmp,
  * lastlog, and other such operations.
  */
-void
+int
 do_exec_pty(Session *s, const char *command)
 {
        int fdout, ptyfd, ttyfd, ptymaster;
@@ -558,12 +636,46 @@ do_exec_pty(Session *s, const char *command)
        ptyfd = s->ptyfd;
        ttyfd = s->ttyfd;
 
+       /*
+        * Create another descriptor of the pty master side for use as the
+        * standard input.  We could use the original descriptor, but this
+        * simplifies code in server_loop.  The descriptor is bidirectional.
+        * Do this before forking (and cleanup in the child) so as to
+        * detect and gracefully fail out-of-fd conditions.
+        */
+       if ((fdout = dup(ptyfd)) < 0) {
+               error("%s: dup #1: %s", __func__, strerror(errno));
+               close(ttyfd);
+               close(ptyfd);
+               return -1;
+       }
+       /* we keep a reference to the pty master */
+       if ((ptymaster = dup(ptyfd)) < 0) {
+               error("%s: dup #2: %s", __func__, strerror(errno));
+               close(ttyfd);
+               close(ptyfd);
+               close(fdout);
+               return -1;
+       }
+
        /* Fork the child. */
-       if ((pid = fork()) == 0) {
+       switch ((pid = fork())) {
+       case -1:
+               error("%s: fork: %.100s", __func__, strerror(errno));
+               close(fdout);
+               close(ptymaster);
+               close(ttyfd);
+               close(ptyfd);
+               return -1;
+       case 0:
                is_child = 1;
 
+               close(fdout);
+               close(ptymaster);
+
                /* Child.  Reinitialize the log because the pid has changed. */
-               log_init(__progname, options.log_level, options.log_facility, log_stderr);
+               log_init(__progname, options.log_level,
+                   options.log_facility, log_stderr);
                /* Close the master side of the pseudo tty. */
                close(ptyfd);
 
@@ -594,11 +706,16 @@ do_exec_pty(Session *s, const char *command)
                        do_pre_login(s);
 # endif
 #endif
-
-               /* Do common processing for the child, such as execing the command. */
-               do_child(s, command);
-               /* NOTREACHED */
+               /*
+                * Do common processing for the child, such as execing
+                * the command.
+                */
+               do_child(s, command);
+               /* NOTREACHED */
+       default:
+               break;
        }
+
 #ifdef _UNICOS
        signal(WJSIGNAL, cray_job_termination_handler);
 #endif /* _UNICOS */
@@ -606,36 +723,22 @@ do_exec_pty(Session *s, const char *command)
        if (is_winnt)
                cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
 #endif
-       if (pid < 0)
-               packet_disconnect("fork failed: %.100s", strerror(errno));
+
        s->pid = pid;
 
        /* Parent.  Close the slave side of the pseudo tty. */
        close(ttyfd);
 
-       /*
-        * Create another descriptor of the pty master side for use as the
-        * standard input.  We could use the original descriptor, but this
-        * simplifies code in server_loop.  The descriptor is bidirectional.
-        */
-       fdout = dup(ptyfd);
-       if (fdout < 0)
-               packet_disconnect("dup #1 failed: %.100s", strerror(errno));
-
-       /* we keep a reference to the pty master */
-       ptymaster = dup(ptyfd);
-       if (ptymaster < 0)
-               packet_disconnect("dup #2 failed: %.100s", strerror(errno));
-       s->ptymaster = ptymaster;
-
        /* Enter interactive session. */
+       s->ptymaster = ptymaster;
        packet_set_interactive(1);
        if (compat20) {
-               session_set_fds(s, ptyfd, fdout, -1);
+               session_set_fds(s, ptyfd, fdout, -1, 1);
        } else {
                server_loop(pid, ptyfd, fdout, -1);
                /* server_loop _has_ closed ptyfd and fdout. */
        }
+       return 0;
 }
 
 #ifdef LOGIN_NEEDS_UTMPX
@@ -670,9 +773,11 @@ do_pre_login(Session *s)
  * This is called to fork and execute a command.  If another command is
  * to be forced, execute that instead.
  */
-void
+int
 do_exec(Session *s, const char *command)
 {
+       int ret;
+
        if (options.adm_forced_command) {
                original_command = command;
                command = options.adm_forced_command;
@@ -703,9 +808,9 @@ do_exec(Session *s, const char *command)
        }
 #endif
        if (s->ttyfd != -1)
-               do_exec_pty(s, command);
+               ret = do_exec_pty(s, command);
        else
-               do_exec_no_pty(s, command);
+               ret = do_exec_no_pty(s, command);
 
        original_command = NULL;
 
@@ -715,6 +820,8 @@ do_exec(Session *s, const char *command)
         * multiple copies of the login messages.
         */
        buffer_clear(&loginmsg);
+
+       return ret;
 }
 
 /* administrative, login(1)-like work */
@@ -1204,7 +1311,7 @@ do_rc_files(Session *s, const char *shell)
 
        /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
        if (!s->is_subsystem && options.adm_forced_command == NULL &&
-           !no_user_rc &&  (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
+           !no_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) {
                snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
                    shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
                if (debug_flag)
@@ -1540,6 +1647,7 @@ do_child(Session *s, const char *command)
        char *argv[ARGV_MAX];
        const char *shell, *shell0, *hostname = NULL;
        struct passwd *pw = s->pw;
+       int r = 0;
 
        /* remove hostkey from the child's memory */
        destroy_sensitive_data();
@@ -1655,12 +1763,16 @@ do_child(Session *s, const char *command)
 
        /* Change current directory to the user's home directory. */
        if (chdir(pw->pw_dir) < 0) {
-               fprintf(stderr, "Could not chdir to home directory %s: %s\n",
-                   pw->pw_dir, strerror(errno));
+               /* Suppress missing homedir warning for chroot case */
 #ifdef HAVE_LOGIN_CAP
-               if (login_getcapbool(lc, "requirehome", 0))
-                       exit(1);
+               r = login_getcapbool(lc, "requirehome", 0);
 #endif
+               if (r || options.chroot_directory == NULL)
+                       fprintf(stderr, "Could not chdir to home "
+                           "directory %s: %s\n", pw->pw_dir,
+                           strerror(errno));
+               if (r)
+                       exit(1);
        }
 
        closefrom(STDERR_FILENO + 1);
@@ -1738,43 +1850,79 @@ do_child(Session *s, const char *command)
        exit(1);
 }
 
+void
+session_unused(int id)
+{
+       debug3("%s: session id %d unused", __func__, id);
+       if (id >= options.max_sessions ||
+           id >= sessions_nalloc) {
+               fatal("%s: insane session id %d (max %d nalloc %d)",
+                   __func__, id, options.max_sessions, sessions_nalloc);
+       }
+       bzero(&sessions[id], sizeof(*sessions));
+       sessions[id].self = id;
+       sessions[id].used = 0;
+       sessions[id].chanid = -1;
+       sessions[id].ptyfd = -1;
+       sessions[id].ttyfd = -1;
+       sessions[id].ptymaster = -1;
+       sessions[id].x11_chanids = NULL;
+       sessions[id].next_unused = sessions_first_unused;
+       sessions_first_unused = id;
+}
+
 Session *
 session_new(void)
 {
-       int i;
-       static int did_init = 0;
-       if (!did_init) {
-               debug("session_new: init");
-               for (i = 0; i < MAX_SESSIONS; i++) {
-                       sessions[i].used = 0;
+       Session *s, *tmp;
+
+       if (sessions_first_unused == -1) {
+               if (sessions_nalloc >= options.max_sessions)
+                       return NULL;
+               debug2("%s: allocate (allocated %d max %d)",
+                   __func__, sessions_nalloc, options.max_sessions);
+               tmp = xrealloc(sessions, sessions_nalloc + 1,
+                   sizeof(*sessions));
+               if (tmp == NULL) {
+                       error("%s: cannot allocate %d sessions",
+                           __func__, sessions_nalloc + 1);
+                       return NULL;
                }
-               did_init = 1;
+               sessions = tmp;
+               session_unused(sessions_nalloc++);
        }
-       for (i = 0; i < MAX_SESSIONS; i++) {
-               Session *s = &sessions[i];
-               if (! s->used) {
-                       memset(s, 0, sizeof(*s));
-                       s->chanid = -1;
-                       s->ptyfd = -1;
-                       s->ttyfd = -1;
-                       s->used = 1;
-                       s->self = i;
-                       s->x11_chanids = NULL;
-                       debug("session_new: session %d", i);
-                       return s;
-               }
+
+       if (sessions_first_unused >= sessions_nalloc ||
+           sessions_first_unused < 0) {
+               fatal("%s: insane first_unused %d max %d nalloc %d",
+                   __func__, sessions_first_unused, options.max_sessions,
+                   sessions_nalloc);
        }
-       return NULL;
+
+       s = &sessions[sessions_first_unused];
+       if (s->used) {
+               fatal("%s: session %d already used",
+                   __func__, sessions_first_unused);
+       }
+       sessions_first_unused = s->next_unused;
+       s->used = 1;
+       s->next_unused = -1;
+       debug("session_new: session %d", s->self);
+
+       return s;
 }
 
 static void
 session_dump(void)
 {
        int i;
-       for (i = 0; i < MAX_SESSIONS; i++) {
+       for (i = 0; i < sessions_nalloc; i++) {
                Session *s = &sessions[i];
-               debug("dump: used %d session %d %p channel %d pid %ld",
+
+               debug("dump: used %d next_unused %d session %d %p "
+                   "channel %d pid %ld",
                    s->used,
+                   s->next_unused,
                    s->self,
                    s,
                    s->chanid,
@@ -1804,7 +1952,7 @@ Session *
 session_by_tty(char *tty)
 {
        int i;
-       for (i = 0; i < MAX_SESSIONS; i++) {
+       for (i = 0; i < sessions_nalloc; i++) {
                Session *s = &sessions[i];
                if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
                        debug("session_by_tty: session %d tty %s", i, tty);
@@ -1820,10 +1968,11 @@ static Session *
 session_by_channel(int id)
 {
        int i;
-       for (i = 0; i < MAX_SESSIONS; i++) {
+       for (i = 0; i < sessions_nalloc; i++) {
                Session *s = &sessions[i];
                if (s->used && s->chanid == id) {
-                       debug("session_by_channel: session %d channel %d", i, id);
+                       debug("session_by_channel: session %d channel %d",
+                           i, id);
                        return s;
                }
        }
@@ -1837,7 +1986,7 @@ session_by_x11_channel(int id)
 {
        int i, j;
 
-       for (i = 0; i < MAX_SESSIONS; i++) {
+       for (i = 0; i < sessions_nalloc; i++) {
                Session *s = &sessions[i];
 
                if (s->x11_chanids == NULL || !s->used)
@@ -1860,7 +2009,7 @@ session_by_pid(pid_t pid)
 {
        int i;
        debug("session_by_pid: pid %ld", (long)pid);
-       for (i = 0; i < MAX_SESSIONS; i++) {
+       for (i = 0; i < sessions_nalloc; i++) {
                Session *s = &sessions[i];
                if (s->used && s->pid == pid)
                        return s;
@@ -1916,7 +2065,8 @@ session_pty_req(Session *s)
 
        /* Allocate a pty and open it. */
        debug("Allocating pty.");
-       if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) {
+       if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
+           sizeof(s->tty)))) {
                if (s->term)
                        xfree(s->term);
                s->term = NULL;
@@ -1969,8 +2119,7 @@ session_subsystem_req(Session *s)
                                s->is_subsystem = SUBSYSTEM_EXT;
                        }
                        debug("subsystem: exec() %s", cmd);
-                       do_exec(s, cmd);
-                       success = 1;
+                       success = do_exec(s, cmd) == 0;
                        break;
                }
        }
@@ -2013,19 +2162,19 @@ static int
 session_shell_req(Session *s)
 {
        packet_check_eom();
-       do_exec(s, NULL);
-       return 1;
+       return do_exec(s, NULL) == 0;
 }
 
 static int
 session_exec_req(Session *s)
 {
-       u_int len;
+       u_int len, success;
+
        char *command = packet_get_string(&len);
        packet_check_eom();
-       do_exec(s, command);
+       success = do_exec(s, command) == 0;
        xfree(command);
-       return 1;
+       return success;
 }
 
 static int
@@ -2035,8 +2184,7 @@ session_break_req(Session *s)
        packet_get_int();       /* ignored */
        packet_check_eom();
 
-       if (s->ttyfd == -1 ||
-           tcsendbreak(s->ttyfd, 0) < 0)
+       if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0)
                return 0;
        return 1;
 }
@@ -2081,7 +2229,7 @@ session_auth_agent_req(Session *s)
 {
        static int called = 0;
        packet_check_eom();
-       if (no_agent_forwarding_flag) {
+       if (no_agent_forwarding_flag || !options.allow_agent_forwarding) {
                debug("session_auth_agent_req: no_agent_forwarding_flag");
                return 0;
        }
@@ -2137,7 +2285,7 @@ session_input_channel_req(Channel *c, const char *rtype)
 }
 
 void
-session_set_fds(Session *s, int fdin, int fdout, int fderr)
+session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty)
 {
        if (!compat20)
                fatal("session_set_fds: called for proto != 2.0");
@@ -2150,8 +2298,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
        channel_set_fds(s->chanid,
            fdout, fdin, fderr,
            fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
-           1,
-           CHAN_SES_WINDOW_DEFAULT);
+           1, is_tty, CHAN_SES_WINDOW_DEFAULT);
 }
 
 /*
@@ -2183,8 +2330,9 @@ session_pty_cleanup2(Session *s)
         * the pty cleanup, so that another process doesn't get this pty
         * while we're still cleaning up.
         */
-       if (close(s->ptymaster) < 0)
-               error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno));
+       if (s->ptymaster != -1 && close(s->ptymaster) < 0)
+               error("close(s->ptymaster/%d): %s",
+                   s->ptymaster, strerror(errno));
 
        /* unlink pty from session */
        s->ttyfd = -1;
@@ -2344,7 +2492,6 @@ session_close(Session *s)
                xfree(s->auth_data);
        if (s->auth_proto)
                xfree(s->auth_proto);
-       s->used = 0;
        if (s->env != NULL) {
                for (i = 0; i < s->num_env; i++) {
                        xfree(s->env[i].name);
@@ -2353,6 +2500,7 @@ session_close(Session *s)
                xfree(s->env);
        }
        session_proctitle(s);
+       session_unused(s->self);
 }
 
 void
@@ -2416,7 +2564,7 @@ void
 session_destroy_all(void (*closefunc)(Session *))
 {
        int i;
-       for (i = 0; i < MAX_SESSIONS; i++) {
+       for (i = 0; i < sessions_nalloc; i++) {
                Session *s = &sessions[i];
                if (s->used) {
                        if (closefunc != NULL)
@@ -2435,7 +2583,7 @@ session_tty_list(void)
        char *cp;
 
        buf[0] = '\0';
-       for (i = 0; i < MAX_SESSIONS; i++) {
+       for (i = 0; i < sessions_nalloc; i++) {
                Session *s = &sessions[i];
                if (s->used && s->ttyfd != -1) {
 
index ee9338e4f5e71f619c1d996c9062bb623ed2e9b9..cbb8e3a32d183abbfa35506c5943bfe3fd11f67c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.29 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: session.h,v 1.30 2008/05/08 12:21:16 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -31,6 +31,7 @@ typedef struct Session Session;
 struct Session {
        int     used;
        int     self;
+       int     next_unused;
        struct passwd *pw;
        Authctxt *authctxt;
        pid_t   pid;
@@ -65,6 +66,7 @@ void   do_authenticated(Authctxt *);
 void    do_cleanup(Authctxt *);
 
 int     session_open(Authctxt *, int);
+void    session_unused(int);
 int     session_input_channel_req(Channel *, const char *);
 void    session_close_by_pid(pid_t, int);
 void    session_close_by_channel(int, void *);
index 69c6377859070b44555df41d8fb5fbe7eb63e286..5e39aa7d21bd6f8b309d1e774c0230ed7fc75aa9 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.81 2008/03/23 12:54:01 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.86 2008/06/26 06:10:09 djm Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -24,6 +24,9 @@
 
 #include <sys/types.h>
 #include <sys/param.h>
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
 #include "openbsd-compat/sys-queue.h"
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
@@ -65,7 +68,9 @@ struct sftp_conn {
        u_int num_requests;
        u_int version;
        u_int msg_id;
-#define SFTP_EXT_POSIX_RENAME  1
+#define SFTP_EXT_POSIX_RENAME  0x00000001
+#define SFTP_EXT_STATVFS       0x00000002
+#define SFTP_EXT_FSTATVFS      0x00000004
        u_int exts;
 };
 
@@ -238,6 +243,57 @@ get_decode_stat(int fd, u_int expected_id, int quiet)
        return(a);
 }
 
+static int
+get_decode_statvfs(int fd, struct sftp_statvfs *st, u_int expected_id,
+    int quiet)
+{
+       Buffer msg;
+       u_int type, id, flag;
+
+       buffer_init(&msg);
+       get_msg(fd, &msg);
+
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       debug3("Received statvfs reply T:%u I:%u", type, id);
+       if (id != expected_id)
+               fatal("ID mismatch (%u != %u)", id, expected_id);
+       if (type == SSH2_FXP_STATUS) {
+               int status = buffer_get_int(&msg);
+
+               if (quiet)
+                       debug("Couldn't statvfs: %s", fx2txt(status));
+               else
+                       error("Couldn't statvfs: %s", fx2txt(status));
+               buffer_free(&msg);
+               return -1;
+       } else if (type != SSH2_FXP_EXTENDED_REPLY) {
+               fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
+                   SSH2_FXP_EXTENDED_REPLY, type);
+       }
+
+       bzero(st, sizeof(*st));
+       st->f_bsize = buffer_get_int64(&msg);
+       st->f_frsize = buffer_get_int64(&msg);
+       st->f_blocks = buffer_get_int64(&msg);
+       st->f_bfree = buffer_get_int64(&msg);
+       st->f_bavail = buffer_get_int64(&msg);
+       st->f_files = buffer_get_int64(&msg);
+       st->f_ffree = buffer_get_int64(&msg);
+       st->f_favail = buffer_get_int64(&msg);
+       st->f_fsid = buffer_get_int64(&msg);
+       flag = buffer_get_int64(&msg);
+       st->f_namemax = buffer_get_int64(&msg);
+
+       st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
+       st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
+
+       buffer_free(&msg);
+
+       return 0;
+}
+
 struct sftp_conn *
 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
 {
@@ -270,10 +326,27 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
        while (buffer_len(&msg) > 0) {
                char *name = buffer_get_string(&msg, NULL);
                char *value = buffer_get_string(&msg, NULL);
+               int known = 0;
 
-               debug2("Init extension: \"%s\"", name);
-               if (strcmp(name, "posix-rename@openssh.com") == 0)
+               if (strcmp(name, "posix-rename@openssh.com") == 0 &&
+                   strcmp(value, "1") == 0) {
                        exts |= SFTP_EXT_POSIX_RENAME;
+                       known = 1;
+               } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
+                   strcmp(value, "2") == 0) {
+                       exts |= SFTP_EXT_STATVFS;
+                       known = 1;
+               } if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
+                   strcmp(value, "2") == 0) {
+                       exts |= SFTP_EXT_FSTATVFS;
+                       known = 1;
+               }
+               if (known) {
+                       debug2("Server supports extension \"%s\" revision %s",
+                           name, value);
+               } else {
+                       debug2("Unrecognised server extension \"%s\"", name);
+               }
                xfree(name);
                xfree(value);
        }
@@ -749,6 +822,60 @@ do_readlink(struct sftp_conn *conn, char *path)
 }
 #endif
 
+int
+do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
+    int quiet)
+{
+       Buffer msg;
+       u_int id;
+
+       if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
+               error("Server does not support statvfs@openssh.com extension");
+               return -1;
+       }
+
+       id = conn->msg_id++;
+
+       buffer_init(&msg);
+       buffer_clear(&msg);
+       buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, "statvfs@openssh.com");
+       buffer_put_cstring(&msg, path);
+       send_msg(conn->fd_out, &msg);
+       buffer_free(&msg);
+
+       return get_decode_statvfs(conn->fd_in, st, id, quiet);
+}
+
+#ifdef notyet
+int
+do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
+    struct sftp_statvfs *st, int quiet)
+{
+       Buffer msg;
+       u_int id;
+
+       if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
+               error("Server does not support fstatvfs@openssh.com extension");
+               return -1;
+       }
+
+       id = conn->msg_id++;
+
+       buffer_init(&msg);
+       buffer_clear(&msg);
+       buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, "fstatvfs@openssh.com");
+       buffer_put_string(&msg, handle, handle_len);
+       send_msg(conn->fd_out, &msg);
+       buffer_free(&msg);
+
+       return get_decode_statvfs(conn->fd_in, st, id, quiet);
+}
+#endif
+
 static void
 send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
     char *handle, u_int handle_len)
@@ -793,7 +920,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
        if (a == NULL)
                return(-1);
 
-       /* XXX: should we preserve set[ug]id? */
+       /* Do not preserve set[ug]id here, as we do not preserve ownership */
        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
                mode = a->perm & 0777;
        else
@@ -1096,7 +1223,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
                        len = 0;
                else do
                        len = read(local_fd, data, conn->transfer_buflen);
-               while ((len == -1) && (errno == EINTR || errno == EAGAIN));
+               while ((len == -1) &&
+                   (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
 
                if (len == -1)
                        fatal("Couldn't read from \"%s\": %s", local_path,
index fd0630e9a781e95da0a10d3fc9175601b1f7693a..edb46790f3ed21858f2dbc39bdab82e47365d02a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.h,v 1.15 2008/01/11 07:22:28 chl Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.17 2008/06/08 20:15:29 dtucker Exp $ */
 
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -29,6 +29,24 @@ struct SFTP_DIRENT {
        Attrib a;
 };
 
+/*
+ * Used for statvfs responses on the wire from the server, because the
+ * server's native format may be larger than the client's.
+ */
+struct sftp_statvfs {
+       u_int64_t f_bsize;
+       u_int64_t f_frsize;
+       u_int64_t f_blocks;
+       u_int64_t f_bfree;
+       u_int64_t f_bavail;
+       u_int64_t f_files;
+       u_int64_t f_ffree;
+       u_int64_t f_favail;
+       u_int64_t f_fsid;
+       u_int64_t f_flag;
+       u_int64_t f_namemax;
+};
+
 /*
  * Initialise a SSH filexfer connection. Returns NULL on error or
  * a pointer to a initialized sftp_conn struct on success.
@@ -70,6 +88,9 @@ int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *);
 /* Canonicalise 'path' - caller must free result */
 char *do_realpath(struct sftp_conn *, char *);
 
+/* Get statistics for filesystem hosting file at "path" */
+int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
+
 /* Rename 'oldpath' to 'newpath' */
 int do_rename(struct sftp_conn *, char *, char *);
 
index 7452eca27041191910bfbd22a5d045d7695593df..74c1e4bc53bed1a7b4097e257fb716b10d6154e2 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sftp-server.8,v 1.12 2007/05/31 19:20:16 jmc Exp $
+.\" $OpenBSD: sftp-server.8,v 1.14 2008/07/18 22:51:01 jmc Exp $
 .\"
 .\" Copyright (c) 2000 Markus Friedl.  All rights reserved.
 .\"
@@ -22,7 +22,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: June 5 2007 $
+.Dd $Mdocdate: July 18 2008 $
 .Dt SFTP-SERVER 8
 .Os
 .Sh NAME
@@ -72,6 +72,16 @@ DEBUG and DEBUG1 are equivalent.
 DEBUG2 and DEBUG3 each specify higher levels of debugging output.
 The default is ERROR.
 .El
+.Pp
+For logging to work,
+.Nm
+must be able to access
+.Pa /dev/log .
+Use of
+.Nm
+in a chroot configuation therefore requires that
+.Xr syslogd 8
+establish a logging socket inside the chroot directory.
 .Sh SEE ALSO
 .Xr sftp 1 ,
 .Xr ssh 1 ,
index d9549f5bc66c36be0141cd194c41948014662be5..24c4ff717227550f0c25fd2cc9df2153321f0d06 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-server.c,v 1.78 2008/02/27 20:21:15 djm Exp $ */
+/* $OpenBSD: sftp-server.c,v 1.84 2008/06/26 06:10:09 djm Exp $ */
 /*
  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
  *
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
 
 #include <dirent.h>
 #include <errno.h>
@@ -98,6 +104,9 @@ errno_to_portable(int unixerrno)
        case EINVAL:
                ret = SSH2_FX_BAD_MESSAGE;
                break;
+       case ENOSYS:
+               ret = SSH2_FX_OP_UNSUPPORTED;
+               break;
        default:
                ret = SSH2_FX_FAILURE;
                break;
@@ -475,6 +484,33 @@ send_attrib(u_int32_t id, const Attrib *a)
        buffer_free(&msg);
 }
 
+static void
+send_statvfs(u_int32_t id, struct statvfs *st)
+{
+       Buffer msg;
+       u_int64_t flag;
+
+       flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
+       flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
+       buffer_put_int(&msg, id);
+       buffer_put_int64(&msg, st->f_bsize);
+       buffer_put_int64(&msg, st->f_frsize);
+       buffer_put_int64(&msg, st->f_blocks);
+       buffer_put_int64(&msg, st->f_bfree);
+       buffer_put_int64(&msg, st->f_bavail);
+       buffer_put_int64(&msg, st->f_files);
+       buffer_put_int64(&msg, st->f_ffree);
+       buffer_put_int64(&msg, st->f_favail);
+       buffer_put_int64(&msg, FSID_TO_ULONG(st->f_fsid));
+       buffer_put_int64(&msg, flag);
+       buffer_put_int64(&msg, st->f_namemax);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
 /* parse incoming */
 
 static void
@@ -490,6 +526,12 @@ process_init(void)
        /* POSIX rename extension */
        buffer_put_cstring(&msg, "posix-rename@openssh.com");
        buffer_put_cstring(&msg, "1"); /* version */
+       /* statvfs extension */
+       buffer_put_cstring(&msg, "statvfs@openssh.com");
+       buffer_put_cstring(&msg, "2"); /* version */
+       /* fstatvfs extension */
+       buffer_put_cstring(&msg, "fstatvfs@openssh.com");
+       buffer_put_cstring(&msg, "2"); /* version */
        send_msg(&msg);
        buffer_free(&msg);
 }
@@ -721,7 +763,7 @@ process_setstat(void)
        }
        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
                logit("set \"%s\" mode %04o", name, a->perm);
-               ret = chmod(name, a->perm & 0777);
+               ret = chmod(name, a->perm & 07777);
                if (ret == -1)
                        status = errno_to_portable(errno);
        }
@@ -775,9 +817,9 @@ process_fsetstat(void)
                if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
                        logit("set \"%s\" mode %04o", name, a->perm);
 #ifdef HAVE_FCHMOD
-                       ret = fchmod(fd, a->perm & 0777);
+                       ret = fchmod(fd, a->perm & 07777);
 #else
-                       ret = chmod(name, a->perm & 0777);
+                       ret = chmod(name, a->perm & 07777);
 #endif
                        if (ret == -1)
                                status = errno_to_portable(errno);
@@ -928,7 +970,7 @@ process_mkdir(void)
        name = get_string(NULL);
        a = get_attrib();
        mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
-           a->perm & 0777 : 0777;
+           a->perm & 07777 : 0777;
        debug3("request %u: mkdir", id);
        logit("mkdir name \"%s\" mode 0%o", name, mode);
        ret = mkdir(name, mode);
@@ -1000,6 +1042,9 @@ process_rename(void)
                /* Race-free rename of regular files */
                if (link(oldpath, newpath) == -1) {
                        if (errno == EOPNOTSUPP
+#ifdef EXDEV
+                           || errno == EXDEV
+#endif
 #ifdef LINK_OPNOTSUPP_ERRNO
                            || errno == LINK_OPNOTSUPP_ERRNO
 #endif
@@ -1099,6 +1144,42 @@ process_extended_posix_rename(u_int32_t id)
        xfree(newpath);
 }
 
+static void
+process_extended_statvfs(u_int32_t id)
+{
+       char *path;
+       struct statvfs st;
+
+       path = get_string(NULL);
+       debug3("request %u: statfs", id);
+       logit("statfs \"%s\"", path);
+
+       if (statvfs(path, &st) != 0)
+               send_status(id, errno_to_portable(errno));
+       else
+               send_statvfs(id, &st);
+        xfree(path);
+}
+
+static void
+process_extended_fstatvfs(u_int32_t id)
+{
+       int handle, fd;
+       struct statvfs st;
+
+       handle = get_handle();
+       debug("request %u: fstatvfs \"%s\" (handle %u)",
+           id, handle_to_name(handle), handle);
+       if ((fd = handle_to_fd(handle)) < 0) {
+               send_status(id, SSH2_FX_FAILURE);
+               return;
+       }
+       if (fstatvfs(fd, &st) != 0)
+               send_status(id, errno_to_portable(errno));
+       else
+               send_statvfs(id, &st);
+}
+
 static void
 process_extended(void)
 {
@@ -1109,6 +1190,10 @@ process_extended(void)
        request = get_string(NULL);
        if (strcmp(request, "posix-rename@openssh.com") == 0)
                process_extended_posix_rename(id);
+       else if (strcmp(request, "statvfs@openssh.com") == 0)
+               process_extended_statvfs(id);
+       else if (strcmp(request, "fstatvfs@openssh.com") == 0)
+               process_extended_fstatvfs(id);
        else
                send_status(id, SSH2_FX_OP_UNSUPPORTED);        /* MUST */
        xfree(request);
index 6e025bc99d023e1a815f3fadbbc4a412730fe31c..b4f9a6884554317038573c33ae6736529b962a8f 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sftp.1,v 1.64 2007/05/31 19:20:16 jmc Exp $
+.\" $OpenBSD: sftp.1,v 1.67 2008/07/15 02:23:14 djm Exp $
 .\"
 .\" Copyright (c) 2001 Damien Miller.  All rights reserved.
 .\"
@@ -22,7 +22,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: June 5 2007 $
+.Dd $Mdocdate: July 15 2008 $
 .Dt SFTP 1
 .Os
 .Sh NAME
@@ -112,7 +112,8 @@ will abort if any of the following
 commands fail:
 .Ic get , put , rename , ln ,
 .Ic rm , mkdir , chdir , ls ,
-.Ic lchdir , chmod , chown , chgrp , lpwd
+.Ic lchdir , chmod , chown ,
+.Ic chgrp , lpwd , df ,
 and
 .Ic lmkdir .
 Termination on error can be suppressed on a command by command basis by
@@ -203,7 +204,7 @@ This option may be useful in debugging the client and server.
 Specify how many requests may be outstanding at any one time.
 Increasing this may slightly improve file transfer speed
 but will increase memory usage.
-The default is 16 outstanding requests.
+The default is 64 outstanding requests.
 .It Fl S Ar program
 Name of the
 .Ar program
@@ -272,6 +273,24 @@ may contain
 characters and may match multiple files.
 .Ar own
 must be a numeric UID.
+.It Xo Ic df
+.Op Fl hi
+.Op Ar path
+.Xc
+Display usage information for the filesystem holding the current directory
+(or
+.Ar path
+if specified).
+If the
+.Fl h
+flag is specified, the capacity information will be displayed using
+"human-readable" suffixes.
+The
+.Fl i
+flag requests display of inode information in addition to capacity information.
+This command is only supported on servers that implement the
+.Dq statvfs@openssh.com
+extension.
 .It Ic exit
 Quit
 .Nm sftp .
index 861c3db05031c20f239b578705b958671707ecbe..e1aa49d0f0863eefdacf7b24b8685842c8159188 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.99 2008/01/20 00:38:30 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.103 2008/07/13 22:16:03 djm Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -25,6 +25,9 @@
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
 
 #include <ctype.h>
 #include <errno.h>
@@ -44,6 +47,14 @@ typedef void EditLine;
 #include <unistd.h>
 #include <stdarg.h>
 
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
+
 #include "xmalloc.h"
 #include "log.h"
 #include "pathnames.h"
@@ -64,7 +75,7 @@ int batchmode = 0;
 size_t copy_buffer_len = 32768;
 
 /* Number of concurrent outstanding requests */
-size_t num_requests = 16;
+size_t num_requests = 64;
 
 /* PID of ssh transport process */
 static pid_t sshpid = -1;
@@ -104,6 +115,7 @@ extern char *__progname;
 #define I_CHGRP                2
 #define I_CHMOD                3
 #define I_CHOWN                4
+#define I_DF           24
 #define I_GET          5
 #define I_HELP         6
 #define I_LCHDIR       7
@@ -136,6 +148,7 @@ static const struct CMD cmds[] = {
        { "chgrp",      I_CHGRP },
        { "chmod",      I_CHMOD },
        { "chown",      I_CHOWN },
+       { "df",         I_DF },
        { "dir",        I_LS },
        { "exit",       I_QUIT },
        { "get",        I_GET },
@@ -200,6 +213,8 @@ help(void)
        printf("chgrp grp path                Change group of file 'path' to 'grp'\n");
        printf("chmod mode path               Change permissions of file 'path' to 'mode'\n");
        printf("chown own path                Change owner of file 'path' to 'own'\n");
+       printf("df [path]                     Display statistics for current directory or\n");
+       printf("                              filesystem containing 'path'\n");
        printf("help                          Display this help text\n");
        printf("get remote-path [local-path]  Download file\n");
        printf("lls [ls-options [path]]       Display local directory listing\n");
@@ -349,7 +364,7 @@ infer_path(const char *p, char **ifp)
 static int
 parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
 {
-       extern int optind, optreset, opterr;
+       extern int opterr, optind, optopt, optreset;
        int ch;
 
        optind = optreset = 1;
@@ -363,7 +378,7 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
                        *pflag = 1;
                        break;
                default:
-                       error("%s: Invalid flag -%c", cmd, ch);
+                       error("%s: Invalid flag -%c", cmd, optopt);
                        return -1;
                }
        }
@@ -374,7 +389,7 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
 static int
 parse_ls_flags(char **argv, int argc, int *lflag)
 {
-       extern int optind, optreset, opterr;
+       extern int opterr, optind, optopt, optreset;
        int ch;
 
        optind = optreset = 1;
@@ -413,7 +428,34 @@ parse_ls_flags(char **argv, int argc, int *lflag)
                        *lflag |= LS_TIME_SORT;
                        break;
                default:
-                       error("ls: Invalid flag -%c", ch);
+                       error("ls: Invalid flag -%c", optopt);
+                       return -1;
+               }
+       }
+
+       return optind;
+}
+
+static int
+parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
+{
+       extern int opterr, optind, optopt, optreset;
+       int ch;
+
+       optind = optreset = 1;
+       opterr = 0;
+
+       *hflag = *iflag = 0;
+       while ((ch = getopt(argc, argv, "hi")) != -1) {
+               switch (ch) {
+               case 'h':
+                       *hflag = 1;
+                       break;
+               case 'i':
+                       *iflag = 1;
+                       break;
+               default:
+                       error("%s: Invalid flag -%c", cmd, optopt);
                        return -1;
                }
        }
@@ -797,6 +839,56 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
        return (0);
 }
 
+static int
+do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
+{
+       struct sftp_statvfs st;
+       char s_used[FMT_SCALED_STRSIZE];
+       char s_avail[FMT_SCALED_STRSIZE];
+       char s_root[FMT_SCALED_STRSIZE];
+       char s_total[FMT_SCALED_STRSIZE];
+
+       if (do_statvfs(conn, path, &st, 1) == -1)
+               return -1;
+       if (iflag) {
+               printf("     Inodes        Used       Avail      "
+                   "(root)    %%Capacity\n");
+               printf("%11llu %11llu %11llu %11llu         %3llu%%\n",
+                   (unsigned long long)st.f_files,
+                   (unsigned long long)(st.f_files - st.f_ffree),
+                   (unsigned long long)st.f_favail,
+                   (unsigned long long)st.f_ffree,
+                   (unsigned long long)(100 * (st.f_files - st.f_ffree) /
+                   st.f_files));
+       } else if (hflag) {
+               strlcpy(s_used, "error", sizeof(s_used));
+               strlcpy(s_avail, "error", sizeof(s_avail));
+               strlcpy(s_root, "error", sizeof(s_root));
+               strlcpy(s_total, "error", sizeof(s_total));
+               fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
+               fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
+               fmt_scaled(st.f_bfree * st.f_frsize, s_root);
+               fmt_scaled(st.f_blocks * st.f_frsize, s_total);
+               printf("    Size     Used    Avail   (root)    %%Capacity\n");
+               printf("%7sB %7sB %7sB %7sB         %3llu%%\n",
+                   s_total, s_used, s_avail, s_root,
+                   (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+                   st.f_blocks));
+       } else {
+               printf("        Size         Used        Avail       "
+                   "(root)    %%Capacity\n");
+               printf("%12llu %12llu %12llu %12llu         %3llu%%\n",
+                   (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
+                   (unsigned long long)(st.f_frsize *
+                   (st.f_blocks - st.f_bfree) / 1024),
+                   (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
+                   (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
+                   (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+                   st.f_blocks));
+       }
+       return 0;
+}
+
 /*
  * Undo escaping of glob sequences in place. Used to undo extra escaping
  * applied in makeargv() when the string is destined for a function that
@@ -972,7 +1064,7 @@ makeargv(const char *arg, int *argcp)
 }
 
 static int
-parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
+parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag,
     unsigned long *n_arg, char **path1, char **path2)
 {
        const char *cmd, *cp = *cpp;
@@ -1016,7 +1108,7 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
        }
 
        /* Get arguments and parse flags */
-       *lflag = *pflag = *n_arg = 0;
+       *lflag = *pflag = *hflag = *n_arg = 0;
        *path1 = *path2 = NULL;
        optidx = 1;
        switch (cmdnum) {
@@ -1068,6 +1160,18 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
                if (cmdnum != I_RM)
                        undo_glob_escape(*path1);
                break;
+       case I_DF:
+               if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
+                   iflag)) == -1)
+                       return -1;
+               /* Default to current directory if no path specified */
+               if (argc - optidx < 1)
+                       *path1 = NULL;
+               else {
+                       *path1 = xstrdup(argv[optidx]);
+                       undo_glob_escape(*path1);
+               }
+               break;
        case I_LS:
                if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
                        return(-1);
@@ -1130,7 +1234,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
     int err_abort)
 {
        char *path1, *path2, *tmp;
-       int pflag, lflag, iflag, cmdnum, i;
+       int pflag, lflag, iflag, hflag, cmdnum, i;
        unsigned long n_arg;
        Attrib a, *aa;
        char path_buf[MAXPATHLEN];
@@ -1138,7 +1242,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
        glob_t g;
 
        path1 = path2 = NULL;
-       cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg,
+       cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &hflag, &n_arg,
            &path1, &path2);
 
        if (iflag != 0)
@@ -1232,6 +1336,13 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
                path1 = make_absolute(path1, *pwd);
                err = do_globbed_ls(conn, path1, tmp, lflag);
                break;
+       case I_DF:
+               /* Default to current directory if no path specified */
+               if (path1 == NULL)
+                       path1 = xstrdup(*pwd);
+               path1 = make_absolute(path1, *pwd);
+               err = do_df(conn, path1, hflag, iflag);
+               break;
        case I_LCHDIR:
                if (chdir(path1) == -1) {
                        error("Couldn't change local directory to "
index 0835da6ed414dab32fedebc9059334a85e293717..2bde8bb7ff0aa36f4362b5e28ecda49a332abcea 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.h,v 1.7 2008/02/08 23:24:07 djm Exp $ */
+/* $OpenBSD: sftp.h,v 1.9 2008/06/13 00:12:02 dtucker Exp $ */
 
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
 #define SSH2_FXF_TRUNC                 0x00000010
 #define SSH2_FXF_EXCL                  0x00000020
 
+/* statvfs@openssh.com f_flag flags */
+#define SSH2_FXE_STATVFS_ST_RDONLY     0x00000001
+#define SSH2_FXE_STATVFS_ST_NOSUID     0x00000002
+
 /* status messages */
 #define SSH2_FX_OK                     0
 #define SSH2_FX_EOF                    1
@@ -94,4 +98,4 @@
 struct passwd;
 
 int    sftp_server_main(int, char **, struct passwd *);
-void   sftp_server_cleanup_exit(int) __dead;
+void   sftp_server_cleanup_exit(int) __attribute__((noreturn));
index 0081be54fed63eb11b88d5b086797a65bd57c3bc..6a5dc62afd83e04f0d78824e65c587f394360ae8 100644 (file)
@@ -34,7 +34,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: September 17 2007 $
+.Dd $Mdocdate: June 5 2007 $
 .Dt SSH-AGENT 1
 .Os
 .Sh NAME
index 6f8727b33066b5279c1705c992a8bb1a008712a3..9123cfe6baf886b087c95c139ef2d96811231634 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.157 2007/09/25 23:48:57 canacar Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.159 2008/06/28 14:05:15 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -312,6 +312,7 @@ process_sign_request2(SocketEntry *e)
        u_char *blob, *data, *signature = NULL;
        u_int blen, dlen, slen = 0;
        extern int datafellows;
+       int odatafellows;
        int ok = -1, flags;
        Buffer msg;
        Key *key;
@@ -322,6 +323,7 @@ process_sign_request2(SocketEntry *e)
        data = buffer_get_string(&e->request, &dlen);
 
        flags = buffer_get_int(&e->request);
+       odatafellows = datafellows;
        if (flags & SSH_AGENT_OLD_SIGNATURE)
                datafellows = SSH_BUG_SIGBLOB;
 
@@ -347,6 +349,7 @@ process_sign_request2(SocketEntry *e)
        xfree(blob);
        if (signature != NULL)
                xfree(signature);
+       datafellows = odatafellows;
 }
 
 /* shared */
@@ -526,9 +529,8 @@ process_add_identity(SocketEntry *e, int version)
                xfree(comment);
                goto send;
        }
-       success = 1;
        while (buffer_len(&e->request)) {
-               switch (buffer_get_char(&e->request)) {
+               switch ((type = buffer_get_char(&e->request))) {
                case SSH_AGENT_CONSTRAIN_LIFETIME:
                        death = time(NULL) + buffer_get_int(&e->request);
                        break;
@@ -536,9 +538,14 @@ process_add_identity(SocketEntry *e, int version)
                        confirm = 1;
                        break;
                default:
-                       break;
+                       error("process_add_identity: "
+                           "Unknown constraint type %d", type);
+                       xfree(comment);
+                       key_free(k);
+                       goto send;
                }
        }
+       success = 1;
        if (lifetime && !death)
                death = time(NULL) + lifetime;
        if ((id = lookup_identity(k, version)) == NULL) {
@@ -604,10 +611,10 @@ no_identities(SocketEntry *e, u_int type)
 
 #ifdef SMARTCARD
 static void
-process_add_smartcard_key (SocketEntry *e)
+process_add_smartcard_key(SocketEntry *e)
 {
        char *sc_reader_id = NULL, *pin;
-       int i, version, success = 0, death = 0, confirm = 0;
+       int i, type, version, success = 0, death = 0, confirm = 0;
        Key **keys, *k;
        Identity *id;
        Idtab *tab;
@@ -616,7 +623,7 @@ process_add_smartcard_key (SocketEntry *e)
        pin = buffer_get_string(&e->request, NULL);
 
        while (buffer_len(&e->request)) {
-               switch (buffer_get_char(&e->request)) {
+               switch ((type = buffer_get_char(&e->request))) {
                case SSH_AGENT_CONSTRAIN_LIFETIME:
                        death = time(NULL) + buffer_get_int(&e->request);
                        break;
@@ -624,7 +631,11 @@ process_add_smartcard_key (SocketEntry *e)
                        confirm = 1;
                        break;
                default:
-                       break;
+                       error("process_add_smartcard_key: "
+                           "Unknown constraint type %d", type);
+                       xfree(sc_reader_id);
+                       xfree(pin);
+                       goto send;
                }
        }
        if (lifetime && !death)
@@ -950,7 +961,8 @@ after_select(fd_set *readset, fd_set *writeset)
                                            buffer_ptr(&sockets[i].output),
                                            buffer_len(&sockets[i].output));
                                        if (len == -1 && (errno == EAGAIN ||
-                                           errno == EINTR))
+                                           errno == EINTR ||
+                                           errno == EWOULDBLOCK))
                                                continue;
                                        break;
                                } while (1);
@@ -964,7 +976,8 @@ after_select(fd_set *readset, fd_set *writeset)
                                do {
                                        len = read(sockets[i].fd, buf, sizeof(buf));
                                        if (len == -1 && (errno == EAGAIN ||
-                                           errno == EINTR))
+                                           errno == EINTR ||
+                                           errno == EWOULDBLOCK))
                                                continue;
                                        break;
                                } while (1);
index 4e629de746d11057f0357f602d4803b4f2fd7bab..3fff59e770825fe3590c385910b582f4e2fab1fa 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-keygen.1,v 1.75 2007/05/31 19:20:16 jmc Exp $
+.\"    $OpenBSD: ssh-keygen.1,v 1.78 2008/06/12 19:10:09 jmc Exp $
 .\"
 .\"  -*- nroff -*-
 .\"
@@ -37,7 +37,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: June 5 2007 $
+.Dd $Mdocdate: June 12 2008 $
 .Dt SSH-KEYGEN 1
 .Os
 .Sh NAME
@@ -262,6 +262,9 @@ Private RSA1 keys are also supported.
 For RSA and DSA keys
 .Nm
 tries to find the matching public key file and prints its fingerprint.
+If combined with
+.Fl v ,
+an ASCII art representation of the key is supplied with the fingerprint.
 .It Fl M Ar memory
 Specify the amount of memory to use (in megabytes) when generating
 candidate moduli for DH-GEX.
index 69b16e6f50e2ffe4ef8410b4cee772fe24d3930b..f7e28406215286c0b53221c331ab403e9acc12a8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.165 2008/01/19 22:37:19 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.171 2008/07/13 21:22:52 sthen Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -72,6 +72,8 @@ int change_comment = 0;
 
 int quiet = 0;
 
+int log_level = SYSLOG_LEVEL_INFO;
+
 /* Flag indicating that we want to hash a known_hosts file */
 int hash_hosts = 0;
 /* Flag indicating that we want lookup a host in known_hosts file */
@@ -504,7 +506,7 @@ do_fingerprint(struct passwd *pw)
 {
        FILE *f;
        Key *public;
-       char *comment = NULL, *cp, *ep, line[16*1024], *fp;
+       char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
        int i, skip = 0, num = 0, invalid = 1;
        enum fp_rep rep;
        enum fp_type fptype;
@@ -522,9 +524,14 @@ do_fingerprint(struct passwd *pw)
        public = key_load_public(identity_file, &comment);
        if (public != NULL) {
                fp = key_fingerprint(public, fptype, rep);
-               printf("%u %s %s\n", key_size(public), fp, comment);
+               ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
+               printf("%u %s %s (%s)\n", key_size(public), fp, comment,
+                   key_type(public));
+               if (log_level >= SYSLOG_LEVEL_VERBOSE)
+                       printf("%s\n", ra);
                key_free(public);
                xfree(comment);
+               xfree(ra);
                xfree(fp);
                exit(0);
        }
@@ -582,8 +589,12 @@ do_fingerprint(struct passwd *pw)
                        }
                        comment = *cp ? cp : comment;
                        fp = key_fingerprint(public, fptype, rep);
-                       printf("%u %s %s\n", key_size(public), fp,
-                           comment ? comment : "no comment");
+                       ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
+                       printf("%u %s %s (%s)\n", key_size(public), fp,
+                           comment ? comment : "no comment", key_type(public));
+                       if (log_level >= SYSLOG_LEVEL_VERBOSE)
+                               printf("%s\n", ra);
+                       xfree(ra);
                        xfree(fp);
                        key_free(public);
                        invalid = 0;
@@ -600,12 +611,29 @@ do_fingerprint(struct passwd *pw)
 static void
 print_host(FILE *f, const char *name, Key *public, int hash)
 {
-       if (hash && (name = host_hash(name, NULL, 0)) == NULL)
-               fatal("hash_host failed");
-       fprintf(f, "%s ", name);
-       if (!key_write(public, f))
-               fatal("key_write failed");
-       fprintf(f, "\n");
+       if (print_fingerprint) {
+               enum fp_rep rep;
+               enum fp_type fptype;
+               char *fp, *ra;
+
+               fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
+               rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
+               fp = key_fingerprint(public, fptype, rep);
+               ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
+               printf("%u %s %s (%s)\n", key_size(public), fp, name,
+                   key_type(public));
+               if (log_level >= SYSLOG_LEVEL_VERBOSE)
+                       printf("%s\n", ra);
+               xfree(ra);
+               xfree(fp);
+       } else {
+               if (hash && (name = host_hash(name, NULL, 0)) == NULL)
+                       fatal("hash_host failed");
+               fprintf(f, "%s ", name);
+               if (!key_write(public, f))
+                       fatal("key_write failed");
+               fprintf(f, "\n");
+       }
 }
 
 static void
@@ -1058,7 +1086,6 @@ main(int argc, char **argv)
        int opt, type, fd, download = 0;
        u_int32_t memory = 0, generator_wanted = 0, trials = 100;
        int do_gen_candidates = 0, do_screen_candidates = 0;
-       int log_level = SYSLOG_LEVEL_INFO;
        BIGNUM *start = NULL;
        FILE *f;
        const char *errstr;
@@ -1231,6 +1258,10 @@ main(int argc, char **argv)
                printf("Can only have one of -p and -c.\n");
                usage();
        }
+       if (print_fingerprint && (delete_host || hash_hosts)) {
+               printf("Cannot use -l with -D or -R.\n");
+               usage();
+       }
        if (delete_host || hash_hosts || find_host)
                do_known_hosts(pw, rr_hostname);
        if (print_fingerprint || print_bubblebabble)
@@ -1435,10 +1466,15 @@ passphrase_again:
 
        if (!quiet) {
                char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
+               char *ra = key_fingerprint(public, SSH_FP_MD5,
+                   SSH_FP_RANDOMART);
                printf("Your public key has been saved in %s.\n",
                    identity_file);
                printf("The key fingerprint is:\n");
                printf("%s %s\n", fp, comment);
+               printf("The key's randomart image is:\n");
+               printf("%s\n", ra);
+               xfree(ra);
                xfree(fp);
        }
 
index 005e57a2b3fe6ba14a54ca682af7721ecca27343..8a4f3bcba3cff209d7234a34a3fa22086d3e0ac8 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-keyscan.1,v 1.23 2007/05/31 19:20:16 jmc Exp $
+.\"    $OpenBSD: ssh-keyscan.1,v 1.24 2008/04/30 10:14:03 djm Exp $
 .\"
 .\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
 .\"
@@ -6,7 +6,7 @@
 .\" permitted provided that due credit is given to the author and the
 .\" OpenBSD project by leaving this copyright notice intact.
 .\"
-.Dd $Mdocdate: June 5 2007 $
+.Dd $Mdocdate: April 30 2008 $
 .Dt SSH-KEYSCAN 1
 .Os
 .Sh NAME
@@ -94,7 +94,7 @@ or
 for protocol version 2.
 Multiple values may be specified by separating them with commas.
 The default is
-.Dq rsa1 .
+.Dq rsa .
 .It Fl v
 Verbose mode.
 Causes
index 43ebfee552e618d523b136a61940e7588f9ed2c0..d810777646e4fc8d434bc452d999344630b1c4b5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keyscan.c,v 1.75 2007/12/27 14:22:08 dtucker Exp $ */
+/* $OpenBSD: ssh-keyscan.c,v 1.76 2008/04/30 10:14:03 djm Exp $ */
 /*
  * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
  *
@@ -56,7 +56,7 @@ int ssh_port = SSH_DEFAULT_PORT;
 #define KT_DSA 2
 #define KT_RSA 4
 
-int get_keytypes = KT_RSA1;    /* Get only RSA1 keys by default */
+int get_keytypes = KT_RSA;     /* Get only RSA keys by default */
 
 int hash_hosts = 0;            /* Hash hostname on output */
 
@@ -656,7 +656,7 @@ conloop(void)
        memcpy(e, read_wait, read_wait_nfdset * sizeof(fd_mask));
 
        while (select(maxfd, r, NULL, e, &seltime) == -1 &&
-           (errno == EAGAIN || errno == EINTR))
+           (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
                ;
 
        for (i = 0; i < maxfd; i++) {
index 814bcb66e9760f855db653af85d5ff03523990c1..3ba54b935ff1368139acde745cb14c939c81384a 100644 (file)
@@ -22,7 +22,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: June 5 2007 $
+.Dd $Mdocdate: May 31 2007 $
 .Dt SSH-KEYSIGN 8
 .Os
 .Sh NAME
index d62df903263c5ffdf0ac1a3a17431180d0d38481..1883578f2269c53318dc81c1a865ccda086c3a23 100644 (file)
@@ -34,8 +34,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: ssh.1,v 1.273 2008/02/11 07:58:28 jmc Exp $
-.Dd $Mdocdate: March 26 2008 $
+.\" $OpenBSD: ssh.1,v 1.277 2008/07/02 13:47:39 djm Exp $
+.Dd $Mdocdate: July 2 2008 $
 .Dt SSH 1
 .Os
 .Sh NAME
@@ -290,6 +290,15 @@ This implies
 The recommended way to start X11 programs at a remote site is with
 something like
 .Ic ssh -f host xterm .
+.Pp
+If the
+.Cm ExitOnForwardFailure
+configuration option is set to
+.Dq yes ,
+then a client started with
+.Fl f
+will wait for all remote port forwards to be successfully established
+before placing itself in the background.
 .It Fl g
 Allows remote hosts to connect to local forwarded ports.
 .It Fl I Ar smartcard_device
@@ -498,6 +507,7 @@ For full details of the options listed below, and their possible values, see
 .It User
 .It UserKnownHostsFile
 .It VerifyHostKeyDNS
+.It VisualHostKey
 .It XAuthLocation
 .El
 .It Fl p Ar port
@@ -1027,9 +1037,31 @@ Fingerprints can be determined using
 .Pp
 .Dl $ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
 .Pp
-If the fingerprint is already known,
-it can be matched and verified,
-and the key can be accepted.
+If the fingerprint is already known, it can be matched
+and the key can be accepted or rejected.
+Because of the difficulty of comparing host keys
+just by looking at hex strings,
+there is also support to compare host keys visually,
+using
+.Em random art .
+By setting the
+.Cm VisualHostKey
+option to
+.Dq yes ,
+a small ASCII graphic gets displayed on every login to a server, no matter
+if the session itself is interactive or not.
+By learning the pattern a known server produces, a user can easily
+find out that the host key has changed when a completely different pattern
+is displayed.
+Because these patterns are not unambiguous however, a pattern that looks
+similar to the pattern remembered only gives a good probability that the
+host key is the same, not guaranteed proof.
+.Pp
+To get a listing of the fingerprints along with their random art for
+all known hosts, the following command line can be used:
+.Pp
+.Dl $ ssh-keygen -lv -f ~/.ssh/known_hosts
+.Pp
 If the fingerprint is unknown,
 an alternative method of verification is available:
 SSH fingerprints verified by DNS.
@@ -1433,6 +1465,13 @@ manual page for more information.
 .%T "The Secure Shell (SSH) Public Key File Format"
 .%D 2006
 .Re
+.Rs
+.%T "Hash Visualization: a New Technique to improve Real-World Security"
+.%A A. Perrig
+.%A D. Song
+.%D 1999
+.%O "International Workshop on Cryptographic Techniques and E-Commerce (CrypTEC '99)"
+.Re
 .Sh AUTHORS
 OpenSSH is a derivative of the original and free
 ssh 1.2.12 release by Tatu Ylonen.
index 2ed76c9a122ff38c93c781b1335080450670dd81..e2dd67d688bdad9a74c94180a03bf5b50da3314f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.309 2008/01/19 20:51:26 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.318 2008/07/02 13:47:39 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -49,7 +49,6 @@
 #include <sys/resource.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
-#include <sys/un.h>
 
 #include <ctype.h>
 #include <errno.h>
@@ -73,6 +72,7 @@
 #include <openssl/evp.h>
 #include <openssl/err.h>
 #include "openbsd-compat/openssl-compat.h"
+#include "openbsd-compat/sys-queue.h"
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -98,7 +98,6 @@
 #include "sshpty.h"
 #include "match.h"
 #include "msg.h"
-#include "monitor_fdpass.h"
 #include "uidswap.h"
 #include "version.h"
 
 
 extern char *__progname;
 
-/* Flag indicating whether debug mode is on.  This can be set on the command line. */
+/* Flag indicating whether debug mode is on.  May be set on the command line. */
 int debug_flag = 0;
 
 /* Flag indicating whether a tty should be allocated */
@@ -165,20 +164,14 @@ Buffer command;
 int subsystem_flag = 0;
 
 /* # of replies received for global requests */
-static int client_global_request_id = 0;
+static int remote_forward_confirms_received = 0;
 
 /* pid of proxycommand child process */
 pid_t proxy_command_pid = 0;
 
-/* fd to control socket */
-int control_fd = -1;
-
-/* Multiplexing control command */
-static u_int mux_command = 0;
-
-/* Only used in control client mode */
-volatile sig_atomic_t control_client_terminate = 0;
-u_int control_server_pid = 0;
+/* mux.c */
+extern int muxserver_sock;
+extern u_int muxclient_command;
 
 /* Prints a help message to the user.  This function never returns. */
 
@@ -199,7 +192,10 @@ usage(void)
 static int ssh_session(void);
 static int ssh_session2(void);
 static void load_public_identity_files(void);
-static void control_client(const char *path);
+
+/* from muxclient.c */
+void muxclient(const char *);
+void muxserver_listen(void);
 
 /*
  * Main program for the ssh client.
@@ -265,15 +261,18 @@ main(int ac, char **av)
         */
        umask(022);
 
-       /* Initialize option structure to indicate that no values have been set. */
+       /*
+        * Initialize option structure to indicate that no values have been
+        * set.
+        */
        initialize_options(&options);
 
        /* Parse command-line arguments. */
        host = NULL;
 
  again:
-       while ((opt = getopt(ac, av,
-           "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
+       while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
+           "ACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) {
                switch (opt) {
                case '1':
                        options.protocol = SSH_PROTO_1;
@@ -309,9 +308,9 @@ main(int ac, char **av)
                        break;
                case 'O':
                        if (strcmp(optarg, "check") == 0)
-                               mux_command = SSHMUX_COMMAND_ALIVE_CHECK;
+                               muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
                        else if (strcmp(optarg, "exit") == 0)
-                               mux_command = SSHMUX_COMMAND_TERMINATE;
+                               muxclient_command = SSHMUX_COMMAND_TERMINATE;
                        else
                                fatal("Invalid multiplex command.");
                        break;
@@ -378,7 +377,8 @@ main(int ac, char **av)
                                options.tun_open = SSH_TUNMODE_DEFAULT;
                        options.tun_local = a2tun(optarg, &options.tun_remote);
                        if (options.tun_local == SSH_TUNID_ERR) {
-                               fprintf(stderr, "Bad tun device '%s'\n", optarg);
+                               fprintf(stderr,
+                                   "Bad tun device '%s'\n", optarg);
                                exit(255);
                        }
                        break;
@@ -481,7 +481,8 @@ main(int ac, char **av)
                        }
                        if (cp != NULL) {
                                fwd.listen_port = a2port(cp);
-                               fwd.listen_host = cleanhostname(fwd.listen_host);
+                               fwd.listen_host =
+                                   cleanhostname(fwd.listen_host);
                        } else {
                                fwd.listen_port = a2port(fwd.listen_host);
                                fwd.listen_host = NULL;
@@ -587,8 +588,10 @@ main(int ac, char **av)
        }
 
        /* Cannot fork to background if no command. */
-       if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag)
-               fatal("Cannot fork into background without a command to execute.");
+       if (fork_after_authentication_flag && buffer_len(&command) == 0 &&
+           !no_shell_flag)
+               fatal("Cannot fork into background without a command "
+                   "to execute.");
 
        /* Allocate a tty by default if no command specified. */
        if (buffer_len(&command) == 0)
@@ -600,7 +603,8 @@ main(int ac, char **av)
        /* Do not allocate a tty if stdin is not a tty. */
        if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) {
                if (tty_flag)
-                       logit("Pseudo-terminal will not be allocated because stdin is not a terminal.");
+                       logit("Pseudo-terminal will not be allocated because "
+                           "stdin is not a terminal.");
                tty_flag = 0;
        }
 
@@ -608,7 +612,8 @@ main(int ac, char **av)
         * Initialize "log" output.  Since we are the client all output
         * actually goes to stderr.
         */
-       log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
+       log_init(av[0],
+           options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
            SYSLOG_FACILITY_USER, 1);
 
        /*
@@ -642,6 +647,28 @@ main(int ac, char **av)
        if (options.user == NULL)
                options.user = xstrdup(pw->pw_name);
 
+       /* Get default port if port has not been set. */
+       if (options.port == 0) {
+               sp = getservbyname(SSH_SERVICE_NAME, "tcp");
+               options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
+       }
+
+       if (options.local_command != NULL) {
+               char thishost[NI_MAXHOST];
+
+               if (gethostname(thishost, sizeof(thishost)) == -1)
+                       fatal("gethostname: %s", strerror(errno));
+               snprintf(buf, sizeof(buf), "%d", options.port);
+               debug3("expanding LocalCommand: %s", options.local_command);
+               cp = options.local_command;
+               options.local_command = percent_expand(cp, "d", pw->pw_dir,
+                   "h", options.hostname? options.hostname : host,
+                    "l", thishost, "n", host, "r", options.user, "p", buf,
+                    "u", pw->pw_name, (char *)NULL);
+               debug3("expanded LocalCommand: %s", options.local_command);
+               xfree(cp);
+       }
+
        if (options.hostname != NULL)
                host = options.hostname;
 
@@ -652,12 +679,6 @@ main(int ac, char **av)
                                *p = (char)tolower(*p);
        }
 
-       /* Get default port if port has not been set. */
-       if (options.port == 0) {
-               sp = getservbyname(SSH_SERVICE_NAME, "tcp");
-               options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
-       }
-
        if (options.proxy_command != NULL &&
            strcmp(options.proxy_command, "none") == 0) {
                xfree(options.proxy_command);
@@ -682,10 +703,10 @@ main(int ac, char **av)
                    "r", options.user, "l", thishost, (char *)NULL);
                xfree(cp);
        }
-       if (mux_command != 0 && options.control_path == NULL)
+       if (muxclient_command != 0 && options.control_path == NULL)
                fatal("No ControlPath specified for \"-O\" command");
        if (options.control_path != NULL)
-               control_client(options.control_path);
+               muxclient(options.control_path);
 
        timeout_ms = options.connection_timeout * 1000;
 
@@ -757,7 +778,8 @@ main(int ac, char **av)
         * Now that we are back to our own permissions, create ~/.ssh
         * directory if it doesn't already exist.
         */
-       snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
+       snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir,
+           strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
        if (stat(buf, &st) < 0)
                if (mkdir(buf, 0700) < 0)
                        error("Could not create directory '%.200s'.", buf);
@@ -778,7 +800,7 @@ main(int ac, char **av)
 
        signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
 
-       /* Log into the remote system.  This never returns if the login fails. */
+       /* Log into the remote system.  Never returns if the login fails. */
        ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
            pw, timeout_ms);
 
@@ -808,7 +830,7 @@ main(int ac, char **av)
        exit_status = compat20 ? ssh_session2() : ssh_session();
        packet_close();
 
-       if (options.control_path != NULL && control_fd != -1)
+       if (options.control_path != NULL && muxserver_sock != -1)
                unlink(options.control_path);
 
        /*
@@ -821,6 +843,34 @@ main(int ac, char **av)
        return exit_status;
 }
 
+/* Callback for remote forward global requests */
+static void
+ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
+{
+       Forward *rfwd = (Forward *)ctxt;
+
+       debug("remote forward %s for: listen %d, connect %s:%d",
+           type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
+           rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
+       if (type == SSH2_MSG_REQUEST_FAILURE) {
+               if (options.exit_on_forward_failure)
+                       fatal("Error: remote port forwarding failed for "
+                           "listen port %d", rfwd->listen_port);
+               else
+                       logit("Warning: remote port forwarding failed for "
+                           "listen port %d", rfwd->listen_port);
+       }
+       if (++remote_forward_confirms_received == options.num_remote_forwards) {
+               debug("All remote forwarding requests processed");
+               if (fork_after_authentication_flag) {
+                       fork_after_authentication_flag = 0;
+                       if (daemon(1, 1) < 0)
+                               fatal("daemon() failed: %.200s",
+                                   strerror(errno));
+               }
+       }
+}
+
 static void
 ssh_init_forwarding(void)
 {
@@ -869,6 +919,8 @@ ssh_init_forwarding(void)
                                logit("Warning: Could not request remote "
                                    "forwarding.");
                }
+               client_register_global_confirm(ssh_confirm_remote_forward,
+                   &options.remote_forwards[i]);
        }
 
        /* Initiate tunnel forwarding. */
@@ -905,10 +957,13 @@ ssh_session(void)
 
        /* Enable compression if requested. */
        if (options.compression) {
-               debug("Requesting compression at level %d.", options.compression_level);
+               debug("Requesting compression at level %d.",
+                   options.compression_level);
 
-               if (options.compression_level < 1 || options.compression_level > 9)
-                       fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
+               if (options.compression_level < 1 ||
+                   options.compression_level > 9)
+                       fatal("Compression level must be from 1 (fast) to "
+                           "9 (slow, best).");
 
                /* Send the request. */
                packet_start(SSH_CMSG_REQUEST_COMPRESSION);
@@ -921,7 +976,8 @@ ssh_session(void)
                else if (type == SSH_SMSG_FAILURE)
                        logit("Warning: Remote host refused compression.");
                else
-                       packet_disconnect("Protocol error waiting for compression response.");
+                       packet_disconnect("Protocol error waiting for "
+                           "compression response.");
        }
        /* Allocate a pseudo tty if appropriate. */
        if (tty_flag) {
@@ -958,9 +1014,11 @@ ssh_session(void)
                        interactive = 1;
                        have_tty = 1;
                } else if (type == SSH_SMSG_FAILURE)
-                       logit("Warning: Remote host failed or refused to allocate a pseudo tty.");
+                       logit("Warning: Remote host failed or refused to "
+                           "allocate a pseudo tty.");
                else
-                       packet_disconnect("Protocol error waiting for pty request response.");
+                       packet_disconnect("Protocol error waiting for pty "
+                           "request response.");
        }
        /* Request X11 forwarding if enabled and DISPLAY is set. */
        display = getenv("DISPLAY");
@@ -970,7 +1028,8 @@ ssh_session(void)
                client_x11_get_proto(display, options.xauth_location,
                    options.forward_x11_trusted, &proto, &data);
                /* Request forwarding with authentication spoofing. */
-               debug("Requesting X11 forwarding with authentication spoofing.");
+               debug("Requesting X11 forwarding with authentication "
+                   "spoofing.");
                x11_request_forwarding_with_spoofing(0, display, proto, data);
 
                /* Read response from the server. */
@@ -980,7 +1039,8 @@ ssh_session(void)
                } else if (type == SSH_SMSG_FAILURE) {
                        logit("Warning: Remote host denied X11 forwarding.");
                } else {
-                       packet_disconnect("Protocol error waiting for X11 forwarding");
+                       packet_disconnect("Protocol error waiting for X11 "
+                           "forwarding");
                }
        }
        /* Tell the packet module whether this is an interactive session. */
@@ -1008,10 +1068,17 @@ ssh_session(void)
            options.permit_local_command)
                ssh_local_cmd(options.local_command);
 
-       /* If requested, let ssh continue in the background. */
-       if (fork_after_authentication_flag)
+       /*
+        * If requested and we are not interested in replies to remote
+        * forwarding requests, then let ssh continue in the background.
+        */
+       if (fork_after_authentication_flag &&
+           (!options.exit_on_forward_failure ||
+           options.num_remote_forwards == 0)) {
+               fork_after_authentication_flag = 0;
                if (daemon(1, 1) < 0)
                        fatal("daemon() failed: %.200s", strerror(errno));
+       }
 
        /*
         * If a command was specified on the command line, execute the
@@ -1021,7 +1088,8 @@ ssh_session(void)
                int len = buffer_len(&command);
                if (len > 900)
                        len = 900;
-               debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
+               debug("Sending command: %.*s", len,
+                   (u_char *)buffer_ptr(&command));
                packet_start(SSH_CMSG_EXEC_CMD);
                packet_put_string(buffer_ptr(&command), buffer_len(&command));
                packet_send();
@@ -1038,88 +1106,6 @@ ssh_session(void)
            options.escape_char : SSH_ESCAPECHAR_NONE, 0);
 }
 
-static void
-ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)
-{
-       int id, len;
-
-       id = packet_get_int();
-       len = buffer_len(&command);
-       if (len > 900)
-               len = 900;
-       packet_check_eom();
-       if (type == SSH2_MSG_CHANNEL_FAILURE)
-               fatal("Request for subsystem '%.*s' failed on channel %d",
-                   len, (u_char *)buffer_ptr(&command), id);
-}
-
-void
-client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
-{
-       int i;
-
-       i = client_global_request_id++;
-       if (i >= options.num_remote_forwards)
-               return;
-       debug("remote forward %s for: listen %d, connect %s:%d",
-           type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
-           options.remote_forwards[i].listen_port,
-           options.remote_forwards[i].connect_host,
-           options.remote_forwards[i].connect_port);
-       if (type == SSH2_MSG_REQUEST_FAILURE) {
-               if (options.exit_on_forward_failure)
-                       fatal("Error: remote port forwarding failed for "
-                           "listen port %d",
-                           options.remote_forwards[i].listen_port);
-               else
-                       logit("Warning: remote port forwarding failed for "
-                           "listen port %d",
-                           options.remote_forwards[i].listen_port);
-       }
-}
-
-static void
-ssh_control_listener(void)
-{
-       struct sockaddr_un addr;
-       mode_t old_umask;
-       int addr_len;
-
-       if (options.control_path == NULL ||
-           options.control_master == SSHCTL_MASTER_NO)
-               return;
-
-       debug("setting up multiplex master socket");
-
-       memset(&addr, '\0', sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       addr_len = offsetof(struct sockaddr_un, sun_path) +
-           strlen(options.control_path) + 1;
-
-       if (strlcpy(addr.sun_path, options.control_path,
-           sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
-               fatal("ControlPath too long");
-
-       if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
-               fatal("%s socket(): %s", __func__, strerror(errno));
-
-       old_umask = umask(0177);
-       if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) {
-               control_fd = -1;
-               if (errno == EINVAL || errno == EADDRINUSE)
-                       fatal("ControlSocket %s already exists",
-                           options.control_path);
-               else
-                       fatal("%s bind(): %s", __func__, strerror(errno));
-       }
-       umask(old_umask);
-
-       if (listen(control_fd, 64) == -1)
-               fatal("%s listen(): %s", __func__, strerror(errno));
-
-       set_nonblock(control_fd);
-}
-
 /* request pty/x11/agent/tcpfwd/shell for channel */
 static void
 ssh_session2_setup(int id, void *arg)
@@ -1135,7 +1121,8 @@ ssh_session2_setup(int id, void *arg)
                client_x11_get_proto(display, options.xauth_location,
                    options.forward_x11_trusted, &proto, &data);
                /* Request forwarding with authentication spoofing. */
-               debug("Requesting X11 forwarding with authentication spoofing.");
+               debug("Requesting X11 forwarding with authentication "
+                   "spoofing.");
                x11_request_forwarding_with_spoofing(id, display, proto, data);
                interactive = 1;
                /* XXX wait for reply */
@@ -1149,7 +1136,7 @@ ssh_session2_setup(int id, void *arg)
        }
 
        client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
-           NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);
+           NULL, fileno(stdin), &command, environ);
 
        packet_set_interactive(interactive);
 }
@@ -1195,7 +1182,8 @@ ssh_session2_open(void)
 
        channel_send_open(c->self);
        if (!no_shell_flag)
-               channel_register_confirm(c->self, ssh_session2_setup, NULL);
+               channel_register_open_confirm(c->self,
+                   ssh_session2_setup, NULL);
 
        return c->self;
 }
@@ -1211,18 +1199,29 @@ ssh_session2(void)
        if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
                id = ssh_session2_open();
 
+       /* If we don't expect to open a new session, then disallow it */
+       if (options.control_master == SSHCTL_MASTER_NO) {
+               debug("Requesting no-more-sessions@openssh.com");
+               packet_start(SSH2_MSG_GLOBAL_REQUEST);
+               packet_put_cstring("no-more-sessions@openssh.com");
+               packet_put_char(0);
+               packet_send();
+       }
+
        /* Execute a local command */
        if (options.local_command != NULL &&
            options.permit_local_command)
                ssh_local_cmd(options.local_command);
 
        /* Start listening for multiplex clients */
-       ssh_control_listener();
+       muxserver_listen();
 
        /* If requested, let ssh continue in the background. */
-       if (fork_after_authentication_flag)
+       if (fork_after_authentication_flag) {
+               fork_after_authentication_flag = 0;
                if (daemon(1, 1) < 0)
                        fatal("daemon() failed: %.200s", strerror(errno));
+       }
 
        return client_loop(tty_flag, tty_flag ?
            options.escape_char : SSH_ESCAPECHAR_NONE, id);
@@ -1245,9 +1244,11 @@ load_public_identity_files(void)
                int count = 0;
                for (i = 0; keys[i] != NULL; i++) {
                        count++;
-                       memmove(&options.identity_files[1], &options.identity_files[0],
+                       memmove(&options.identity_files[1],
+                           &options.identity_files[0],
                            sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));
-                       memmove(&options.identity_keys[1], &options.identity_keys[0],
+                       memmove(&options.identity_keys[1],
+                           &options.identity_keys[0],
                            sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
                        options.num_identity_files++;
                        options.identity_keys[0] = keys[i];
@@ -1285,237 +1286,3 @@ load_public_identity_files(void)
        bzero(pwdir, strlen(pwdir));
        xfree(pwdir);
 }
-
-static void
-control_client_sighandler(int signo)
-{
-       control_client_terminate = signo;
-}
-
-static void
-control_client_sigrelay(int signo)
-{
-       int save_errno = errno;
-
-       if (control_server_pid > 1)
-               kill(control_server_pid, signo);
-
-       errno = save_errno;
-}
-
-static int
-env_permitted(char *env)
-{
-       int i, ret;
-       char name[1024], *cp;
-
-       if ((cp = strchr(env, '=')) == NULL || cp == env)
-               return (0);
-       ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
-       if (ret <= 0 || (size_t)ret >= sizeof(name))
-               fatal("env_permitted: name '%.100s...' too long", env);
-
-       for (i = 0; i < options.num_send_env; i++)
-               if (match_pattern(name, options.send_env[i]))
-                       return (1);
-
-       return (0);
-}
-
-static void
-control_client(const char *path)
-{
-       struct sockaddr_un addr;
-       int i, r, fd, sock, exitval[2], num_env, addr_len;
-       Buffer m;
-       char *term;
-       extern char **environ;
-       u_int  flags;
-
-       if (mux_command == 0)
-               mux_command = SSHMUX_COMMAND_OPEN;
-
-       switch (options.control_master) {
-       case SSHCTL_MASTER_AUTO:
-       case SSHCTL_MASTER_AUTO_ASK:
-               debug("auto-mux: Trying existing master");
-               /* FALLTHROUGH */
-       case SSHCTL_MASTER_NO:
-               break;
-       default:
-               return;
-       }
-
-       memset(&addr, '\0', sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       addr_len = offsetof(struct sockaddr_un, sun_path) +
-           strlen(path) + 1;
-
-       if (strlcpy(addr.sun_path, path,
-           sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
-               fatal("ControlPath too long");
-
-       if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
-               fatal("%s socket(): %s", __func__, strerror(errno));
-
-       if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
-               if (mux_command != SSHMUX_COMMAND_OPEN) {
-                       fatal("Control socket connect(%.100s): %s", path,
-                           strerror(errno));
-               }
-               if (errno == ENOENT)
-                       debug("Control socket \"%.100s\" does not exist", path);
-               else {
-                       error("Control socket connect(%.100s): %s", path,
-                           strerror(errno));
-               }
-               close(sock);
-               return;
-       }
-
-       if (stdin_null_flag) {
-               if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
-                       fatal("open(/dev/null): %s", strerror(errno));
-               if (dup2(fd, STDIN_FILENO) == -1)
-                       fatal("dup2: %s", strerror(errno));
-               if (fd > STDERR_FILENO)
-                       close(fd);
-       }
-
-       term = getenv("TERM");
-
-       flags = 0;
-       if (tty_flag)
-               flags |= SSHMUX_FLAG_TTY;
-       if (subsystem_flag)
-               flags |= SSHMUX_FLAG_SUBSYS;
-       if (options.forward_x11)
-               flags |= SSHMUX_FLAG_X11_FWD;
-       if (options.forward_agent)
-               flags |= SSHMUX_FLAG_AGENT_FWD;
-
-       signal(SIGPIPE, SIG_IGN);
-
-       buffer_init(&m);
-
-       /* Send our command to server */
-       buffer_put_int(&m, mux_command);
-       buffer_put_int(&m, flags);
-       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
-               fatal("%s: msg_send", __func__);
-       buffer_clear(&m);
-
-       /* Get authorisation status and PID of controlee */
-       if (ssh_msg_recv(sock, &m) == -1)
-               fatal("%s: msg_recv", __func__);
-       if (buffer_get_char(&m) != SSHMUX_VER)
-               fatal("%s: wrong version", __func__);
-       if (buffer_get_int(&m) != 1)
-               fatal("Connection to master denied");
-       control_server_pid = buffer_get_int(&m);
-
-       buffer_clear(&m);
-
-       switch (mux_command) {
-       case SSHMUX_COMMAND_ALIVE_CHECK:
-               fprintf(stderr, "Master running (pid=%d)\r\n",
-                   control_server_pid);
-               exit(0);
-       case SSHMUX_COMMAND_TERMINATE:
-               fprintf(stderr, "Exit request sent.\r\n");
-               exit(0);
-       case SSHMUX_COMMAND_OPEN:
-               /* continue below */
-               break;
-       default:
-               fatal("silly mux_command %d", mux_command);
-       }
-
-       /* SSHMUX_COMMAND_OPEN */
-       buffer_put_cstring(&m, term ? term : "");
-       buffer_append(&command, "\0", 1);
-       buffer_put_cstring(&m, buffer_ptr(&command));
-
-       if (options.num_send_env == 0 || environ == NULL) {
-               buffer_put_int(&m, 0);
-       } else {
-               /* Pass environment */
-               num_env = 0;
-               for (i = 0; environ[i] != NULL; i++)
-                       if (env_permitted(environ[i]))
-                               num_env++; /* Count */
-
-               buffer_put_int(&m, num_env);
-
-               for (i = 0; environ[i] != NULL && num_env >= 0; i++)
-                       if (env_permitted(environ[i])) {
-                               num_env--;
-                               buffer_put_cstring(&m, environ[i]);
-                       }
-       }
-
-       if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
-               fatal("%s: msg_send", __func__);
-
-       if (mm_send_fd(sock, STDIN_FILENO) == -1 ||
-           mm_send_fd(sock, STDOUT_FILENO) == -1 ||
-           mm_send_fd(sock, STDERR_FILENO) == -1)
-               fatal("%s: send fds failed", __func__);
-
-       /* Wait for reply, so master has a chance to gather ttymodes */
-       buffer_clear(&m);
-       if (ssh_msg_recv(sock, &m) == -1)
-               fatal("%s: msg_recv", __func__);
-       if (buffer_get_char(&m) != SSHMUX_VER)
-               fatal("%s: wrong version", __func__);
-       buffer_free(&m);
-
-       signal(SIGHUP, control_client_sighandler);
-       signal(SIGINT, control_client_sighandler);
-       signal(SIGTERM, control_client_sighandler);
-       signal(SIGWINCH, control_client_sigrelay);
-
-       if (tty_flag)
-               enter_raw_mode();
-
-       /*
-        * Stick around until the controlee closes the client_fd.
-        * Before it does, it is expected to write this process' exit
-        * value (one int). This process must read the value and wait for
-        * the closure of the client_fd; if this one closes early, the 
-        * multiplex master will terminate early too (possibly losing data).
-        */
-       exitval[0] = 0;
-       for (i = 0; !control_client_terminate && i < (int)sizeof(exitval);) {
-               r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
-               if (r == 0) {
-                       debug2("Received EOF from master");
-                       break;
-               }
-               if (r == -1) {
-                       if (errno == EINTR)
-                               continue;
-                       fatal("%s: read %s", __func__, strerror(errno));
-               }
-               i += r;
-       }
-
-       close(sock);
-       leave_raw_mode();
-       if (i > (int)sizeof(int))
-               fatal("%s: master returned too much data (%d > %lu)",
-                   __func__, i, sizeof(int));
-       if (control_client_terminate) {
-               debug2("Exiting on signal %d", control_client_terminate);
-               exitval[0] = 255;
-       } else if (i < (int)sizeof(int)) {
-               debug2("Control master terminated unexpectedly");
-               exitval[0] = 255;
-       } else
-               debug2("Received exit status from master %d", exitval[0]);
-
-       if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
-               fprintf(stderr, "Shared connection to %s closed.\r\n", host);
-
-       exit(exitval[0]);
-}
index 17fc0ec668c938ed4e2063d68c128853cb203c33..85e7ba06d7d8dd57267e2d96fe3446e3fc3cf693 100644 (file)
@@ -34,8 +34,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: ssh_config.5,v 1.105 2007/10/29 07:48:19 jmc Exp $
-.Dd $Mdocdate: December 2 2007 $
+.\" $OpenBSD: ssh_config.5,v 1.111 2008/06/26 11:46:31 grunk Exp $
+.Dd $Mdocdate: June 26 2008 $
 .Dt SSH_CONFIG 5
 .Os
 .Sh NAME
@@ -103,6 +103,7 @@ Restricts the following declarations (up to the next
 .Cm Host
 keyword) to be only for those hosts that match one of the patterns
 given after the keyword.
+If more than one pattern is provided, they should be separated by whitepsace.
 A single
 .Ql *
 as a pattern can be used to provide global
@@ -600,6 +601,21 @@ Specifies a command to execute on the local machine after successfully
 connecting to the server.
 The command string extends to the end of the line, and is executed with
 the user's shell.
+The following escape character substitutions will be performed:
+.Ql %d
+(local user's home directory),
+.Ql %h
+(remote host name),
+.Ql %l
+(local host name),
+.Ql %n
+(host name as provided on the command line),
+.Ql %p
+(remote port),
+.Ql %r
+(remote user name) or
+.Ql %u
+(local user name).
 This directive is ignored unless
 .Cm PermitLocalCommand
 has been enabled.
@@ -1044,6 +1060,16 @@ See also
 .Sx VERIFYING HOST KEYS
 in
 .Xr ssh 1 .
+.It Cm VisualHostKey
+If this flag is set to
+.Dq yes ,
+an ASCII art representation of the remote host key fingerprint is
+printed additionally to the hex fingerprint string.
+If this flag is set to
+.Dq no ,
+only the hex fingerprint string will be printed.
+The default is
+.Dq no .
 .It Cm XAuthLocation
 Specifies the full pathname of the
 .Xr xauth 1
index a604c9724aa0512f2b7732ab509c1142364fd6dc..ec8ba33e01674ea93d7b1cc14a9beb0e81621f78 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.203 2007/12/27 14:22:08 dtucker Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.211 2008/07/01 07:24:22 dtucker Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -77,23 +77,6 @@ extern pid_t proxy_command_pid;
 static int show_other_keys(const char *, Key *);
 static void warn_changed_key(Key *);
 
-static void
-ms_subtract_diff(struct timeval *start, int *ms)
-{
-       struct timeval diff, finish;
-
-       gettimeofday(&finish, NULL);
-       timersub(&finish, start, &diff);        
-       *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
-}
-
-static void
-ms_to_timeval(struct timeval *tv, int ms)
-{
-       tv->tv_sec = ms / 1000;
-       tv->tv_usec = (ms % 1000) * 1000;
-}
-
 /*
  * Connect to the given ssh server using a proxy command.
  */
@@ -178,6 +161,8 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
 
        /* Set the connection file descriptors. */
        packet_set_connection(pout[0], pin[1]);
+       packet_set_timeout(options.server_alive_interval,
+           options.server_alive_count_max);
 
        /* Indicate OK return */
        return 0;
@@ -221,7 +206,7 @@ ssh_create_socket(int privileged, struct addrinfo *ai)
        hints.ai_socktype = ai->ai_socktype;
        hints.ai_protocol = ai->ai_protocol;
        hints.ai_flags = AI_PASSIVE;
-       gaierr = getaddrinfo(options.bind_address, "0", &hints, &res);
+       gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
        if (gaierr) {
                error("getaddrinfo: %s: %s", options.bind_address,
                    ssh_gai_strerror(gaierr));
@@ -422,6 +407,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
 
        /* Set the connection. */
        packet_set_connection(sock, sock);
+       packet_set_timeout(options.server_alive_interval,
+           options.server_alive_count_max);
 
        return 0;
 }
@@ -550,10 +537,10 @@ ssh_exchange_identification(int timeout_ms)
                    (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
                    remote_major);
        /* Send our own protocol version identification. */
-       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n",
+       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s",
            compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
            compat20 ? PROTOCOL_MINOR_2 : minor1,
-           SSH_VERSION);
+           SSH_VERSION, compat20 ? "\r\n" : "\n");
        if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf))
                fatal("write: %.100s", strerror(errno));
        client_version_string = xstrdup(buf);
@@ -602,14 +589,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
        Key *file_key;
        const char *type = key_type(host_key);
        char *ip = NULL, *host = NULL;
-       char hostline[1000], *hostp, *fp;
+       char hostline[1000], *hostp, *fp, *ra;
        HostStatus host_status;
        HostStatus ip_status;
        int r, local = 0, host_ip_differ = 0;
        int salen;
        char ntop[NI_MAXHOST];
        char msg[1024];
-       int len, host_line, ip_line;
+       int len, host_line, ip_line, cancelled_forwarding = 0;
        const char *host_file = NULL, *ip_file = NULL;
 
        /*
@@ -656,6 +643,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
        } else {
                ip = xstrdup("<no hostip for proxy command>");
        }
+
        /*
         * Turn off check_host_ip if the connection is to localhost, via proxy
         * command or if we don't have a hostname to compare with
@@ -740,6 +728,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                                logit("Warning: Permanently added the %s host "
                                    "key for IP address '%.128s' to the list "
                                    "of known hosts.", type, ip);
+               } else if (options.visual_host_key) {
+                       fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+                       ra = key_fingerprint(host_key, SSH_FP_MD5,
+                           SSH_FP_RANDOMART);
+                       logit("Host key fingerprint is %s\n%s\n", fp, ra);
+                       xfree(ra);
+                       xfree(fp);
                }
                break;
        case HOST_NEW:
@@ -775,6 +770,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                                snprintf(msg1, sizeof(msg1), ".");
                        /* The default */
                        fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+                       ra = key_fingerprint(host_key, SSH_FP_MD5,
+                           SSH_FP_RANDOMART);
                        msg2[0] = '\0';
                        if (options.verify_host_key_dns) {
                                if (matching_host_key_dns)
@@ -789,10 +786,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                        snprintf(msg, sizeof(msg),
                            "The authenticity of host '%.200s (%s)' can't be "
                            "established%s\n"
-                           "%s key fingerprint is %s.\n%s"
+                           "%s key fingerprint is %s.%s%s\n%s"
                            "Are you sure you want to continue connecting "
                            "(yes/no)? ",
-                           host, ip, msg1, type, fp, msg2);
+                           host, ip, msg1, type, fp,
+                           options.visual_host_key ? "\n" : "",
+                           options.visual_host_key ? ra : "",
+                           msg2);
+                       xfree(ra);
                        xfree(fp);
                        if (!confirm(msg))
                                goto fail;
@@ -845,7 +846,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                        error("@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @");
                        error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
                        error("The %s host key for %s has changed,", type, host);
-                       error("and the key for the according IP address %s", ip);
+                       error("and the key for the corresponding IP address %s", ip);
                        error("%s. This could either mean that", key_msg);
                        error("DNS SPOOFING is happening or the IP address for the host");
                        error("and its host key have changed at the same time.");
@@ -877,27 +878,32 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                        error("Password authentication is disabled to avoid "
                            "man-in-the-middle attacks.");
                        options.password_authentication = 0;
+                       cancelled_forwarding = 1;
                }
                if (options.kbd_interactive_authentication) {
                        error("Keyboard-interactive authentication is disabled"
                            " to avoid man-in-the-middle attacks.");
                        options.kbd_interactive_authentication = 0;
                        options.challenge_response_authentication = 0;
+                       cancelled_forwarding = 1;
                }
                if (options.challenge_response_authentication) {
                        error("Challenge/response authentication is disabled"
                            " to avoid man-in-the-middle attacks.");
                        options.challenge_response_authentication = 0;
+                       cancelled_forwarding = 1;
                }
                if (options.forward_agent) {
                        error("Agent forwarding is disabled to avoid "
                            "man-in-the-middle attacks.");
                        options.forward_agent = 0;
+                       cancelled_forwarding = 1;
                }
                if (options.forward_x11) {
                        error("X11 forwarding is disabled to avoid "
                            "man-in-the-middle attacks.");
                        options.forward_x11 = 0;
+                       cancelled_forwarding = 1;
                }
                if (options.num_local_forwards > 0 ||
                    options.num_remote_forwards > 0) {
@@ -905,12 +911,18 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                            "man-in-the-middle attacks.");
                        options.num_local_forwards =
                            options.num_remote_forwards = 0;
+                       cancelled_forwarding = 1;
                }
                if (options.tun_open != SSH_TUNMODE_NO) {
                        error("Tunnel forwarding is disabled to avoid "
                            "man-in-the-middle attacks.");
                        options.tun_open = SSH_TUNMODE_NO;
+                       cancelled_forwarding = 1;
                }
+               if (options.exit_on_forward_failure && cancelled_forwarding)
+                       fatal("Error: forwarding disabled due to host key "
+                           "check failure");
+               
                /*
                 * XXX Should permit the user to change to use the new id.
                 * This could be done by converting the host key to an
@@ -1063,18 +1075,20 @@ static int
 show_key_from_file(const char *file, const char *host, int keytype)
 {
        Key *found;
-       char *fp;
+       char *fp, *ra;
        int line, ret;
 
        found = key_new(keytype);
        if ((ret = lookup_key_in_hostfile_by_type(file, host,
            keytype, found, &line))) {
                fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+               ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART);
                logit("WARNING: %s key found for host %s\n"
                    "in %s:%d\n"
-                   "%s key fingerprint %s.",
+                   "%s key fingerprint %s.\n%s\n",
                    key_type(found), host, file, line,
-                   key_type(found), fp);
+                   key_type(found), fp, ra);
+               xfree(ra);
                xfree(fp);
        }
        key_free(found);
index 5bb7723682496638db03c4e27ad4ecc7a86c9c07..389bec9e43b47dcf9eb9e12f4ff3a692e3941fe1 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.165 2008/01/19 23:09:49 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.166 2008/07/17 08:48:00 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -38,6 +38,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
+#include <vis.h>
+#endif
 
 #include "openbsd-compat/sys-queue.h"
 
@@ -374,14 +377,21 @@ input_userauth_error(int type, u_int32_t seq, void *ctxt)
 void
 input_userauth_banner(int type, u_int32_t seq, void *ctxt)
 {
-       char *msg, *lang;
+       char *msg, *raw, *lang;
+       u_int len;
 
        debug3("input_userauth_banner");
-       msg = packet_get_string(NULL);
+       raw = packet_get_string(&len);
        lang = packet_get_string(NULL);
-       if (options.log_level >= SYSLOG_LEVEL_INFO)
+       if (options.log_level >= SYSLOG_LEVEL_INFO) {
+               if (len > 65536)
+                       len = 65536;
+               msg = xmalloc(len * 4); /* max expansion from strnvis() */
+               strnvis(msg, raw, len * 4, VIS_SAFE|VIS_OCTAL);
                fprintf(stderr, "%s", msg);
-       xfree(msg);
+               xfree(msg);
+       }
+       xfree(raw);
        xfree(lang);
 }
 
index c9476ade37d950a07baa95ce4ccfa01825ba0d31..c4c4181fcda38af0cfccafcb6fa57eba6a5657d9 100644 (file)
@@ -34,8 +34,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd.8,v 1.241 2008/03/27 22:37:57 jmc Exp $
-.Dd $Mdocdate: April 3 2008 $
+.\" $OpenBSD: sshd.8,v 1.246 2008/07/02 02:24:18 djm Exp $
+.Dd $Mdocdate: July 2 2008 $
 .Dt SSHD 8
 .Os
 .Sh NAME
@@ -44,8 +44,9 @@
 .Sh SYNOPSIS
 .Nm sshd
 .Bk -words
-.Op Fl 46Ddeiqt
+.Op Fl 46DdeiqTt
 .Op Fl b Ar bits
+.Op Fl C Ar connection_spec
 .Op Fl f Ar config_file
 .Op Fl g Ar login_grace_time
 .Op Fl h Ar host_key_file
@@ -99,7 +100,25 @@ Forces
 to use IPv6 addresses only.
 .It Fl b Ar bits
 Specifies the number of bits in the ephemeral protocol version 1
-server key (default 768).
+server key (default 1024).
+.It Fl C Ar connection_spec
+Specify the connection parameters to use for the
+.Fl T
+extended test mode.
+If provided, any
+.Cm Match
+directives in the configuration file
+that would apply to the specified user, host, and address will be set before
+the configuration is written to standard output.
+The connection parameters are supplied as keyword=value pairs.
+The keywords are
+.Dq user ,
+.Dq host ,
+and
+.Dq addr .
+All are required and may be supplied in any order, either with multiple
+.Fl C
+options or as a comma-separated list.
 .It Fl D
 When this option is specified,
 .Nm
@@ -191,6 +210,15 @@ Quiet mode.
 Nothing is sent to the system log.
 Normally the beginning,
 authentication, and termination of each connection is logged.
+.It Fl T
+Extended test mode.
+Check the validity of the configuration file, output the effective configuration
+to stdout and then exit.
+Optionally,
+.Cm Match
+rules may be applied by specifying the connection parameters using one or more
+.Fl C
+options.
 .It Fl t
 Test mode.
 Only check the validity of the configuration file and sanity of the keys.
@@ -503,23 +531,27 @@ This option is automatically disabled if
 .Cm UseLogin
 is enabled.
 .It Cm from="pattern-list"
-Specifies that in addition to public key authentication, the canonical name
-of the remote host must be present in the comma-separated list of
-patterns.
-The purpose
-of this option is to optionally increase security: public key authentication
-by itself does not trust the network or name servers or anything (but
-the key); however, if somebody somehow steals the key, the key
-permits an intruder to log in from anywhere in the world.
-This additional option makes using a stolen key more difficult (name
-servers and/or routers would have to be compromised in addition to
-just the key).
-.Pp
+Specifies that in addition to public key authentication, either the canonical
+name of the remote host or its IP address must be present in the
+comma-separated list of patterns.
 See
 .Sx PATTERNS
 in
 .Xr ssh_config 5
 for more information on patterns.
+.Pp
+In addition to the wildcard matching that may be applied to hostnames or
+addresses, a
+.Cm from
+stanza may match IP addressess using CIDR address/masklen notation.
+.Pp
+The purpose of this option is to optionally increase security: public key
+authentication by itself does not trust the network or name servers or
+anything (but the key); however, if somebody somehow steals the key, the key
+permits an intruder to log in from anywhere in the world.
+This additional option makes using a stolen key more difficult (name
+servers and/or routers would have to be compromised in addition to
+just the key).
 .It Cm no-agent-forwarding
 Forbids authentication agent forwarding when this key is used for
 authentication.
index 5dfc2b185bf815ce09ac19e27319f21d9ed6845d..6e5bb5476a571cf318aeef0a5020ba1888a7253c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.355 2008/02/14 13:10:31 mbalmer Exp $ */
+/* $OpenBSD: sshd.c,v 1.364 2008/07/10 18:08:11 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -54,6 +54,7 @@
 # include <sys/time.h>
 #endif
 #include "openbsd-compat/sys-tree.h"
+#include "openbsd-compat/sys-queue.h"
 #include <sys/wait.h>
 
 #include <errno.h>
@@ -368,9 +369,6 @@ grace_alarm_handler(int sig)
 static void
 generate_ephemeral_server_key(void)
 {
-       u_int32_t rnd = 0;
-       int i;
-
        verbose("Generating %s%d bit RSA key.",
            sensitive_data.server_key ? "new " : "", options.server_key_bits);
        if (sensitive_data.server_key != NULL)
@@ -379,12 +377,7 @@ generate_ephemeral_server_key(void)
            options.server_key_bits);
        verbose("RSA key generation complete.");
 
-       for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
-               if (i % 4 == 0)
-                       rnd = arc4random();
-               sensitive_data.ssh1_cookie[i] = rnd & 0xff;
-               rnd >>= 8;
-       }
+       arc4random_buf(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
        arc4random_stir();
 }
 
@@ -406,7 +399,7 @@ sshd_exchange_identification(int sock_in, int sock_out)
        int mismatch;
        int remote_major, remote_minor;
        int major, minor;
-       char *s;
+       char *s, *newline = "\n";
        char buf[256];                  /* Must not be larger than remote_version. */
        char remote_version[256];       /* Must be at least as big as buf. */
 
@@ -417,11 +410,13 @@ sshd_exchange_identification(int sock_in, int sock_out)
        } else if (options.protocol & SSH_PROTO_2) {
                major = PROTOCOL_MAJOR_2;
                minor = PROTOCOL_MINOR_2;
+               newline = "\r\n";
        } else {
                major = PROTOCOL_MAJOR_1;
                minor = PROTOCOL_MINOR_1;
        }
-       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION);
+       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", major, minor,
+           SSH_VERSION, newline);
        server_version_string = xstrdup(buf);
 
        /* Send our protocol version identification. */
@@ -583,16 +578,14 @@ demote_sensitive_data(void)
 static void
 privsep_preauth_child(void)
 {
-       u_int32_t rnd[256];
+       u_int32_t rnd[256];
        gid_t gidset[1];
-       u_int i;
 
        /* Enable challenge-response authentication for privilege separation */
        privsep_challenge_enable();
 
        arc4random_stir();
-       for (i = 0; i < 256; i++)
-               rnd[i] = arc4random();
+       arc4random_buf(rnd, sizeof(rnd));
        RAND_seed(rnd, sizeof(rnd));
 
        /* Demote the private keys to public keys. */
@@ -666,7 +659,6 @@ static void
 privsep_postauth(Authctxt *authctxt)
 {
        u_int32_t rnd[256];
-       u_int i;
 
 #ifdef DISABLE_FD_PASSING
        if (1) {
@@ -685,7 +677,7 @@ privsep_postauth(Authctxt *authctxt)
        if (pmonitor->m_pid == -1)
                fatal("fork of unprivileged child failed");
        else if (pmonitor->m_pid != 0) {
-               debug2("User child is on pid %ld", (long)pmonitor->m_pid);
+               verbose("User child is on pid %ld", (long)pmonitor->m_pid);
                close(pmonitor->m_recvfd);
                buffer_clear(&loginmsg);
                monitor_child_postauth(pmonitor);
@@ -700,8 +692,7 @@ privsep_postauth(Authctxt *authctxt)
        demote_sensitive_data();
 
        arc4random_stir();
-       for (i = 0; i < 256; i++)
-               rnd[i] = arc4random();
+       arc4random_buf(rnd, sizeof(rnd));
        RAND_seed(rnd, sizeof(rnd));
 
        /* Drop privileges */
@@ -803,7 +794,7 @@ drop_connection(int startups)
        p *= startups - options.max_startups_begin;
        p /= options.max_startups - options.max_startups_begin;
        p += options.max_startups_rate;
-       r = arc4random() % 100;
+       r = arc4random_uniform(100);
 
        debug("drop_connection: p %d, r %d", p, r);
        return (r < p) ? 1 : 0;
@@ -815,8 +806,9 @@ usage(void)
        fprintf(stderr, "%s, %s\n",
            SSH_RELEASE, SSLeay_version(SSLEAY_VERSION));
        fprintf(stderr,
-"usage: sshd [-46Ddeiqt] [-b bits] [-f config_file] [-g login_grace_time]\n"
-"            [-h host_key_file] [-k key_gen_time] [-o option] [-p port] [-u len]\n"
+"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file]\n"
+"            [-g login_grace_time] [-h host_key_file] [-k key_gen_time]\n"
+"            [-o option] [-p port] [-u len]\n"
        );
        exit(1);
 }
@@ -1104,7 +1096,8 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
                        *newsock = accept(listen_socks[i],
                            (struct sockaddr *)&from, &fromlen);
                        if (*newsock < 0) {
-                               if (errno != EINTR && errno != EWOULDBLOCK)
+                               if (errno != EINTR && errno != EAGAIN &&
+                                   errno != EWOULDBLOCK)
                                        error("accept: %.100s", strerror(errno));
                                continue;
                        }
@@ -1251,9 +1244,12 @@ main(int ac, char **av)
        int opt, i, on = 1;
        int sock_in = -1, sock_out = -1, newsock = -1;
        const char *remote_ip;
+       char *test_user = NULL, *test_host = NULL, *test_addr = NULL;
        int remote_port;
-       char *line;
+       char *line, *p, *cp;
        int config_s[2] = { -1 , -1 };
+       u_int64_t ibytes, obytes;
+       mode_t new_umask;
        Key *key;
        Authctxt *authctxt;
 
@@ -1287,7 +1283,7 @@ main(int ac, char **av)
        initialize_server_options(&options);
 
        /* Parse command-line arguments. */
-       while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqrtQR46")) != -1) {
+       while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:C:dDeiqrtQRT46")) != -1) {
                switch (opt) {
                case '4':
                        options.address_family = AF_INET;
@@ -1365,6 +1361,25 @@ main(int ac, char **av)
                case 't':
                        test_flag = 1;
                        break;
+               case 'T':
+                       test_flag = 2;
+                       break;
+               case 'C':
+                       cp = optarg;
+                       while ((p = strsep(&cp, ",")) && *p != '\0') {
+                               if (strncmp(p, "addr=", 5) == 0)
+                                       test_addr = xstrdup(p + 5);
+                               else if (strncmp(p, "host=", 5) == 0)
+                                       test_host = xstrdup(p + 5);
+                               else if (strncmp(p, "user=", 5) == 0)
+                                       test_user = xstrdup(p + 5);
+                               else {
+                                       fprintf(stderr, "Invalid test "
+                                           "mode specification %s\n", p);
+                                       exit(1);
+                               }
+                       }
+                       break;
                case 'u':
                        utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL);
                        if (utmp_len > MAXHOSTNAMELEN) {
@@ -1426,6 +1441,21 @@ main(int ac, char **av)
        sensitive_data.have_ssh1_key = 0;
        sensitive_data.have_ssh2_key = 0;
 
+       /*
+        * If we're doing an extended config test, make sure we have all of
+        * the parameters we need.  If we're not doing an extended test,
+        * do not silently ignore connection test params.
+        */
+       if (test_flag >= 2 &&
+          (test_user != NULL || test_host != NULL || test_addr != NULL)
+           && (test_user == NULL || test_host == NULL || test_addr == NULL))
+               fatal("user, host and addr are all required when testing "
+                  "Match configs");
+       if (test_flag < 2 && (test_user != NULL || test_host != NULL ||
+           test_addr != NULL))
+               fatal("Config test connection parameter (-C) provided without "
+                  "test mode (-T)");
+
        /* Fetch our configuration */
        buffer_init(&cfg);
        if (rexeced_flag)
@@ -1554,6 +1584,13 @@ main(int ac, char **av)
                            "world-writable.", _PATH_PRIVSEP_CHROOT_DIR);
        }
 
+       if (test_flag > 1) {
+               if (test_user != NULL && test_addr != NULL && test_host != NULL)
+                       parse_server_match_config(&options, test_user,
+                           test_host, test_addr);
+               dump_config(&options);
+       }
+
        /* Configuration looks good, so exit if in test mode. */
        if (test_flag)
                exit(0);
@@ -1578,6 +1615,10 @@ main(int ac, char **av)
                rexec_argv[rexec_argc + 1] = NULL;
        }
 
+       /* Ensure that umask disallows at least group and world write */
+       new_umask = umask(0077) | 0022;
+       (void) umask(new_umask);
+
        /* Initialize the log (it is reinitialized below in case we forked). */
        if (debug_flag && (!inetd_flag || rexeced_flag))
                log_stderr = 1;
@@ -1872,11 +1913,18 @@ main(int ac, char **av)
                        destroy_sensitive_data();
        }
 
+       packet_set_timeout(options.client_alive_interval,
+           options.client_alive_count_max);
+
        /* Start session. */
        do_authenticated(authctxt);
 
        /* The connection has been terminated. */
-       verbose("Closing connection to %.100s", remote_ip);
+       packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
+       packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
+       verbose("Transferred: sent %llu, received %llu bytes", obytes, ibytes);
+
+       verbose("Closing connection to %.500s port %d", remote_ip, remote_port);
 
 #ifdef USE_PAM
        if (options.use_pam)
@@ -1956,7 +2004,6 @@ do_ssh1_kex(void)
        u_char session_key[SSH_SESSION_KEY_LENGTH];
        u_char cookie[8];
        u_int cipher_type, auth_mask, protocol_flags;
-       u_int32_t rnd = 0;
 
        /*
         * Generate check bytes that the client must send back in the user
@@ -1967,12 +2014,7 @@ do_ssh1_kex(void)
         * cookie.  This only affects rhosts authentication, and this is one
         * of the reasons why it is inherently insecure.
         */
-       for (i = 0; i < 8; i++) {
-               if (i % 4 == 0)
-                       rnd = arc4random();
-               cookie[i] = rnd & 0xff;
-               rnd >>= 8;
-       }
+       arc4random_buf(cookie, sizeof(cookie));
 
        /*
         * Send our public key.  We include in the packet 64 bits of random
index ddfbbe91eb1f4318633129301aca264c14e40597..1b53a0efb91fcd232f2be78c8cd95823cc5c766d 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: sshd_config,v 1.77 2008/02/08 23:24:07 djm Exp $
+#      $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $
 
 # This is the sshd server system-wide configuration file.  See
 # sshd_config(5) for more information.
@@ -28,7 +28,7 @@ Protocol 2
 
 # Lifetime and size of ephemeral version 1 server key
 #KeyRegenerationInterval 1h
-#ServerKeyBits 768
+#ServerKeyBits 1024
 
 # Logging
 # obsoletes QuietMode and FascistLogging
@@ -41,6 +41,7 @@ Protocol 2
 #PermitRootLogin yes
 #StrictModes yes
 #MaxAuthTries 6
+#MaxSessions 10
 
 #RSAAuthentication yes
 #PubkeyAuthentication yes
@@ -84,6 +85,7 @@ Protocol 2
 # and ChallengeResponseAuthentication to 'no'.
 #UsePAM no
 
+#AllowAgentForwarding yes
 #AllowTcpForwarding yes
 #GatewayPorts no
 #X11Forwarding no
index 510ff9c7930df941880359673bffedb29084e5f5..7255b1c2260029905f60da901b3e91924bc6d941 100644 (file)
@@ -34,8 +34,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.84 2008/03/25 11:58:02 djm Exp $
-.Dd $Mdocdate: March 27 2008 $
+.\" $OpenBSD: sshd_config.5,v 1.96 2008/07/02 02:24:18 djm Exp $
+.Dd $Mdocdate: July 2 2008 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -95,6 +95,15 @@ Valid arguments are
 (use IPv6 only).
 The default is
 .Dq any .
+.It Cm AllowAgentForwarding
+Specifies whether
+.Xr ssh-agent 1
+forwarding is permitted.
+The default is
+.Dq yes .
+Note that disabling agent forwarding does not improve security
+unless users are also denied shell access, as they can always install
+their own forwarders.
 .It Cm AllowGroups
 This keyword can be followed by a list of group name patterns, separated
 by spaces.
@@ -548,6 +557,7 @@ line are satisfied, the keywords on the following lines override those
 set in the global section of the config file, until either another
 .Cm Match
 line or the end of the file.
+.Pp
 The arguments to
 .Cm Match
 are one or more criteria-pattern pairs.
@@ -557,17 +567,43 @@ The available criteria are
 .Cm Host ,
 and
 .Cm Address .
+The match patterns may consist of single entries or comma-separated
+lists and may use the wildcard and negation operators described in the
+.Sx PATTERNS
+section of
+.Xr ssh_config 5 .
+.Pp
+The patterns in an
+.Cm Address
+criteria may additionally contain addresses to match in CIDR
+address/masklen format, e.g.\&
+.Dq 192.0.2.0/24
+or
+.Dq 3ffe:ffff::/32 .
+Note that the mask length provided must be consistent with the address -
+it is an error to specify a mask length that is too long for the address
+or one with bits set in this host portion of the address.
+For example,
+.Dq 192.0.2.0/33
+and
+.Dq 192.0.2.0/8
+respectively.
+.Pp
 Only a subset of keywords may be used on the lines following a
 .Cm Match
 keyword.
 Available keywords are
 .Cm AllowTcpForwarding ,
 .Cm Banner ,
+.Cm ChrootDirectory ,
 .Cm ForceCommand ,
 .Cm GatewayPorts ,
-.Cm GSSApiAuthentication ,
+.Cm GSSAPIAuthentication ,
+.Cm HostbasedAuthentication ,
 .Cm KbdInteractiveAuthentication ,
 .Cm KerberosAuthentication ,
+.Cm MaxAuthTries ,
+.Cm MaxSessions ,
 .Cm PasswordAuthentication ,
 .Cm PermitOpen ,
 .Cm PermitRootLogin ,
@@ -583,6 +619,9 @@ connection.
 Once the number of failures reaches half this value,
 additional failures are logged.
 The default is 6.
+.It Cm MaxSessions
+Specifies the maximum number of open sessions permitted per network connection.
+The default is 10.
 .It Cm MaxStartups
 Specifies the maximum number of concurrent unauthenticated connections to the
 SSH daemon.
@@ -772,7 +811,7 @@ The default is
 This option applies to protocol version 1 only.
 .It Cm ServerKeyBits
 Defines the number of bits in the ephemeral protocol version 1 server key.
-The minimum value is 512, and the default is 768.
+The minimum value is 512, and the default is 1024.
 .It Cm StrictModes
 Specifies whether
 .Xr sshd 8
index 7fac622d9be1f9bd426a921c5ef5ba1913a16c61..ac90035846245685f4ecf482a2f95d29fccdb7ab 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshpty.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: sshpty.h,v 1.11 2008/05/19 15:45:07 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -16,7 +16,7 @@
 
 #include <termios.h>
 
-struct termios get_saved_tio(void);
+struct termios *get_saved_tio(void);
 void    leave_raw_mode(void);
 void    enter_raw_mode(void);
 
index 04567669b13bcb466dc3bbdda1e0cddc3318c4cd..21ade4e5153dc6ec9ab790ab728700f3049ec813 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshtty.c,v 1.12 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: sshtty.c,v 1.13 2008/05/19 15:45:07 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 static struct termios _saved_tio;
 static int _in_raw_mode = 0;
 
-struct termios
+struct termios *
 get_saved_tio(void)
 {
-       return _saved_tio;
+       return _in_raw_mode ? &_saved_tio : NULL;
 }
 
 void
index d8e2c553abd6d079740db22f67efddb71c9ed57d..e116b19990696a6548203a7ee97c1251568c99fa 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ttymodes.c,v 1.26 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: ttymodes.c,v 1.28 2008/07/07 00:31:41 stevesk Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -298,6 +298,10 @@ tty_make_modes(int fd, struct termios *tiop)
        }
 
        if (tiop == NULL) {
+               if (fd == -1) {
+                       debug("tty_make_modes: no fd or tio");
+                       goto end;
+               }
                if (tcgetattr(fd, &tio) == -1) {
                        logit("tcgetattr: %.100s", strerror(errno));
                        goto end;
@@ -317,12 +321,10 @@ tty_make_modes(int fd, struct termios *tiop)
 
        /* Store values of mode flags. */
 #define TTYCHAR(NAME, OP) \
-       debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \
        buffer_put_char(&buf, OP); \
        put_arg(&buf, special_char_encode(tio.c_cc[NAME]));
 
 #define TTYMODE(NAME, FIELD, OP) \
-       debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \
        buffer_put_char(&buf, OP); \
        put_arg(&buf, ((tio.FIELD & NAME) != 0));
 
@@ -353,7 +355,7 @@ tty_parse_modes(int fd, int *n_bytes_ptr)
        int n_bytes = 0;
        int failure = 0;
        u_int (*get_arg)(void);
-       int arg, arg_size;
+       int arg_size;
 
        if (compat20) {
                *n_bytes_ptr = packet_get_int();
@@ -410,16 +412,14 @@ tty_parse_modes(int fd, int *n_bytes_ptr)
        case OP: \
          n_bytes += arg_size; \
          tio.c_cc[NAME] = special_char_decode(get_arg()); \
-         debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \
          break;
 #define TTYMODE(NAME, FIELD, OP) \
        case OP: \
          n_bytes += arg_size; \
-         if ((arg = get_arg())) \
+         if (get_arg()) \
            tio.FIELD |= NAME; \
          else \
            tio.FIELD &= ~NAME; \
-         debug3("tty_parse_modes: %d %d", OP, arg); \
          break;
 
 #include "ttymodes.h"
index ca5e08b3e2671b4edb3770b4d2ff8da199bbd724..92902bc09b2f0250c5bbdcfe068d29b47f99938e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: umac.c,v 1.2 2007/09/12 19:39:19 stevesk Exp $ */
+/* $OpenBSD: umac.c,v 1.3 2008/05/12 20:52:20 pvalchev Exp $ */
 /* -----------------------------------------------------------------------
  * 
  * umac.c -- C Implementation UMAC Message Authentication
@@ -136,12 +136,14 @@ static UINT32 LOAD_UINT32_REVERSED(void *ptr)
     return (UINT32)temp;
 }
 
+# if (__LITTLE_ENDIAN__)
 static void STORE_UINT32_REVERSED(void *ptr, UINT32 x)
 {
     UINT32 i = (UINT32)x;
     *(UINT32 *)ptr = (i >> 24) | ((i & 0x00FF0000) >> 8 )
                    | ((i & 0x0000FF00) << 8 ) | (i << 24);
 }
+# endif /* __LITTLE_ENDIAN */
 #endif /* HAVE_SWAP32 */
 
 /* The following definitions use the above reversal-primitives to do the right
@@ -179,14 +181,14 @@ typedef AES_KEY aes_int_key[1];
 /* The user-supplied UMAC key is stretched using AES in a counter
  * mode to supply all random bits needed by UMAC. The kdf function takes
  * an AES internal key representation 'key' and writes a stream of
- * 'nbytes' bytes to the memory pointed at by 'buffer_ptr'. Each distinct
+ * 'nbytes' bytes to the memory pointed at by 'bufp'. Each distinct
  * 'ndx' causes a distinct byte stream.
  */
-static void kdf(void *buffer_ptr, aes_int_key key, UINT8 ndx, int nbytes)
+static void kdf(void *bufp, aes_int_key key, UINT8 ndx, int nbytes)
 {
     UINT8 in_buf[AES_BLOCK_LEN] = {0};
     UINT8 out_buf[AES_BLOCK_LEN];
-    UINT8 *dst_buf = (UINT8 *)buffer_ptr;
+    UINT8 *dst_buf = (UINT8 *)bufp;
     int i;
     
     /* Setup the initial value */
@@ -544,6 +546,7 @@ static void nh_transform(nh_ctx *hc, UINT8 *buf, UINT32 nbytes)
 
 /* ---------------------------------------------------------------------- */
 
+#if (__LITTLE_ENDIAN__)
 static void endian_convert(void *buf, UWORD bpw, UINT32 num_bytes)
 /* We endian convert the keys on little-endian computers to               */
 /* compensate for the lack of big-endian memory reads during hashing.     */
@@ -566,7 +569,6 @@ static void endian_convert(void *buf, UWORD bpw, UINT32 num_bytes)
         } while (--iters);
     }
 }
-#if (__LITTLE_ENDIAN__)
 #define endian_convert_if_le(x,y,z) endian_convert((x),(y),(z))
 #else
 #define endian_convert_if_le(x,y,z) do{}while(0)  /* Do nothing */
@@ -1043,7 +1045,8 @@ static int uhash_update(uhash_ctx_t ctx, u_char *input, long len)
  */
 {
     UWORD bytes_hashed, bytes_remaining;
-    UINT8 nh_result[STREAMS*sizeof(UINT64)];
+    UINT64 result_buf[STREAMS];
+    UINT8 *nh_result = (UINT8 *)&result_buf;
     
     if (ctx->msg_len + len <= L1_KEY_LEN) {
         nh_update(&ctx->hash, (UINT8 *)input, len);
@@ -1095,7 +1098,8 @@ static int uhash_update(uhash_ctx_t ctx, u_char *input, long len)
 static int uhash_final(uhash_ctx_t ctx, u_char *res)
 /* Incorporate any pending data, pad, and generate tag */
 {
-    UINT8 nh_result[STREAMS*sizeof(UINT64)];
+    UINT64 result_buf[STREAMS];
+    UINT8 *nh_result = (UINT8 *)&result_buf;
 
     if (ctx->msg_len > L1_KEY_LEN) {
         if (ctx->msg_len % L1_KEY_LEN) {
index a310df51c140ec8ff66d12b8083678446fceabd9..41a081f12d61820e2000e3645751aac2540b4557 100644 (file)
@@ -1,6 +1,6 @@
-/* $OpenBSD: version.h,v 1.53 2008/04/03 09:50:14 djm Exp $ */
+/* $OpenBSD: version.h,v 1.54 2008/07/21 08:19:07 djm Exp $ */
 
-#define SSH_VERSION    "OpenSSH_5.0"
+#define SSH_VERSION    "OpenSSH_5.1"
 
 #define SSH_PORTABLE   "p1"
 #define SSH_RELEASE    SSH_VERSION SSH_PORTABLE
This page took 0.88236 seconds and 5 git commands to generate.