OpenSSH
Revision as of 21:34, 24 November 2010 by <bdi>PhilippeTeuwen</bdi> (talk | contribs) (Reverted edits by Etegohy (Talk) to last revision by PhilippeTeuwen)
Patch for login with eID
Inspired from http://simi.be/?page_id=9
Getting the patch from http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=355274 and porting it to v4.7p1
Some rejs easy to solve from v4.2 to v4.7 and one less obvious change in debian/control: fix the debconf dependancies (was ${debconf:Depends} I think):
Package: openssh-client-sc Architecture: any Depends: ${shlibs:Depends}, debconf (>= 1.2.0) | debconf-2.0,...
I recompile ssh with smartcard support.
apt-get source openssh-client cd openssh-4.7p1 patch -p1 < ../mypatch dpkg-buildpackage -uc -us -rfakeroot
Sending my public key to the ssh server:
pkcs15-tool --read-ssh-key 2 |tail -n1|ssh user@host 'cat - >> ~/.ssh/authorized_keys'
Then logging, being prompted for my PIN:
ssh -I 0 user@host.com
Here is the patch:
diff -Naur openssh-4.7p1.orig/debian/control openssh-4.7p1/debian/control --- openssh-4.7p1.orig/debian/control 2008-02-05 01:27:54.000000000 +0100 +++ openssh-4.7p1/debian/control 2008-02-05 01:26:10.000000000 +0100 @@ -2,15 +2,15 @@ Section: net Priority: standard Maintainer: Debian OpenSSH Maintainers <debian-ssh@lists.debian.org> -Build-Depends: libwrap0-dev | libwrap-dev, zlib1g-dev (>= 1:1.2.3-1), libssl-dev (>= 0.9.8-1), libpam0g-dev | libpam-dev, libgtk2.0-dev, libedit-dev, debhelper (>= 5.0.22), sharutils, libselinux1-dev [alpha amd64 arm armeb armel hppa i386 ia64 lpia m68k mips mipsel powerpc ppc64 s390 sparc], libkrb5-dev +Build-Depends: libwrap0-dev | libwrap-dev, zlib1g-dev (>= 1:1.2.3-1), libssl-dev (>= 0.9.8-1), libpam0g-dev | libpam-dev, libgtk2.0-dev, libedit-dev, debhelper (>= 5.0.22), sharutils, libselinux1-dev [alpha amd64 arm armeb armel hppa i386 ia64 lpia m68k mips mipsel powerpc ppc64 s390 sparc], libkrb5-dev, libopensc2-dev Standards-Version: 3.7.3 Uploaders: Colin Watson <cjwatson@debian.org>, Matthew Vernon <matthew@debian.org> Package: openssh-client Architecture: any Depends: ${shlibs:Depends}, debconf (>= 1.2.0) | debconf-2.0, adduser (>= 3.10), dpkg (>= 1.7.0), passwd -Conflicts: ssh (<< 1:3.8.1p1-9), sftp, rsh-client (<<0.16.1-1), ssh-krb5 (<< 1:4.3p2-7) -Replaces: ssh, ssh-krb5 +Conflicts: ssh (<< 1:3.8.1p1-9), sftp, rsh-client (<<0.16.1-1), ssh-krb5 (<< 1:4.3p2-7), openssh-client-sc +Replaces: ssh, ssh-krb5, openssh-client-sc Suggests: ssh-askpass, xbase-clients, libpam-ssh, keychain Provides: rsh-client, ssh-client Description: secure shell client, an rlogin/rsh/rcp replacement @@ -33,10 +33,37 @@ In some countries it may be illegal to use any encryption at all without a special permit. +Package: openssh-client-sc +Architecture: any +Depends: ${shlibs:Depends}, debconf (>= 1.2.0) | debconf-2.0, adduser (>= 3.10), dpkg (>= 1.7.0) +Conflicts: ssh (<< 1:3.8.1p1-9), sftp, rsh-client (<<0.16.1-1), ssh-krb5, openssh-client +Replaces: ssh (<< 1:3.8.1p1-9), ssh-krb5, openssh-client +Suggests: ssh-askpass, xbase-clients +Provides: rsh-client, ssh-client, openssh-client +Description: Secure shell client, an rlogin/rsh/rcp replacement with smartcard support + This is the portable version of OpenSSH, a free implementation of + the Secure Shell protocol as specified by the IETF secsh working + group. + . + Ssh (Secure Shell) is a program for logging into a remote machine + and for executing commands on a remote machine. + It provides secure encrypted communications between two untrusted + hosts over an insecure network. X11 connections and arbitrary TCP/IP + ports can also be forwarded over the secure channel. + It is intended as a replacement for rlogin, rsh and rcp, and can be + used to provide applications with a secure communication channel. + . + This package provides the ssh, scp and sftp clients, the ssh-agent + and ssh-add programs to make public key authentication more convenient, + and the ssh-keygen, ssh-keyscan, ssh-copy-id and ssh-argv0 utilities. + . + In some countries it may be illegal to use any encryption at all + without a special permit. + Package: openssh-server Priority: optional Architecture: any -Depends: ${shlibs:Depends}, debconf (>= 1.2.0) | debconf-2.0, libpam-runtime (>= 0.76-14), libpam-modules (>= 0.72-9), adduser (>= 3.9), dpkg (>= 1.9.0), openssh-client (= ${binary:Version}), lsb-base (>= 3.0-6) +Depends: ${shlibs:Depends}, debconf (>= 1.2.0) | debconf-2.0, libpam-runtime (>= 0.76-14), libpam-modules (>= 0.72-9), adduser (>= 3.9), dpkg (>= 1.9.0), openssh-client (= ${binary:Version}) | openssh-client-sc (= ${Source-Version}), lsb-base (>= 3.0-6) Conflicts: ssh (<< 1:3.8.1p1-9), ssh-nonfree (<<2), ssh-socks, ssh2, sftp, rsh-client (<<0.16.1-1), ssh-krb5 (<< 1:4.3p2-7) Replaces: ssh, openssh-client (<< 1:3.8.1p1-11), ssh-krb5 Suggests: ssh-askpass, xbase-clients, rssh, molly-guard @@ -62,7 +89,7 @@ Package: ssh Priority: extra Architecture: all -Depends: openssh-client, openssh-server +Depends: openssh-client | openssh-client-sc, openssh-server Description: secure shell client and server (metapackage) This metapackage is a convenient way to install both the OpenSSH client and the OpenSSH server. It provides nothing in and of itself, so you diff -Naur openssh-4.7p1.orig/debian/openssh-client-sc.config openssh-4.7p1/debian/openssh-client-sc.config --- openssh-4.7p1.orig/debian/openssh-client-sc.config 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/debian/openssh-client-sc.config 2008-02-05 01:19:52.000000000 +0100 @@ -0,0 +1,26 @@ +#!/bin/sh + +action=$1 +version=$2 + +# Source debconf library. +. /usr/share/debconf/confmodule +db_version 2.0 + +if [ -d /etc/ssh-nonfree ] && [ ! -d /etc/ssh ]; then + version=1.2.27 + cp -a /etc/ssh-nonfree /etc/ssh +fi + +# Was ssh-keysign's setuid bit turned off using the obsolete debconf +# question? If so, turn this into a statoverride. (Ugh.) +if dpkg --compare-versions "$2" lt 1:4.1p1-2 && \ + db_get ssh/SUID_client && [ "$RET" = false ] && + [ -x /usr/sbin/dpkg-statoverride ] && \ + ! dpkg-statoverride --list /usr/lib/ssh-keysign && \ + ! dpkg-statoverride --list /usr/lib/openssh/ssh-keysign; then + dpkg-statoverride --update --add root root 0755 \ + /usr/lib/openssh/ssh-keysign +fi + +exit 0 diff -Naur openssh-4.7p1.orig/debian/openssh-client-sc.dirs openssh-4.7p1/debian/openssh-client-sc.dirs --- openssh-4.7p1.orig/debian/openssh-client-sc.dirs 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/debian/openssh-client-sc.dirs 2008-02-05 01:19:52.000000000 +0100 @@ -0,0 +1 @@ +usr/share/lintian/overrides diff -Naur openssh-4.7p1.orig/debian/openssh-client-sc.lintian openssh-4.7p1/debian/openssh-client-sc.lintian --- openssh-4.7p1.orig/debian/openssh-client-sc.lintian 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/debian/openssh-client-sc.lintian 2008-02-05 01:19:52.000000000 +0100 @@ -0,0 +1,2 @@ +openssh-client-sc: setuid-binary usr/lib/openssh/ssh-keysign 4755 root/root +openssh-client-sc: no-debconf-templates diff -Naur openssh-4.7p1.orig/debian/openssh-client-sc.postinst openssh-4.7p1/debian/openssh-client-sc.postinst --- openssh-4.7p1.orig/debian/openssh-client-sc.postinst 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/debian/openssh-client-sc.postinst 2008-02-05 01:19:52.000000000 +0100 @@ -0,0 +1,106 @@ +#!/bin/sh -e + +action="$1" +oldversion="$2" + +. /usr/share/debconf/confmodule +db_version 2.0 + +umask 022 + +if [ "$action" != configure ] + then + exit 0 +fi + + +fix_rsh_diversion() { +# get rid of mistaken rsh diversion (circa 1.2.27-1) + + if [ -L /usr/bin/rsh ] && + dpkg-divert --list '/usr/bin/rsh.real/rsh' | grep -q ' ssh$' ; then + for cmd in rlogin rsh rcp ; do + [ -L /usr/bin/$cmd ] && rm /usr/bin/$cmd + dpkg-divert --package ssh --remove --rename \ + --divert /usr/bin/rsh.real/$cmd /usr/bin/$cmd + + [ -L /usr/man/man1/$cmd.1.gz ] && rm /usr/man/man1/$$cmd.1.gz + dpkg-divert --package ssh --remove --rename \ + --divert /usr/man/man1/$cmd.real.1.gz /usr/man/man1/$cmd.1.gz + done + + rmdir /usr/bin/rsh.real + fi +} + +create_alternatives() { +# Create alternatives for the various r* tools. +# Make sure we don't change existing alternatives that a user might have +# changed, but clean up after some old alternatives that mistakenly pointed +# rlogin and rcp to ssh. + update-alternatives --quiet --remove rlogin /usr/bin/ssh + update-alternatives --quiet --remove rcp /usr/bin/ssh + for cmd in rsh rlogin rcp; do + scmd="s${cmd#r}" + if ! update-alternatives --display "$cmd" | \ + grep -q "$scmd"; then + update-alternatives --quiet --install "/usr/bin/$cmd" "$cmd" "/usr/bin/$scmd" 20 \ + --slave "/usr/share/man/man1/$cmd.1.gz" "$cmd.1.gz" "/usr/share/man/man1/$scmd.1.gz" + fi + done +} + +set_ssh_permissions() { + if dpkg --compare-versions "$oldversion" lt-nl 1:3.4p1-1 ; then + if [ -x /usr/sbin/dpkg-statoverride ] ; then + if dpkg-statoverride --list /usr/bin/ssh >/dev/null; then + dpkg-statoverride --remove /usr/bin/ssh >/dev/null + fi + fi + fi + + # libexecdir changed, so migrate old statoverrides. + if [ -x /usr/sbin/dpkg-statoverride ] && + override="$(dpkg-statoverride --list /usr/lib/ssh-keysign)"; then + override_user="${override%% *}" + override="${override#* }" + override_group="${override%% *}" + override="${override#* }" + override_mode="${override%% *}" + if dpkg-statoverride --update --add \ + "$override_user" "$override_group" "$override_mode" \ + /usr/lib/openssh/ssh-keysign; then + dpkg-statoverride --remove /usr/lib/ssh-keysign || true + fi + fi +} + +fix_ssh_group() { + # Try to remove non-system group mistakenly created by 1:3.5p1-1. + # set_ssh_agent_permissions() below will re-create it properly. + if getent group ssh >/dev/null; then + delgroup --quiet ssh || true + fi +} + +set_ssh_agent_permissions() { + if ! getent group ssh >/dev/null; then + addgroup --system --quiet ssh + fi + if ! [ -x /usr/sbin/dpkg-statoverride ] || \ + ! dpkg-statoverride --list /usr/bin/ssh-agent >/dev/null ; then + chgrp ssh /usr/bin/ssh-agent + chmod 2755 /usr/bin/ssh-agent + fi +} + + +fix_rsh_diversion +create_alternatives +set_ssh_permissions +if [ "$2" = "1:3.5p1-1" ]; then + fix_ssh_group +fi +set_ssh_agent_permissions + +exit 0 diff -Naur openssh-4.7p1.orig/debian/openssh-client-sc.postrm openssh-4.7p1/debian/openssh-client-sc.postrm --- openssh-4.7p1.orig/debian/openssh-client-sc.postrm 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/debian/openssh-client-sc.postrm 2008-02-05 01:19:52.000000000 +0100 @@ -0,0 +1,20 @@ +#!/bin/sh -e + +#DEBHELPER# + +if [ "$1" = "purge" ] +then + # Remove all non-conffiles that ssh might create, so that we can + # smoothly remove /etc/ssh if and only if the user hasn't dropped some + # other files in there. Conffiles have already been removed at this + # point. + rm -f /etc/ssh/moduli /etc/ssh/primes + rm -f /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2 + rmdir --ignore-fail-on-non-empty /etc/ssh +fi + +if [ "$1" = "purge" ] ; then + delgroup --quiet ssh > /dev/null || true +fi + +exit 0 diff -Naur openssh-4.7p1.orig/debian/openssh-client-sc.prerm openssh-4.7p1/debian/openssh-client-sc.prerm --- openssh-4.7p1.orig/debian/openssh-client-sc.prerm 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/debian/openssh-client-sc.prerm 2008-02-05 01:19:52.000000000 +0100 @@ -0,0 +1,39 @@ +#! /bin/sh +# prerm script for ssh +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * <prerm> `remove' +# * <old-prerm> `upgrade' <new-version> +# * <new-prerm> `failed-upgrade' <old-version> +# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version> +# * <deconfigured's-prerm> `deconfigure' `in-favour' +# <package-being-installed> <version> `removing' +# <conflicting-package> <version> +# for details, see /usr/share/doc/packaging-manual/ + +case "$1" in + remove|deconfigure) + update-alternatives --quiet --remove rsh /usr/bin/ssh + update-alternatives --quiet --remove rlogin /usr/bin/slogin + update-alternatives --quiet --remove rcp /usr/bin/scp + ;; + upgrade) + ;; + failed-upgrade) + ;; + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff -Naur openssh-4.7p1.orig/debian/rules openssh-4.7p1/debian/rules --- openssh-4.7p1.orig/debian/rules 2008-02-05 01:27:54.000000000 +0100 +++ openssh-4.7p1/debian/rules 2008-02-05 01:27:03.000000000 +0100 @@ -108,7 +108,7 @@ confflags += --with-ldflags='$(PIE_LDFLAGS)' endif -build: build-deb build-udeb +build: build-deb build-sc-deb build-udeb build-deb: build-deb-stamp build-deb-stamp: @@ -128,6 +128,23 @@ touch build-deb-stamp +build-sc-deb: build-sc-deb-stamp +build-sc-deb-stamp: + dh_testdir + mkdir -p build-sc-deb + cd build-sc-deb && $(FORCE_LIBS) ../configure --prefix=/usr --sysconfdir=/etc/ssh --libexecdir=/usr/lib/openssh --mandir=/usr/share/man --with-tcp-wrappers --with-xauth=/usr/bin/X11/xauth --with-default-path=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games --with-superuser-path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11 --with-pam --with-4in6 --with-privsep-path=/var/run/sshd --without-rand-helper --with-libedit --with-kerberos5=/usr $(SELINUX) --with-opensc=/usr + +ifeq ($(DEB_HOST_ARCH_OS),linux) + # Some 2.2 kernels have trouble with setres[ug]id() (bug #239999). + perl -pi -e 's/.*#undef (BROKEN_SETRES[UG]ID).*/#define $$1 1/' build-sc-deb/config.h +endif + # Debian's /var/log/btmp has inappropriate permissions. + perl -pi -e 's,.*#define USE_BTMP .*,/* #undef USE_BTMP */,' build-sc-deb/config.h + + $(MAKE) -C build-sc-deb -j 2 ASKPASS_PROGRAM='/usr/bin/ssh-askpass' CFLAGS='$(OPTFLAGS) -g -Wall -Wpointer-arith -Wuninitialized -Wsign-compare -std=gnu99 -DLOGIN_PROGRAM=\"/bin/login\" -DLOGIN_NO_ENDOPT -DSSHD_PAM_SERVICE=\"ssh\" -DSSH_EXTRAVERSION="\" $(SSH_EXTRAVERSION)\""' + + touch build-sc-deb-stamp + build-udeb: build-udeb-stamp build-udeb-stamp: dh_testdir @@ -143,8 +160,8 @@ clean: dh_testdir - rm -f build-deb-stamp build-udeb-stamp - rm -rf build-deb build-udeb + rm -f build-deb-stamp build-sc-deb-stamp build-udeb-stamp + rm -rf build-deb build-sc-deb build-udeb $(MAKE) -C contrib clean rm -f config.log rm -f debian/ssh-askpass-gnome.png @@ -158,10 +175,13 @@ dh_installdirs $(MAKE) -C build-deb DESTDIR=`pwd`/debian/openssh-client install-nokeys + $(MAKE) -C build-sc-deb DESTDIR=`pwd`/debian/openssh-client-sc install-nokeys rm -f debian/openssh-client/etc/ssh/sshd_config + rm -f debian/openssh-client-sc/etc/ssh/sshd_config #Temporary hack: remove /usr/share/Ssh.bin, since we have no smartcard support anyway. rm -f debian/openssh-client/usr/share/Ssh.bin + rm -f debian/openssh-client-sc/usr/share/Ssh.bin # Split off the server. mv debian/openssh-client/usr/sbin/sshd debian/openssh-server/usr/sbin/ @@ -171,10 +191,19 @@ mv debian/openssh-client/usr/share/man/man8/sshd.8 debian/openssh-server/usr/share/man/man8/ mv debian/openssh-client/usr/share/man/man8/sftp-server.8 debian/openssh-server/usr/share/man/man8/ rmdir debian/openssh-client/usr/sbin debian/openssh-client/var/run/sshd + rm -f debian/openssh-client-sc/usr/sbin/sshd + rm -f debian/openssh-client-sc/usr/lib/openssh/sftp-server + rm -f debian/openssh-client-sc/usr/share/man/man5/sshd_config.5 + rm -f debian/openssh-client-sc/usr/share/man/man8/sshd.8 + rm -f debian/openssh-client-sc/usr/share/man/man8/sftp-server.8 + rmdir debian/openssh-client-sc/usr/sbin debian/openssh-client-sc/var/run/sshd install -m 755 contrib/ssh-copy-id debian/openssh-client/usr/bin/ssh-copy-id install -m 644 -c contrib/ssh-copy-id.1 debian/openssh-client/usr/share/man/man1/ssh-copy-id.1 install -m 644 debian/moduli.5 debian/openssh-client/usr/share/man/man5/moduli.5 + install -m 755 contrib/ssh-copy-id debian/openssh-client-sc/usr/bin/ssh-copy-id + install -m 644 -c contrib/ssh-copy-id.1 debian/openssh-client-sc/usr/share/man/man1/ssh-copy-id.1 + install -m 644 debian/moduli.5 debian/openssh-client-sc/usr/share/man/man5/moduli.5 install -s -o root -g root -m 755 contrib/gnome-ssh-askpass2 debian/ssh-askpass-gnome/usr/lib/openssh/gnome-ssh-askpass install -m 644 debian/gnome-ssh-askpass.1 debian/ssh-askpass-gnome/usr/share/man/man1/gnome-ssh-askpass.1 @@ -182,6 +211,8 @@ install -m 755 debian/ssh-argv0 debian/openssh-client/usr/bin/ssh-argv0 install -m 644 debian/ssh-argv0.1 debian/openssh-client/usr/share/man/man1/ssh-argv0.1 + install -m 755 debian/ssh-argv0 debian/openssh-client-sc/usr/bin/ssh-argv0 + install -m 644 debian/ssh-argv0.1 debian/openssh-client-sc/usr/share/man/man1/ssh-argv0.1 install -o root -g root debian/openssh-server.init debian/openssh-server/etc/init.d/ssh install -o root -g root -m 644 debian/openssh-server.default debian/openssh-server/etc/default/ssh @@ -203,7 +234,7 @@ binary-indep: binary-ssh binary-ssh-krb5 # Build architecture-dependent files here. -binary-arch: binary-openssh-client binary-openssh-server +binary-arch: binary-openssh-client binary-openssh-client-sc binary-openssh-server binary-arch: binary-ssh-askpass-gnome binary-arch: binary-openssh-client-udeb binary-openssh-server-udeb @@ -233,6 +264,28 @@ dh_md5sums dh_builddeb +binary-openssh-client-sc: DH_OPTIONS=-popenssh-client-sc +binary-openssh-client-sc: build install + dh_testdir + dh_testroot + dh_installdebconf + dh_installdocs OVERVIEW README README.dns + cat debian/copyright.head LICENCE > debian/openssh-client-sc/usr/share/doc/openssh-client-sc/copyright + dh_installchangelogs ChangeLog + install -m644 debian/openssh-client.lintian debian/openssh-client-sc/usr/share/lintian/overrides/openssh-client-sc + mv debian/openssh-client-sc/usr/share/doc/openssh-client-sc debian/openssh-client-sc/usr/share/doc/openssh-client + dh_strip + dh_compress + dh_fixperms + chmod u+s debian/openssh-client-sc/usr/lib/openssh/ssh-keysign + dh_installdeb + test ! -e debian/ssh/etc/ssh/ssh_prng_cmds \ + || echo "/etc/ssh/ssh_prng_cmds" >> debian/openssh-client-sc/DEBIAN/conffiles + dh_shlibdeps + dh_gencontrol -- -V'debconf-depends=debconf (>= $(MINDEBCONFVER)) | debconf-2.0' + dh_md5sums + dh_builddeb + binary-openssh-server: DH_OPTIONS=-popenssh-server binary-openssh-server: build install dh_testdir diff -Naur openssh-4.7p1.orig/scard.c openssh-4.7p1/scard.c --- openssh-4.7p1.orig/scard.c 2008-02-05 01:27:54.000000000 +0100 +++ openssh-4.7p1/scard.c 2008-02-05 01:19:52.000000000 +0100 @@ -40,6 +40,9 @@ #include "misc.h" #include "scard.h" +/* currently unused */ +int ask_for_pin = 0; + #if OPENSSL_VERSION_NUMBER < 0x00907000L #define USE_ENGINE #define RSA_get_default_method RSA_get_default_openssl_method diff -Naur openssh-4.7p1.orig/scard.h openssh-4.7p1/scard.h --- openssh-4.7p1.orig/scard.h 2008-02-05 01:27:54.000000000 +0100 +++ openssh-4.7p1/scard.h 2008-02-05 01:19:52.000000000 +0100 @@ -31,6 +31,8 @@ #define SCARD_ERROR_NOCARD -2 #define SCARD_ERROR_APPLET -3 +extern int ask_for_pin; + Key **sc_get_keys(const char *, const char *); void sc_close(void); int sc_put_key(Key *, const char *); diff -Naur openssh-4.7p1.orig/scard-opensc.c openssh-4.7p1/scard-opensc.c --- openssh-4.7p1.orig/scard-opensc.c 2008-02-05 01:27:54.000000000 +0100 +++ openssh-4.7p1/scard-opensc.c 2008-02-05 01:19:52.000000000 +0100 @@ -43,6 +43,8 @@ #include "misc.h" #include "scard.h" +int ask_for_pin=0; + #if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE) #define USE_ENGINE #define RSA_get_default_method RSA_get_default_openssl_method @@ -124,6 +126,7 @@ struct sc_pkcs15_prkey_info *key; struct sc_pkcs15_object *pin_obj; struct sc_pkcs15_pin_info *pin; + char *passphrase = NULL; priv = (struct sc_priv_data *) RSA_get_app_data(rsa); if (priv == NULL) @@ -161,24 +164,47 @@ goto err; } pin = pin_obj->data; + + if (sc_pin) + passphrase = sc_pin; + else if (ask_for_pin) { + /* we need a pin but don't have one => ask for the pin */ + char prompt[64]; + + snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", + key_obj->label ? key_obj->label : "smartcard key"); + passphrase = read_passphrase(prompt, 0); + if (!passphrase || !strcmp(passphrase, "")) + goto err; + } else + /* no pin => error */ + goto err; + r = sc_lock(card); if (r) { error("Unable to lock smartcard: %s", sc_strerror(r)); goto err; } - if (sc_pin != NULL) { - r = sc_pkcs15_verify_pin(p15card, pin, sc_pin, - strlen(sc_pin)); + r = sc_pkcs15_verify_pin(p15card, pin, passphrase, + strlen(passphrase)); if (r) { sc_unlock(card); error("PIN code verification failed: %s", sc_strerror(r)); goto err; } - } + *key_obj_out = key_obj; + if (!sc_pin) { + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + } return 0; err: + if (!sc_pin && passphrase) { + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + } sc_close(); return -1; } diff -Naur openssh-4.7p1.orig/ssh.c openssh-4.7p1/ssh.c --- openssh-4.7p1.orig/ssh.c 2008-02-05 01:27:54.000000000 +0100 +++ openssh-4.7p1/ssh.c 2008-02-05 01:19:52.000000000 +0100 @@ -1225,6 +1225,9 @@ #ifdef SMARTCARD Key **keys; + if (!options.batch_mode) + ask_for_pin = 1; + if (options.smartcard_device != NULL && options.num_identity_files < SSH_MAX_IDENTITY_FILES && (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) {
Patch for faster transfers
See http://www.psc.edu/networking/projects/hpn-ssh/
Here is the patch OpenSSH-4.7p1-hpn13 v1 ported to Debian OpenSSH-4.7p1-5
diff -Naur openssh-4.7p1-debian/HPN12-README openssh-4.7p1/HPN12-README --- openssh-4.7p1-debian/HPN12-README 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/HPN12-README 2008-04-02 14:10:52.000000000 +0200 @@ -0,0 +1,111 @@ +Notes: + +To use the NONE option you must have the NoneEnabled switch set on the server and +you *must* have *both* NoneEnabled and NoneSwitch set to yes on the client. The NONE +feature works with ALL ssh subsystems (as far as we can tell) *AS LONG AS* a tty is not +spawned. If a user uses the -T switch to prevent a tty being created the NONE cipher will +be disabled. + +The performance increase will only be as good as the network and TCP stack tuning +on the reciever side of the connection allows. As a rule of thumb a user will need +at least 10Mb/s connection with a 100ms RTT to see a doubling of performance. The +HPN-SSH home page describes this in greater detail. + +http://www.psc.edu/networking/projects/hpn-ssh + +Buffer Sizes: + +If HPN is disabled the receive buffer size will be set to the +OpenSSH default of 64K. + +If an HPN system connects to a nonHPN system the receive buffer will +be set to the HPNBufferSize value. The default is 2MB but user adjustable. + +If an HPN to HPN connection is established a number of different things might +happen based on the user options and conditions. + +Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set +HPN Buffer Size = up to 64MB +This is the default state. The HPN buffer size will grow to a maximum of 64MB +as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB is +geared towards 10GigE transcontinental connections. + +Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set +HPN Buffer Size = TCP receive buffer value. +Users on non-autotuning systesm should disable TCPRcvBufPoll in the +ssh_cofig and sshd_config + +Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set +HPN Buffer Size = minmum of TCP receive buffer and HPNBufferSize. +This would be the system defined TCP receive buffer (RWIN). + +Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET +HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize. +Generally there is no need to set both. + +Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set +HPN Buffer Size = grows to HPNBufferSize +The buffer will grow up to the maximum size specified here. + +Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET +HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize. +Generally there is no need to set both of these, especially on autotuning +systems. However, if the users wishes to override the autotuning this would be +one way to do it. + +Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET +HPN Buffer Size = TCPRcvBuf. +This will override autotuning and set the TCP recieve buffer to the user defined +value. + + +HPN Specific Configuration options + +TcpRcvBuf=[int]KB client + set the TCP socket receive buffer to n Kilobytes. It can be set up to the +maximum socket size allowed by the system. This is useful in situations where +the tcp receive window is set low but the maximum buffer size is set +higher (as is typical). This works on a per TCP connection basis. You can also +use this to artifically limit the transfer rate of the connection. In these +cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB. +Default is the current system wide tcp receive buffer size. + +TcpRcvBufPoll=[yes/no] client/server + enable of disable the polling of the tcp receive buffer through the life +of the connection. You would want to make sure that this option is enabled +for systems making use of autotuning kernels (linux 2.4.24+, 2.6, MS Vista) +default is yes. + +NoneEnabled=[yes/no] client/server + enable or disable the use of the None cipher. Care must always be used +when enabling this as it will allow users to send data in the clear. However, +it is important to note that authentication information remains encrypted +even if this option is enabled. Set to no by default. + +NoneSwitch=[yes/no] client + Switch the encryption cipher being used to the None cipher after +authentication takes place. NoneEnabled must be enabled on both the client +and server side of the connection. When the connection switches to the NONE +cipher a warning is sent to STDERR. The connection attempt will fail with an +error if a client requests a NoneSwitch from the server that does not explicitly +have NoneEnabled set to yes. Note: The NONE cipher cannot be used in +interactive (shell) sessions and it will fail silently. Set to no by default. + +HPNDisabled=[yes/no] client/server + In some situations, such as transfers on a local area network, the impact +of the HPN code produces a net decrease in performance. In these cases it is +helpful to disable the HPN functionality. By default HPNDisabled is set to no. + +HPNBufferSize=[int]KB client/server + This is the default buffer size the HPN functionality uses when interacting +with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf +option as applied to the internal SSH flow control. This value can range from +1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance +problems depending on the length of the network path. The default size of this buffer +is 2MB. + + +Credits: This patch was conceived, designed, and led by Chris Rapier (rapier@psc.edu) + The majority of the actual coding for versions up to HPN12v1 was performed + by Michael Stevens (mstevens@andrew.cmu.edu). This work was financed, in part, + by Cisco System, Inc., and the National Science Foundation. diff -Naur openssh-4.7p1-debian/Makefile.in openssh-4.7p1/Makefile.in --- openssh-4.7p1-debian/Makefile.in 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/Makefile.in 2008-04-02 14:10:52.000000000 +0200 @@ -43,7 +43,7 @@ LD=@LD@ CFLAGS=@CFLAGS@ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -LIBS=@LIBS@ +LIBS=@LIBS@ -lpthread SSHDLIBS=@SSHDLIBS@ LIBEDIT=@LIBEDIT@ AR=@AR@ @@ -64,7 +64,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \ canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \ - cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \ + cipher-bf1.o cipher-ctr.o cipher-ctr-mt.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 \ diff -Naur openssh-4.7p1-debian/atomicio.c openssh-4.7p1/atomicio.c --- openssh-4.7p1-debian/atomicio.c 2007-06-25 14:15:12.000000000 +0200 +++ openssh-4.7p1/atomicio.c 2008-04-02 14:10:52.000000000 +0200 @@ -57,13 +57,13 @@ res = (f) (fd, s + pos, n - pos); switch (res) { case -1: -#ifdef EWOULDBLOCK - if (errno == EINTR || errno == EWOULDBLOCK) -#else if (errno == EINTR) -#endif continue; +#ifdef EWOULDBLOCK + if (errno == EAGAIN || errno == EWOULDBLOCK) { +#else if (errno == EAGAIN) { +#endif (void)poll(&pfd, 1, -1); continue; } @@ -103,13 +103,13 @@ res = (f) (fd, iov, iovcnt); switch (res) { case -1: -#ifdef EWOULDBLOCK - if (errno == EINTR || errno == EWOULDBLOCK) -#else if (errno == EINTR) -#endif continue; +#ifdef EWOULDBLOCK + if (errno == EAGAIN || errno == EWOULDBLOCK) { +#else if (errno == EAGAIN) { +#endif (void)poll(&pfd, 1, -1); continue; } diff -Naur openssh-4.7p1-debian/auth2.c openssh-4.7p1/auth2.c --- openssh-4.7p1-debian/auth2.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/auth2.c 2008-04-02 14:10:52.000000000 +0200 @@ -44,6 +44,7 @@ #include "dispatch.h" #include "pathnames.h" #include "buffer.h" +#include "canohost.h" #ifdef GSSAPI #include "ssh-gss.h" @@ -68,6 +69,9 @@ extern Authmethod method_gssapi; #endif +static int log_flag = 0; + + Authmethod *authmethods[] = { &method_none, &method_pubkey, @@ -153,6 +157,11 @@ service = packet_get_string(NULL); method = packet_get_string(NULL); debug("userauth-request for user %s service %s method %s", user, service, method); + if (!log_flag) { + logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", + get_remote_ipaddr(), get_remote_port(), user); + log_flag = 1; + } debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); if ((role = strchr(user, '/')) != NULL) diff -Naur openssh-4.7p1-debian/buffer.c openssh-4.7p1/buffer.c --- openssh-4.7p1-debian/buffer.c 2006-08-05 04:39:39.000000000 +0200 +++ openssh-4.7p1/buffer.c 2008-04-02 14:10:52.000000000 +0200 @@ -127,7 +127,9 @@ /* Increase the size of the buffer and retry. */ newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); - if (newlen > BUFFER_MAX_LEN) + /* need it to be slightly larger than the MAX LEN for this */ + /* still investigating *why* but this works for now -cjr */ + if (newlen > (BUFFER_MAX_LEN_HPN + BUFFER_MAX_LEN)) fatal("buffer_append_space: alloc %u not supported", newlen); buffer->buf = xrealloc(buffer->buf, 1, newlen); diff -Naur openssh-4.7p1-debian/buffer.h openssh-4.7p1/buffer.h --- openssh-4.7p1-debian/buffer.h 2006-08-05 04:39:39.000000000 +0200 +++ openssh-4.7p1/buffer.h 2008-04-02 14:10:52.000000000 +0200 @@ -16,6 +16,9 @@ #ifndef BUFFER_H #define BUFFER_H +/* move the following to a more appropriate place and name */ +#define BUFFER_MAX_LEN_HPN 0x4000000 /* 64MB */ + typedef struct { u_char *buf; /* Buffer for data. */ u_int alloc; /* Number of bytes allocated for data. */ diff -Naur openssh-4.7p1-debian/channels.c openssh-4.7p1/channels.c --- openssh-4.7p1-debian/channels.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/channels.c 2008-04-02 14:10:52.000000000 +0200 @@ -311,6 +311,7 @@ c->local_window_max = window; c->local_consumed = 0; c->local_maxpacket = maxpack; + c->dynamic_window = 0; c->remote_id = -1; c->remote_name = xstrdup(remote_name); c->remote_window = 0; @@ -765,11 +766,35 @@ FD_SET(c->sock, writeset); } +int channel_tcpwinsz () { + u_int32_t tcpwinsz = 0; + socklen_t optsz = sizeof(tcpwinsz); + int ret = -1; + + /* if we aren't on a socket return 128KB*/ + if(!packet_connection_is_on_socket()) + return(128*1024); + ret = getsockopt(packet_get_connection_in(), + SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz); + /* return no more than 64MB */ + if ((ret == 0) && tcpwinsz > BUFFER_MAX_LEN_HPN) + tcpwinsz = BUFFER_MAX_LEN_HPN; + debug2("tcpwinsz: %d for connection: %d", tcpwinsz, + packet_get_connection_in()); + return(tcpwinsz); +} + static void channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) { u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); + /* check buffer limits */ + if ((!c->tcpwinsz) || (c->dynamic_window > 0)) + c->tcpwinsz = channel_tcpwinsz(); + + limit = MIN(limit, 2 * c->tcpwinsz); + if (c->istate == CHAN_INPUT_OPEN && limit > 0 && buffer_len(&c->input) < limit && @@ -1661,14 +1686,21 @@ c->local_maxpacket*3) || c->local_window < c->local_window_max/2) && c->local_consumed > 0) { + u_int addition = 0; + /* adjust max window size if we are in a dynamic environment */ + if (c->dynamic_window && (c->tcpwinsz > c->local_window_max)) { + /* grow the window somewhat aggressively to maintain pressure */ + addition = 1.5*(c->tcpwinsz - c->local_window_max); + c->local_window_max += addition; + } packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); packet_put_int(c->remote_id); - packet_put_int(c->local_consumed); + packet_put_int(c->local_consumed + addition); packet_send(); debug2("channel %d: window %d sent adjust %d", c->self, c->local_window, c->local_consumed); - c->local_window += c->local_consumed; + c->local_window += c->local_consumed + addition; c->local_consumed = 0; } return 1; @@ -1871,11 +1903,12 @@ /* If there is data to send to the connection, enqueue some of it now. */ -void +int channel_output_poll(void) { Channel *c; u_int i, len; + int packet_length = 0; for (i = 0; i < channels_alloc; i++) { c = channels[i]; @@ -1915,7 +1948,7 @@ packet_start(SSH2_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(data, dlen); - packet_send(); + packet_length = packet_send(); c->remote_window -= dlen + 4; xfree(data); } @@ -1945,7 +1978,7 @@ SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(buffer_ptr(&c->input), len); - packet_send(); + packet_length = packet_send(); buffer_consume(&c->input, len); c->remote_window -= len; } @@ -1980,12 +2013,13 @@ packet_put_int(c->remote_id); packet_put_int(SSH2_EXTENDED_DATA_STDERR); packet_put_string(buffer_ptr(&c->extended), len); - packet_send(); + packet_length = packet_send(); buffer_consume(&c->extended, len); c->remote_window -= len; debug2("channel %d: sent ext data %d", c->self, len); } } + return (packet_length); } @@ -2342,7 +2376,8 @@ static int channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, - const char *host_to_connect, u_short port_to_connect, int gateway_ports) + const char *host_to_connect, u_short port_to_connect, int gateway_ports, + int hpn_disabled, int hpn_buffer_size) { Channel *c; int sock, r, success = 0, wildcard = 0, is_client; @@ -2455,9 +2490,15 @@ continue; } /* Allocate a channel number for the socket. */ + /* explicitly test for hpn disabled option. if true use smaller window size */ + if (hpn_disabled) c = channel_new("port listener", type, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "port listener", 1); + else + c = channel_new("port listener", type, sock, sock, -1, + hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); strlcpy(c->path, host, sizeof(c->path)); c->host_port = port_to_connect; c->listening_port = listen_port; @@ -2494,20 +2535,22 @@ /* protocol local port fwd, used by ssh (and sshd in v1) */ int channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, - const char *host_to_connect, u_short port_to_connect, int gateway_ports) + const char *host_to_connect, u_short port_to_connect, int gateway_ports, + int hpn_disabled, int hpn_buffer_size) { return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, listen_host, listen_port, host_to_connect, port_to_connect, - gateway_ports); + gateway_ports, hpn_disabled, hpn_buffer_size); } /* protocol v2 remote port fwd, used by sshd */ int channel_setup_remote_fwd_listener(const char *listen_address, - u_short listen_port, int gateway_ports) + u_short listen_port, int gateway_ports, int hpn_disabled, int hpn_buffer_size) { return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, - listen_address, listen_port, NULL, 0, gateway_ports); + listen_address, listen_port, NULL, 0, gateway_ports, + hpn_disabled, hpn_buffer_size); } /* @@ -2622,7 +2665,8 @@ * message if there was an error). */ int -channel_input_port_forward_request(int is_root, int gateway_ports) +channel_input_port_forward_request(int is_root, int gateway_ports, + int hpn_disabled, int hpn_buffer_size) { u_short port, host_port; int success = 0; @@ -2648,7 +2692,7 @@ /* Initiate forwarding */ success = channel_setup_local_fwd_listener(NULL, port, hostname, - host_port, gateway_ports); + host_port, gateway_ports, hpn_disabled, hpn_buffer_size); /* Free the argument string. */ xfree(hostname); @@ -2852,7 +2896,8 @@ */ int x11_create_display_inet(int x11_display_offset, int x11_use_localhost, - int single_connection, u_int *display_numberp, int **chanids) + int single_connection, u_int *display_numberp, int **chanids, + int hpn_disabled, int hpn_buffer_size) { Channel *nc = NULL; int display_number, sock; @@ -2950,10 +2995,17 @@ *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); for (n = 0; n < num_socks; n++) { sock = socks[n]; + /* Is this really necassary? */ + if (hpn_disabled) nc = channel_new("x11 listener", SSH_CHANNEL_X11_LISTENER, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "X11 inet listener", 1); + else + nc = channel_new("x11 listener", + SSH_CHANNEL_X11_LISTENER, sock, sock, -1, + hpn_buffer_size, CHAN_X11_PACKET_DEFAULT, + 0, "X11 inet listener", 1); nc->single_connection = single_connection; (*chanids)[n] = nc->self; } diff -Naur openssh-4.7p1-debian/channels.h openssh-4.7p1/channels.h --- openssh-4.7p1-debian/channels.h 2007-06-12 15:38:54.000000000 +0200 +++ openssh-4.7p1/channels.h 2008-04-02 14:10:52.000000000 +0200 @@ -98,8 +98,10 @@ u_int local_window_max; u_int local_consumed; u_int local_maxpacket; + int dynamic_window; int extended_usage; int single_connection; + u_int tcpwinsz; char *ctype; /* type */ @@ -122,9 +124,11 @@ /* default window/packet sizes for tcp/x11-fwd-channel */ #define CHAN_SES_PACKET_DEFAULT (32*1024) -#define CHAN_SES_WINDOW_DEFAULT (64*CHAN_SES_PACKET_DEFAULT) +#define CHAN_SES_WINDOW_DEFAULT (4*CHAN_SES_PACKET_DEFAULT) + #define CHAN_TCP_PACKET_DEFAULT (32*1024) -#define CHAN_TCP_WINDOW_DEFAULT (64*CHAN_TCP_PACKET_DEFAULT) +#define CHAN_TCP_WINDOW_DEFAULT (4*CHAN_TCP_PACKET_DEFAULT) + #define CHAN_X11_PACKET_DEFAULT (16*1024) #define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT) @@ -193,7 +197,7 @@ void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int); void channel_after_select(fd_set *, fd_set *); -void channel_output_poll(void); +int channel_output_poll(void); int channel_not_very_much_buffered_data(void); void channel_close_all(void); @@ -208,21 +212,21 @@ int channel_add_adm_permitted_opens(char *, int); void channel_clear_permitted_opens(void); void channel_clear_adm_permitted_opens(void); -int channel_input_port_forward_request(int, int); +int channel_input_port_forward_request(int, int, int, int); int channel_connect_to(const char *, u_short); int channel_connect_by_listen_address(u_short); int channel_request_remote_forwarding(const char *, u_short, const char *, u_short); int channel_setup_local_fwd_listener(const char *, u_short, - const char *, u_short, int); + const char *, u_short, int, int, int); void channel_request_rforward_cancel(const char *host, u_short port); -int channel_setup_remote_fwd_listener(const char *, u_short, int); +int channel_setup_remote_fwd_listener(const char *, u_short, int, int, int); int channel_cancel_rport_listener(const char *, u_short); /* x11 forwarding */ int x11_connect_display(void); -int x11_create_display_inet(int, int, int, u_int *, int **); +int x11_create_display_inet(int, int, int, u_int *, int **, int, int); void x11_input_open(int, u_int32_t, void *); void x11_request_forwarding_with_spoofing(int, const char *, const char *, const char *); diff -Naur openssh-4.7p1-debian/cipher-ctr-mt.c openssh-4.7p1/cipher-ctr-mt.c --- openssh-4.7p1-debian/cipher-ctr-mt.c 1970-01-01 01:00:00.000000000 +0100 +++ openssh-4.7p1/cipher-ctr-mt.c 2008-04-02 14:10:52.000000000 +0200 @@ -0,0 +1,473 @@ +/* + * OpenSSH Multi-threaded AES-CTR Cipher + * + * Author: Benjamin Bennett <ben@psc.edu> + * Copyright (c) 2008 Pittsburgh Supercomputing Center. All rights reserved. + * + * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged, + * Copyright (c) 2003 Markus Friedl <markus@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. + */ +#include "includes.h" + +#include <sys/types.h> + +#include <stdarg.h> +#include <string.h> + +#include <openssl/evp.h> + +#include "xmalloc.h" +#include "log.h" + +/* compatibility with old or broken OpenSSL versions */ +#include "openbsd-compat/openssl-compat.h" + +#ifndef USE_BUILTIN_RIJNDAEL +#include <openssl/aes.h> +#endif + +#include <pthread.h> + +/*-------------------- TUNABLES --------------------*/ +/* Number of pregen threads to use */ +#define CIPHER_THREADS 2 + +/* Number of keystream queues */ +#define NUMKQ (CIPHER_THREADS + 2) + +/* Length of a keystream queue */ +#define KQLEN 4096 + +/* Processor cacheline length */ +#define CACHELINE_LEN 64 + +/* Collect thread stats and print at cancellation when in debug mode */ +// #define CIPHER_THREAD_STATS + +/* Use single-byte XOR instead of 8-byte XOR */ +// #define CIPHER_BYTE_XOR +/*-------------------- END TUNABLES --------------------*/ + + +const EVP_CIPHER *evp_aes_ctr_mt(void); + +#ifdef CIPHER_THREAD_STATS +/* + * Struct to collect thread stats + */ +struct thread_stats { + u_int fills; + u_int skips; + u_int waits; + u_int drains; +}; + +/* + * Debug print the thread stats + * Use with pthread_cleanup_push for displaying at thread cancellation + */ +static void +thread_loop_stats(void *x) +{ + struct thread_stats *s = x; + + debug("tid %lu - %u fills, %u skips, %u waits", pthread_self(), + s->fills, s->skips, s->waits); +} + + #define STATS_STRUCT(s) struct thread_stats s + #define STATS_INIT(s) { memset(&s, 0, sizeof(s)); } + #define STATS_FILL(s) { s.fills++; } + #define STATS_SKIP(s) { s.skips++; } + #define STATS_WAIT(s) { s.waits++; } + #define STATS_DRAIN(s) { s.drains++; } +#else + #define STATS_STRUCT(s) + #define STATS_INIT(s) + #define STATS_FILL(s) + #define STATS_SKIP(s) + #define STATS_WAIT(s) + #define STATS_DRAIN(s) +#endif + +/* Keystream Queue state */ +enum { + KQINIT, + KQEMPTY, + KQFILLING, + KQFULL, + KQDRAINING +}; + +/* Keystream Queue struct */ +struct kq { + u_char keys[KQLEN][AES_BLOCK_SIZE]; + u_char ctr[AES_BLOCK_SIZE]; + u_char pad0[CACHELINE_LEN]; + volatile int qstate; + pthread_mutex_t lock; + pthread_cond_t cond; + u_char pad1[CACHELINE_LEN]; +}; + +/* Context struct */ +struct ssh_aes_ctr_ctx +{ + struct kq q[NUMKQ]; + AES_KEY aes_ctx; + STATS_STRUCT(stats); + u_char aes_counter[AES_BLOCK_SIZE]; + pthread_t tid[CIPHER_THREADS]; + int state; + int qidx; + int ridx; +}; + +/* <friedl> + * increment counter 'ctr', + * the counter is of size 'len' bytes and stored in network-byte-order. + * (LSB at ctr[len-1], MSB at ctr[0]) + */ +static void +ssh_ctr_inc(u_char *ctr, u_int len) +{ + int i; + + for (i = len - 1; i >= 0; i--) + if (++ctr[i]) /* continue on overflow */ + return; +} + +/* + * Add num to counter 'ctr' + */ +static void +ssh_ctr_add(u_char *ctr, uint32_t num, u_int len) +{ + int i; + uint16_t n; + + for (n = 0, i = len - 1; i >= 0 && (num || n); i--) { + n = ctr[i] + (num & 0xff) + n; + num >>= 8; + ctr[i] = n & 0xff; + n >>= 8; + } +} + +/* + * Threads may be cancelled in a pthread_cond_wait, we must free the mutex + */ +static void +thread_loop_cleanup(void *x) +{ + pthread_mutex_unlock((pthread_mutex_t *)x); +} + +/* + * The life of a pregen thread: + * Find empty keystream queues and fill them using their counter. + * When done, update counter for the next fill. + */ +static void * +thread_loop(void *x) +{ + AES_KEY key; + STATS_STRUCT(stats); + struct ssh_aes_ctr_ctx *c = x; + struct kq *q; + int i; + int qidx; + + /* Threads stats on cancellation */ + STATS_INIT(stats); +#ifdef CIPHER_THREAD_STATS + pthread_cleanup_push(thread_loop_stats, &stats); +#endif + + /* Thread local copy of AES key */ + memcpy(&key, &c->aes_ctx, sizeof(key)); + + /* + * Handle the special case of startup, one thread must fill + * the first KQ then mark it as draining. Lock held throughout. + */ + if (pthread_equal(pthread_self(), c->tid[0])) { + q = &c->q[0]; + pthread_mutex_lock(&q->lock); + if (q->qstate == KQINIT) { + for (i = 0; i < KQLEN; i++) { + AES_encrypt(q->ctr, q->keys[i], &key); + ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); + } + ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE); + q->qstate = KQDRAINING; + STATS_FILL(stats); + pthread_cond_broadcast(&q->cond); + } + pthread_mutex_unlock(&q->lock); + } + else + STATS_SKIP(stats); + + /* + * Normal case is to find empty queues and fill them, skipping over + * queues already filled by other threads and stopping to wait for + * a draining queue to become empty. + * + * Multiple threads may be waiting on a draining queue and awoken + * when empty. The first thread to wake will mark it as filling, + * others will move on to fill, skip, or wait on the next queue. + */ + for (qidx = 1;; qidx = (qidx + 1) % NUMKQ) { + /* Check if I was cancelled, also checked in cond_wait */ + pthread_testcancel(); + + /* Lock queue and block if its draining */ + q = &c->q[qidx]; + pthread_mutex_lock(&q->lock); + pthread_cleanup_push(thread_loop_cleanup, &q->lock); + while (q->qstate == KQDRAINING || q->qstate == KQINIT) { + STATS_WAIT(stats); + pthread_cond_wait(&q->cond, &q->lock); + } + pthread_cleanup_pop(0); + + /* If filling or full, somebody else got it, skip */ + if (q->qstate != KQEMPTY) { + pthread_mutex_unlock(&q->lock); + STATS_SKIP(stats); + continue; + } + + /* + * Empty, let's fill it. + * Queue lock is relinquished while we do this so others + * can see that it's being filled. + */ + q->qstate = KQFILLING; + pthread_mutex_unlock(&q->lock); + for (i = 0; i < KQLEN; i++) { + AES_encrypt(q->ctr, q->keys[i], &key); + ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); + } + + /* Re-lock, mark full and signal consumer */ + pthread_mutex_lock(&q->lock); + ssh_ctr_add(q->ctr, KQLEN * (NUMKQ - 1), AES_BLOCK_SIZE); + q->qstate = KQFULL; + STATS_FILL(stats); + pthread_cond_signal(&q->cond); + pthread_mutex_unlock(&q->lock); + } + +#ifdef CIPHER_THREAD_STATS + /* Stats */ + pthread_cleanup_pop(1); +#endif + + return NULL; +} + +static int +ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, + u_int len) +{ + struct ssh_aes_ctr_ctx *c; + struct kq *q, *oldq; + int ridx; + u_char *buf; + + if (len == 0) + return (1); + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) + return (0); + + q = &c->q[c->qidx]; + ridx = c->ridx; + + /* src already padded to block multiple */ + while (len > 0) { + buf = q->keys[ridx]; + +#ifdef CIPHER_BYTE_XOR + dest[0] = src[0] ^ buf[0]; + dest[1] = src[1] ^ buf[1]; + dest[2] = src[2] ^ buf[2]; + dest[3] = src[3] ^ buf[3]; + dest[4] = src[4] ^ buf[4]; + dest[5] = src[5] ^ buf[5]; + dest[6] = src[6] ^ buf[6]; + dest[7] = src[7] ^ buf[7]; + dest[8] = src[8] ^ buf[8]; + dest[9] = src[9] ^ buf[9]; + dest[10] = src[10] ^ buf[10]; + dest[11] = src[11] ^ buf[11]; + dest[12] = src[12] ^ buf[12]; + dest[13] = src[13] ^ buf[13]; + dest[14] = src[14] ^ buf[14]; + dest[15] = src[15] ^ buf[15]; +#else + *(uint64_t *)dest = *(uint64_t *)src ^ *(uint64_t *)buf; + *(uint64_t *)(dest + 8) = *(uint64_t *)(src + 8) ^ + *(uint64_t *)(buf + 8); +#endif + + dest += 16; + src += 16; + len -= 16; + ssh_ctr_inc(ctx->iv, AES_BLOCK_SIZE); + + /* Increment read index, switch queues on rollover */ + if ((ridx = (ridx + 1) % KQLEN) == 0) { + oldq = q; + + /* Mark next queue draining, may need to wait */ + c->qidx = (c->qidx + 1) % NUMKQ; + q = &c->q[c->qidx]; + pthread_mutex_lock(&q->lock); + while (q->qstate != KQFULL) { + STATS_WAIT(c->stats); + pthread_cond_wait(&q->cond, &q->lock); + } + q->qstate = KQDRAINING; + pthread_mutex_unlock(&q->lock); + + /* Mark consumed queue empty and signal producers */ + pthread_mutex_lock(&oldq->lock); + oldq->qstate = KQEMPTY; + STATS_DRAIN(c->stats); + pthread_cond_broadcast(&oldq->cond); + pthread_mutex_unlock(&oldq->lock); + } + } + c->ridx = ridx; + return (1); +} + +#define HAVE_NONE 0 +#define HAVE_KEY 1 +#define HAVE_IV 2 +static int +ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, + int enc) +{ + struct ssh_aes_ctr_ctx *c; + int i; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { + c = xmalloc(sizeof(*c)); + + c->state = HAVE_NONE; + for (i = 0; i < NUMKQ; i++) { + pthread_mutex_init(&c->q[i].lock, NULL); + pthread_cond_init(&c->q[i].cond, NULL); + } + + STATS_INIT(c->stats); + + EVP_CIPHER_CTX_set_app_data(ctx, c); + } + + if (c->state == (HAVE_KEY | HAVE_IV)) { + /* Cancel pregen threads */ + for (i = 0; i < CIPHER_THREADS; i++) + pthread_cancel(c->tid[i]); + for (i = 0; i < CIPHER_THREADS; i++) + pthread_join(c->tid[i], NULL); + /* Start over getting key & iv */ + c->state = HAVE_NONE; + } + + if (key != NULL) { + AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, + &c->aes_ctx); + c->state |= HAVE_KEY; + } + + if (iv != NULL) { + memcpy(ctx->iv, iv, AES_BLOCK_SIZE); + c->state |= HAVE_IV; + } + + if (c->state == (HAVE_KEY | HAVE_IV)) { + /* Clear queues */ + memcpy(c->q[0].ctr, ctx->iv, AES_BLOCK_SIZE); + c->q[0].qstate = KQINIT; + for (i = 1; i < NUMKQ; i++) { + memcpy(c->q[i].ctr, ctx->iv, AES_BLOCK_SIZE); + ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE); + c->q[i].qstate = KQEMPTY; + } + c->qidx = 0; + c->ridx = 0; + + /* Start threads */ + for (i = 0; i < CIPHER_THREADS; i++) { + pthread_create(&c->tid[i], NULL, thread_loop, c); + } + pthread_mutex_lock(&c->q[0].lock); + while (c->q[0].qstate != KQDRAINING) + pthread_cond_wait(&c->q[0].cond, &c->q[0].lock); + pthread_mutex_unlock(&c->q[0].lock); + + } + return (1); +} + +static int +ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct ssh_aes_ctr_ctx *c; + int i; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { +#ifdef CIPHER_THREAD_STATS + debug("main thread: %u drains, %u waits", c->stats.drains, + c->stats.waits); +#endif + /* Cancel pregen threads */ + for (i = 0; i < CIPHER_THREADS; i++) + pthread_cancel(c->tid[i]); + for (i = 0; i < CIPHER_THREADS; i++) + pthread_join(c->tid[i], NULL); + + memset(c, 0, sizeof(*c)); + xfree(c); + EVP_CIPHER_CTX_set_app_data(ctx, NULL); + } + return (1); +} + +/* <friedl> */ +const EVP_CIPHER * +evp_aes_ctr_mt(void) +{ + static EVP_CIPHER aes_ctr; + + memset(&aes_ctr, 0, sizeof(EVP_CIPHER)); + aes_ctr.nid = NID_undef; + aes_ctr.block_size = AES_BLOCK_SIZE; + aes_ctr.iv_len = AES_BLOCK_SIZE; + aes_ctr.key_len = 16; + aes_ctr.init = ssh_aes_ctr_init; + aes_ctr.cleanup = ssh_aes_ctr_cleanup; + aes_ctr.do_cipher = ssh_aes_ctr; +#ifndef SSH_OLD_EVP + aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; +#endif + return (&aes_ctr); +} diff -Naur openssh-4.7p1-debian/cipher.c openssh-4.7p1/cipher.c --- openssh-4.7p1-debian/cipher.c 2006-08-05 04:39:39.000000000 +0200 +++ openssh-4.7p1/cipher.c 2008-04-02 14:10:52.000000000 +0200 @@ -55,6 +55,7 @@ extern const EVP_CIPHER *evp_ssh1_3des(void); extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); extern const EVP_CIPHER *evp_aes_128_ctr(void); +extern const EVP_CIPHER *evp_aes_ctr_mt(void); extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); struct Cipher { @@ -81,9 +82,9 @@ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc }, { "rijndael-cbc@lysator.liu.se", SSH_CIPHER_SSH2, 16, 32, 0, EVP_aes_256_cbc }, - { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, evp_aes_128_ctr }, - { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_128_ctr }, - { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_128_ctr }, + { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, evp_aes_ctr_mt }, + { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, evp_aes_ctr_mt }, + { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, evp_aes_ctr_mt }, #ifdef USE_CIPHER_ACSS { "acss@openssh.org", SSH_CIPHER_SSH2, 16, 5, 0, EVP_acss }, #endif @@ -156,7 +157,8 @@ for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; (p = strsep(&cp, CIPHER_SEP))) { c = cipher_by_name(p); - if (c == NULL || c->number != SSH_CIPHER_SSH2) { + if (c == NULL || (c->number != SSH_CIPHER_SSH2 && +c->number != SSH_CIPHER_NONE)) { debug("bad cipher %s [%s]", p, names); xfree(cipher_list); return 0; @@ -330,6 +332,7 @@ int evplen; switch (c->number) { + case SSH_CIPHER_NONE: case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: @@ -364,6 +367,7 @@ int evplen = 0; switch (c->number) { + case SSH_CIPHER_NONE: case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: diff -Naur openssh-4.7p1-debian/clientloop.c openssh-4.7p1/clientloop.c --- openssh-4.7p1-debian/clientloop.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/clientloop.c 2008-04-02 14:10:52.000000000 +0200 @@ -915,13 +915,16 @@ set_nonblock(client_fd); + if (options.hpn_disabled) window = CHAN_SES_WINDOW_DEFAULT; + else + window = options.hpn_buffer_size; + 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); @@ -1023,7 +1026,8 @@ if (local) { if (channel_setup_local_fwd_listener(fwd.listen_host, fwd.listen_port, fwd.connect_host, - fwd.connect_port, options.gateway_ports) < 0) { + fwd.connect_port, options.gateway_ports, + options.hpn_disabled, options.hpn_buffer_size) < 0) { logit("Port forwarding failed."); goto out; } @@ -1724,10 +1728,16 @@ 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); + if (options.hpn_disabled) + c = channel_new("forwarded-tcpip", + SSH_CHANNEL_CONNECTING, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, + originator_address, 1); + else + c = channel_new("forwarded-tcpip", + SSH_CHANNEL_CONNECTING, sock, sock, -1, + options.hpn_buffer_size, options.hpn_buffer_size, 0, + originator_address, 1); xfree(originator_address); xfree(listen_address); return c; @@ -1761,9 +1771,15 @@ sock = x11_connect_display(); if (sock < 0) return NULL; + /* again is this really necessary for X11? */ + if (options.hpn_disabled) c = channel_new("x11", SSH_CHANNEL_X11_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); + else + c = channel_new("x11", + SSH_CHANNEL_X11_OPEN, sock, sock, -1, + options.hpn_buffer_size, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); c->force_drain = 1; return c; } @@ -1782,10 +1798,17 @@ sock = ssh_get_authentication_socket(); if (sock < 0) return NULL; - c = channel_new("authentication agent connection", - SSH_CHANNEL_OPEN, sock, sock, -1, - CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, - "authentication agent connection", 1); + /* not sure this is really needed here either */ + if (options.hpn_disabled) + c = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, + "authentication agent connection", 1); + else + c = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + options.hpn_buffer_size, options.hpn_buffer_size, 0, + "authentication agent connection", 1); c->force_drain = 1; return c; } @@ -1812,10 +1835,18 @@ return -1; } + if(options.hpn_disabled) c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "tun", 1); + else + c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, + options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, + 0, "tun", 1); c->datagram = 1; + + #if defined(SSH_TUN_FILTER) if (options.tun_open == SSH_TUNMODE_POINTOPOINT) channel_register_filter(c->self, sys_tun_infilter, diff -Naur openssh-4.7p1-debian/compat.c openssh-4.7p1/compat.c --- openssh-4.7p1-debian/compat.c 2007-01-05 06:26:46.000000000 +0100 +++ openssh-4.7p1/compat.c 2008-04-02 14:10:52.000000000 +0200 @@ -169,6 +169,15 @@ strlen(check[i].pat), 0) == 1) { debug("match: %s pat %s", version, check[i].pat); datafellows = check[i].bugs; + /* Check to see if the remote side is OpenSSH and not HPN */ + if(strstr(version,"OpenSSH") != NULL) + { + if (strstr(version,"hpn") == NULL) + { + datafellows |= SSH_BUG_LARGEWINDOW; + debug("Remote is NON-HPN aware"); + } + } return; } } diff -Naur openssh-4.7p1-debian/compat.h openssh-4.7p1/compat.h --- openssh-4.7p1-debian/compat.h 2007-01-05 06:26:46.000000000 +0100 +++ openssh-4.7p1/compat.h 2008-04-02 14:10:52.000000000 +0200 @@ -57,6 +57,7 @@ #define SSH_BUG_FIRSTKEX 0x00800000 #define SSH_OLD_FORWARD_ADDR 0x01000000 #define SSH_BUG_RFWD_ADDR 0x02000000 +#define SSH_BUG_LARGEWINDOW 0x04000000 void enable_compat13(void); void enable_compat20(void); diff -Naur openssh-4.7p1-debian/debian/changelog openssh-4.7p1/debian/changelog --- openssh-4.7p1-debian/debian/changelog 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/debian/changelog 2008-04-02 14:12:40.000000000 +0200 @@ -1,3 +1,9 @@ +openssh (1:4.7p1-5-hpn13v1) unstable; urgency=low + + * Integrates HPN-SSH patch + + -- Philippe Teuwen <phil a teuwen o org> Wed, 02 Apr 2008 12:37:00 +0000 + openssh (1:4.7p1-5) unstable; urgency=low * Recommends: xauth rather than Suggests: xbase-clients. diff -Naur openssh-4.7p1-debian/kex.c openssh-4.7p1/kex.c --- openssh-4.7p1-debian/kex.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/kex.c 2008-04-02 14:10:52.000000000 +0200 @@ -48,6 +48,7 @@ #include "match.h" #include "dispatch.h" #include "monitor.h" +#include "canohost.h" #ifdef GSSAPI #include "ssh-gss.h" @@ -68,7 +69,8 @@ static void kex_choose_conf(Kex *); /* put algorithm proposal into buffer */ -static void +/* used in sshconnect.c as well as kex.c */ +void kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) { u_int i; @@ -394,6 +396,13 @@ int nenc, nmac, ncomp; u_int mode, ctos, need; int first_kex_follows, type; + int log_flag = 0; + + int auth_flag; + + auth_flag = packet_authentication_state(); + + debug ("AUTH STATE IS %d", auth_flag); my = kex_buf2prop(&kex->my, NULL); peer = kex_buf2prop(&kex->peer, &first_kex_follows); @@ -418,11 +427,34 @@ choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); + debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name); + if (strcmp(newkeys->enc.name, "none") == 0) { + debug("Requesting NONE. Authflag is %d", auth_flag); + if (auth_flag == 1) { + debug("None requested post authentication."); + } else { + fatal("Pre-authentication none cipher requests are not allowed."); + } + } debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); + /* client starts withctos = 0 && log flag = 0 and no log*/ + /* 2nd client pass ctos=1 and flag = 1 so no log*/ + /* server starts with ctos =1 && log_flag = 0 so log */ + /* 2nd sever pass ctos = 1 && log flag = 1 so no log*/ + /* -cjr*/ + if (ctos && !log_flag) { + logit("SSH: Server;Ltype: Kex;Remote: %s-%d;Enc: %s;MAC: %s;Comp: %s", + get_remote_ipaddr(), + get_remote_port(), + newkeys->enc.name, + newkeys->mac.name, + newkeys->comp.name); + } + log_flag = 1; } choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], diff -Naur openssh-4.7p1-debian/kex.h openssh-4.7p1/kex.h --- openssh-4.7p1-debian/kex.h 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/kex.h 2008-04-02 14:10:52.000000000 +0200 @@ -135,6 +135,8 @@ void (*kex[KEX_MAX])(Kex *); }; +void kex_prop2buf(Buffer *, char *proposal[PROPOSAL_MAX]); + Kex *kex_setup(char *[PROPOSAL_MAX]); void kex_finish(Kex *); diff -Naur openssh-4.7p1-debian/myproposal.h openssh-4.7p1/myproposal.h --- openssh-4.7p1-debian/myproposal.h 2007-06-11 06:01:42.000000000 +0200 +++ openssh-4.7p1/myproposal.h 2008-04-02 14:10:52.000000000 +0200 @@ -46,6 +46,8 @@ "arcfour128,arcfour256,arcfour," \ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \ "aes128-ctr,aes192-ctr,aes256-ctr" +#define KEX_ENCRYPT_INCLUDE_NONE KEX_DEFAULT_ENCRYPT \ + ",none" #define KEX_DEFAULT_MAC \ "hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160," \ "hmac-ripemd160@openssh.com," \ diff -Naur openssh-4.7p1-debian/packet.c openssh-4.7p1/packet.c --- openssh-4.7p1-debian/packet.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/packet.c 2008-04-02 14:10:52.000000000 +0200 @@ -713,7 +713,7 @@ /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ -static void +static int packet_send2_wrapped(void) { u_char type, *cp, *macbuf = NULL; @@ -825,11 +825,13 @@ set_newkeys(MODE_OUT); else if (type == SSH2_MSG_USERAUTH_SUCCESS && server_side) packet_enable_delayed_compress(); + return(packet_length); } -static void +static int packet_send2(void) { + static int packet_length = 0; static int rekeying = 0; struct packet *p; u_char type, *cp; @@ -847,7 +849,7 @@ memcpy(&p->payload, &outgoing_packet, sizeof(Buffer)); buffer_init(&outgoing_packet); TAILQ_INSERT_TAIL(&outgoing, p, next); - return; + return(sizeof(Buffer)); } } @@ -855,7 +857,7 @@ if (type == SSH2_MSG_KEXINIT) rekeying = 1; - packet_send2_wrapped(); + packet_length = packet_send2_wrapped(); /* after a NEWKEYS message we can send the complete queue */ if (type == SSH2_MSG_NEWKEYS) { @@ -868,19 +870,22 @@ sizeof(Buffer)); TAILQ_REMOVE(&outgoing, p, next); xfree(p); - packet_send2_wrapped(); + packet_length += packet_send2_wrapped(); } } + return(packet_length); } -void +int packet_send(void) { + int packet_len = 0; if (compat20) - packet_send2(); + packet_len = packet_send2(); else packet_send1(); DBG(debug("packet_send done")); + return(packet_len); } /* @@ -1429,21 +1434,23 @@ /* Checks if there is any buffered output, and tries to write some of the output. */ -void +int packet_write_poll(void) { - int len = buffer_len(&output); + int len = 0; + len = buffer_len(&output); if (len > 0) { len = write(connection_out, buffer_ptr(&output), len); if (len <= 0) { if (errno == EAGAIN) - return; + return (0); else fatal("Write failed: %.100s", strerror(errno)); } buffer_consume(&output, len); } + return(len); } /* @@ -1451,14 +1458,15 @@ * written. */ -void +int packet_write_wait(void) { fd_set *setp; + u_int bytes_sent = 0; setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS), sizeof(fd_mask)); - packet_write_poll(); + bytes_sent += packet_write_poll(); while (packet_have_data_to_write()) { memset(setp, 0, howmany(connection_out + 1, NFDBITS) * sizeof(fd_mask)); @@ -1466,9 +1474,10 @@ while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && (errno == EAGAIN || errno == EINTR)) ; - packet_write_poll(); + bytes_sent += packet_write_poll(); } xfree(setp); + return (bytes_sent); } /* Returns true if there is buffered data to write to the connection. */ @@ -1590,12 +1599,24 @@ } } +int rekey_requested = 0; +void +packet_request_rekeying(void) +{ + rekey_requested = 1; +} + #define MAX_PACKETS (1U<<31) int packet_need_rekeying(void) { if (datafellows & SSH_BUG_NOREKEY) return 0; + if (rekey_requested == 1) + { + rekey_requested = 0; + return 1; + } return (p_send.packets > MAX_PACKETS) || (p_read.packets > MAX_PACKETS) || @@ -1620,3 +1641,9 @@ { after_authentication = 1; } + +int +packet_authentication_state(void) +{ + return(after_authentication); +} diff -Naur openssh-4.7p1-debian/packet.h openssh-4.7p1/packet.h --- openssh-4.7p1-debian/packet.h 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/packet.h 2008-04-02 14:10:52.000000000 +0200 @@ -20,6 +20,7 @@ #include <openssl/bn.h> +void packet_request_rekeying(void); void packet_set_connection(int, int, int); void packet_set_nonblocking(void); int packet_get_connection_in(void); @@ -34,6 +35,7 @@ int packet_is_interactive(void); void packet_set_server(void); void packet_set_authenticated(void); +int packet_authentication_state(void); void packet_start(u_char); void packet_put_char(int ch); @@ -43,7 +45,7 @@ void packet_put_string(const void *buf, u_int len); void packet_put_cstring(const char *str); void packet_put_raw(const void *buf, u_int len); -void packet_send(void); +int packet_send(void); int packet_read(void); void packet_read_expect(int type); @@ -71,8 +73,8 @@ int packet_get_ssh1_cipher(void); void packet_set_iv(int, u_char *); -void packet_write_poll(void); -void packet_write_wait(void); +int packet_write_poll(void); +int packet_write_wait(void); int packet_have_data_to_write(void); int packet_not_very_much_data_to_write(void); diff -Naur openssh-4.7p1-debian/readconf.c openssh-4.7p1/readconf.c --- openssh-4.7p1-debian/readconf.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/readconf.c 2008-04-02 14:10:52.000000000 +0200 @@ -135,6 +135,8 @@ oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oProtocolKeepAlives, oSetupTimeOut, + oNoneEnabled, oTcpRcvBufPoll, oTcpRcvBuf, oNoneSwitch, oHPNDisabled, + oHPNBufferSize, oDeprecated, oUnsupported } OpCodes; @@ -237,6 +239,12 @@ { "permitlocalcommand", oPermitLocalCommand }, { "protocolkeepalives", oProtocolKeepAlives }, { "setuptimeout", oSetupTimeOut }, + { "noneenabled", oNoneEnabled }, + { "tcprcvbufpoll", oTcpRcvBufPoll }, + { "tcprcvbuf", oTcpRcvBuf }, + { "noneswitch", oNoneSwitch }, + { "hpndisabled", oHPNDisabled }, + { "hpnbuffersize", oHPNBufferSize }, { NULL, oBadOption } }; @@ -472,6 +480,37 @@ intptr = &options->check_host_ip; goto parse_flag; + case oNoneEnabled: + intptr = &options->none_enabled; + goto parse_flag; + + /* we check to see if the command comes from the */ + /* command line or not. If it does then enable it */ + /* otherwise fail. NONE should never be a default configuration */ + case oNoneSwitch: + if(strcmp(filename,"command-line")==0) + { + intptr = &options->none_switch; + goto parse_flag; + } else { + error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename); + error("Continuing..."); + debug("NoneSwitch directive found in %.200s.", filename); + return 0; + } + + case oHPNDisabled: + intptr = &options->hpn_disabled; + goto parse_flag; + + case oHPNBufferSize: + intptr = &options->hpn_buffer_size; + goto parse_int; + + case oTcpRcvBufPoll: + intptr = &options->tcp_rcv_buf_poll; + goto parse_flag; + case oVerifyHostKeyDNS: intptr = &options->verify_host_key_dns; goto parse_yesnoask; @@ -651,6 +690,10 @@ intptr = &options->connection_attempts; goto parse_int; + case oTcpRcvBuf: + intptr = &options->tcp_rcv_buf; + goto parse_int; + case oCipher: intptr = &options->cipher; arg = strdelim(&s); @@ -1111,6 +1154,12 @@ options->tun_remote = -1; options->local_command = NULL; options->permit_local_command = -1; + options->none_switch = -1; + options->none_enabled = -1; + options->hpn_disabled = -1; + options->hpn_buffer_size = -1; + options->tcp_rcv_buf_poll = -1; + options->tcp_rcv_buf = -1; } /* @@ -1242,6 +1291,29 @@ } if (options->server_alive_count_max == -1) options->server_alive_count_max = 3; + if (options->none_switch == -1) + options->none_switch = 0; + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; + if (options->hpn_buffer_size > -1) + { + /* if a user tries to set the size to 0 set it to 1KB */ + if (options->hpn_buffer_size == 0) + options->hpn_buffer_size = 1024; + /*limit the buffer to 64MB*/ + if (options->hpn_buffer_size > 65536) + { + options->hpn_buffer_size = 65536*1024; + debug("User requested buffer larger than 64MB. Request reverted to 64MB"); + } + debug("hpn_buffer_size set to %d", options->hpn_buffer_size); + } + if (options->tcp_rcv_buf == 0) + options->tcp_rcv_buf = 1; + if (options->tcp_rcv_buf > -1) + options->tcp_rcv_buf *=1024; + if (options->tcp_rcv_buf_poll == -1) + options->tcp_rcv_buf_poll = 1; if (options->control_master == -1) options->control_master = 0; if (options->hash_known_hosts == -1) diff -Naur openssh-4.7p1-debian/readconf.h openssh-4.7p1/readconf.h --- openssh-4.7p1-debian/readconf.h 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/readconf.h 2008-04-02 14:10:52.000000000 +0200 @@ -59,6 +59,12 @@ * (best). */ int tcp_keep_alive; /* Set SO_KEEPALIVE. */ int setuptimeout; /* timeout in the protocol banner exchange */ + + int tcp_rcv_buf; /* user switch to set tcp recv buffer */ + int tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */ + int hpn_disabled; /* Switch to disable HPN buffer management */ + int hpn_buffer_size; /* User definable size for HPN buffer window */ + LogLevel log_level; /* Level for logging. */ int port; /* Port to connect. */ @@ -104,6 +110,8 @@ int enable_ssh_keysign; int rekey_limit; + int none_switch; /* Use none cipher */ + int none_enabled; /* Allow none to be used */ int no_host_authentication_for_localhost; int identities_only; int server_alive_interval; diff -Naur openssh-4.7p1-debian/scp.c openssh-4.7p1/scp.c --- openssh-4.7p1-debian/scp.c 2007-08-08 06:29:58.000000000 +0200 +++ openssh-4.7p1/scp.c 2008-04-02 14:10:52.000000000 +0200 @@ -585,7 +585,7 @@ off_t i, amt, statbytes; size_t result; int fd = -1, haderr, indx; - char *last, *name, buf[2048], encname[MAXPATHLEN]; + char *last, *name, buf[16384], encname[MAXPATHLEN]; int len; for (indx = 0; indx < argc; ++indx) { @@ -645,7 +645,7 @@ (void) atomicio(vwrite, remout, buf, strlen(buf)); if (response() < 0) goto next; - if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { + if ((bp = allocbuf(&buffer, fd, sizeof(buf))) == NULL) { next: if (fd != -1) { (void) close(fd); fd = -1; @@ -813,7 +813,7 @@ mode_t mode, omode, mask; off_t size, statbytes; int setimes, targisdir, wrerrno = 0; - char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; + char ch, *cp, *np, *targ, *why, *vect[1], buf[16384]; struct timeval tv[2]; #define atime tv[0] @@ -974,7 +974,7 @@ continue; } (void) atomicio(vwrite, remout, "", 1); - if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { + if ((bp = allocbuf(&buffer, ofd, sizeof(buf))) == NULL) { (void) close(ofd); continue; } @@ -984,8 +984,8 @@ statbytes = 0; if (showprogress) start_progress_meter(curfile, size, &statbytes); - for (count = i = 0; i < size; i += 4096) { - amt = 4096; + for (count = i = 0; i < size; i += sizeof(buf)) { + amt = sizeof(buf); if (i + amt > size) amt = size - i; count += amt; @@ -1002,7 +1002,7 @@ } while (amt > 0); if (limit_rate) - bwlimit(4096); + bwlimit(sizeof(buf)); if (count == bp->cnt) { /* Keep reading so we stay sync'd up. */ diff -Naur openssh-4.7p1-debian/servconf.c openssh-4.7p1/servconf.c --- openssh-4.7p1-debian/servconf.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/servconf.c 2008-04-02 14:10:52.000000000 +0200 @@ -124,11 +124,19 @@ options->permit_tun = -1; options->num_permitted_opens = -1; options->adm_forced_command = NULL; + options->none_enabled = -1; + options->tcp_rcv_buf_poll = -1; + options->hpn_disabled = -1; + options->hpn_buffer_size = -1; } void fill_default_server_options(ServerOptions *options) { + int sock; + int socksize; + int socksizelen = sizeof(int); + /* Portable-specific options */ if (options->use_pam == -1) options->use_pam = 0; @@ -256,6 +264,42 @@ if (options->permit_tun == -1) options->permit_tun = SSH_TUNMODE_NO; + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; + + if (options->hpn_buffer_size == -1) { + /* option not explicitly set. Now we have to figure out */ + /* what value to use */ + if (options->hpn_disabled == 1) { + options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; + } else { + /* get the current RCV size and set it to that */ + /*create a socket but don't connect it */ + /* we use that the get the rcv socket size */ + sock = socket(AF_INET, SOCK_STREAM, 0); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + close(sock); + options->hpn_buffer_size = socksize; + debug ("HPN Buffer Size: %d", options->hpn_buffer_size); + + } + } else { + /* we have to do this incase the user sets both values in a contradictory */ + /* manner. hpn_disabled overrrides hpn_buffer_size*/ + if (options->hpn_disabled <= 0) { + if (options->hpn_buffer_size == 0) + options->hpn_buffer_size = 1; + /* limit the maximum buffer to 64MB */ + if (options->hpn_buffer_size > 64*1024) { + options->hpn_buffer_size = 64*1024*1024; + } else { + options->hpn_buffer_size *= 1024; + } + } else + options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT; + } + /* Turn privilege separation on by default */ if (use_privsep == -1) use_privsep = 1; @@ -300,7 +344,8 @@ sGssKeyEx, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, - sUsePrivilegeSeparation, + sUsePrivilegeSeparation, sNoneEnabled, sTcpRcvBufPoll, + sHPNDisabled, sHPNBufferSize, sDeprecated, sUnsupported } ServerOpCodes; @@ -419,6 +464,10 @@ { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, + { "noneenabled", sNoneEnabled }, + { "hpndisabled", sHPNDisabled }, + { "hpnbuffersize", sHPNBufferSize }, + { "tcprcvbufpoll", sTcpRcvBufPoll }, { NULL, sBadOption, 0 } }; @@ -434,6 +483,7 @@ for (i = 0; keywords[i].name; i++) if (strcasecmp(cp, keywords[i].name) == 0) { + debug ("Config token is %s", keywords[i].name); *flags = keywords[i].flags; return keywords[i].opcode; } @@ -843,6 +893,22 @@ *intptr = value; break; + case sNoneEnabled: + intptr = &options->none_enabled; + goto parse_flag; + + case sTcpRcvBufPoll: + intptr = &options->tcp_rcv_buf_poll; + goto parse_flag; + + case sHPNDisabled: + intptr = &options->hpn_disabled; + goto parse_flag; + + case sHPNBufferSize: + intptr = &options->hpn_buffer_size; + goto parse_int; + case sIgnoreUserKnownHosts: intptr = &options->ignore_user_known_hosts; goto parse_flag; diff -Naur openssh-4.7p1-debian/servconf.h openssh-4.7p1/servconf.h --- openssh-4.7p1-debian/servconf.h 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/servconf.h 2008-04-02 14:10:52.000000000 +0200 @@ -139,6 +139,10 @@ char *adm_forced_command; int use_pam; /* Enable auth via PAM */ + int none_enabled; /* enable NONE cipher switch */ + int tcp_rcv_buf_poll; /* poll tcp rcv window in autotuning kernels*/ + int hpn_disabled; /* disable hpn functionality. false by default */ + int hpn_buffer_size; /* set the hpn buffer size - default 3MB */ int permit_tun; diff -Naur openssh-4.7p1-debian/serverloop.c openssh-4.7p1/serverloop.c --- openssh-4.7p1-debian/serverloop.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/serverloop.c 2008-04-02 14:10:52.000000000 +0200 @@ -92,10 +92,10 @@ static int fdout; /* Descriptor for stdout (for reading); May be same number as fdin. */ static int fderr; /* Descriptor for stderr. May be -1. */ -static long stdin_bytes = 0; /* Number of bytes written to stdin. */ -static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ -static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ -static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ +static u_long stdin_bytes = 0; /* Number of bytes written to stdin. */ +static u_long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ +static u_long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ +static u_long fdout_bytes = 0; /* Number of stdout bytes read from program. */ static int stdin_eof = 0; /* EOF message received from client. */ static int fdout_eof = 0; /* EOF encountered reading from fdout. */ static int fderr_eof = 0; /* EOF encountered readung from fderr. */ @@ -120,6 +120,20 @@ static void server_init_dispatch(void); /* + * Returns current time in seconds from Jan 1, 1970 with the maximum + * available resolution. + */ + +static double +get_current_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; +} + + +/* * we write to this pipe if a SIGCHLD is caught in order to avoid * the race between select() and child_terminated */ @@ -408,6 +422,7 @@ } else { /* Buffer any received data. */ packet_process_incoming(buf, len); + fdout_bytes += len; } } if (compat20) @@ -430,6 +445,7 @@ } else { buffer_append(&stdout_buffer, buf, len); fdout_bytes += len; + debug ("FD out now: %ld", fdout_bytes); } } /* Read and buffer any available stderr data from the program. */ @@ -496,7 +512,7 @@ } /* Send any buffered packet data to the client. */ if (FD_ISSET(connection_out, writeset)) - packet_write_poll(); + stdin_bytes += packet_write_poll(); } /* @@ -813,8 +829,10 @@ { fd_set *readset = NULL, *writeset = NULL; int rekeying = 0, max_fd, nalloc = 0; + double start_time, total_time; debug("Entering interactive session for SSH2."); + start_time = get_current_time(); mysignal(SIGCHLD, sigchld_handler); child_terminated = 0; @@ -876,6 +894,11 @@ /* free remaining sessions, e.g. remove wtmp entries */ session_destroy_all(NULL); + total_time = get_current_time() - start_time; + logit("SSH: Server;LType: Throughput;Remote: %s-%d;IN: %lu;OUT: %lu;Duration: %.1f;tPut_in: %.1f;tPut_out: %.1f", + get_remote_ipaddr(), get_remote_port(), + stdin_bytes, fdout_bytes, total_time, stdin_bytes / total_time, + fdout_bytes / total_time); } static void @@ -957,9 +980,14 @@ xfree(originator); if (sock < 0) return NULL; + if (options.hpn_disabled) c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); + else + c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, + sock, sock, -1, options.hpn_buffer_size, + CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); return c; } @@ -994,8 +1022,12 @@ sock = tun_open(tun, mode); if (sock < 0) goto done; + if (options.hpn_disabled) c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + else + c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, + options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); c->datagram = 1; #if defined(SSH_TUN_FILTER) if (mode == SSH_TUNMODE_POINTOPOINT) @@ -1025,6 +1057,8 @@ c = channel_new("session", SSH_CHANNEL_LARVAL, -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 0, "server-session", 1); + if ((options.tcp_rcv_buf_poll > 0) && (!options.hpn_disabled)) + c->dynamic_window = 1; if (session_open(the_authctxt, c->self) != 1) { debug("session open failed, free channel %d", c->self); channel_free(c); @@ -1121,7 +1155,8 @@ } else { /* Start listening on the port */ success = channel_setup_remote_fwd_listener( - listen_address, listen_port, options.gateway_ports); + listen_address, listen_port, options.gateway_ports, + options.hpn_disabled, options.hpn_buffer_size); } xfree(listen_address); } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { diff -Naur openssh-4.7p1-debian/session.c openssh-4.7p1/session.c --- openssh-4.7p1-debian/session.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/session.c 2008-04-02 14:10:52.000000000 +0200 @@ -211,6 +211,7 @@ packet_disconnect("listen: %.100s", strerror(errno)); /* Allocate a channel for the authentication agent socket. */ + /* this shouldn't matter if its hpn or not - cjr */ nc = channel_new("auth socket", SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, @@ -348,7 +349,8 @@ } debug("Received TCP/IP port forwarding request."); if (channel_input_port_forward_request(s->pw->pw_uid == 0, - options.gateway_ports) < 0) { + options.gateway_ports, options.hpn_disabled, + options.hpn_buffer_size) < 0) { debug("Port forwarding failed."); break; } @@ -2058,11 +2060,18 @@ */ if (s->chanid == -1) fatal("no channel for session %d", s->self); + if(options.hpn_disabled) channel_set_fds(s->chanid, fdout, fdin, fderr, fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 1, CHAN_SES_WINDOW_DEFAULT); + else + channel_set_fds(s->chanid, + fdout, fdin, fderr, + fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + 1, + options.hpn_buffer_size); } /* @@ -2407,7 +2416,8 @@ } if (x11_create_display_inet(options.x11_display_offset, options.x11_use_localhost, s->single_connection, - &s->display_number, &s->x11_chanids) == -1) { + &s->display_number, &s->x11_chanids, + options.hpn_disabled, options.hpn_buffer_size) == -1) { debug("x11_create_display_inet failed."); return 0; } diff -Naur openssh-4.7p1-debian/ssh.c openssh-4.7p1/ssh.c --- openssh-4.7p1-debian/ssh.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/ssh.c 2008-04-02 14:10:52.000000000 +0200 @@ -507,9 +507,6 @@ no_shell_flag = 1; no_tty_flag = 1; break; - case 'T': - no_tty_flag = 1; - break; case 'o': dummy = 1; line = xstrdup(optarg); @@ -518,6 +515,13 @@ exit(255); xfree(line); break; + case 'T': + no_tty_flag = 1; + /* ensure that the user doesn't try to backdoor a */ + /* null cipher switch on an interactive session */ + /* so explicitly disable it no matter what */ + options.none_switch=0; + break; case 's': subsystem_flag = 1; break; @@ -834,7 +838,8 @@ options.local_forwards[i].listen_port, options.local_forwards[i].connect_host, options.local_forwards[i].connect_port, - options.gateway_ports); + options.gateway_ports, options.hpn_disabled, + options.hpn_buffer_size); } if (i > 0 && success != i && options.exit_on_forward_failure) fatal("Could not request local forwarding."); @@ -1147,6 +1152,9 @@ { Channel *c; int window, packetmax, in, out, err; + int sock; + int socksize; + int socksizelen = sizeof(int); if (stdin_null_flag) { in = open(_PATH_DEVNULL, O_RDONLY); @@ -1167,9 +1175,70 @@ if (!isatty(err)) set_nonblock(err); - window = CHAN_SES_WINDOW_DEFAULT; + /* we need to check to see if what they want to do about buffer */ + /* sizes here. In a hpn to nonhpn connection we want to limit */ + /* the window size to something reasonable in case the far side */ + /* has the large window bug. In hpn to hpn connection we want to */ + /* use the max window size but allow the user to override it */ + /* lastly if they disabled hpn then use the ssh std window size */ + + /* so why don't we just do a getsockopt() here and set the */ + /* ssh window to that? In the case of a autotuning receive */ + /* window the window would get stuck at the initial buffer */ + /* size generally less than 96k. Therefore we need to set the */ + /* maximum ssh window size to the maximum hpn buffer size */ + /* unless the user has specifically set the tcprcvbufpoll */ + /* to no. In which case we *can* just set the window to the */ + /* minimum of the hpn buffer size and tcp receive buffer size */ + + if(options.hpn_disabled) + { + options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; + } + else if (datafellows & SSH_BUG_LARGEWINDOW) + { + debug("HPN to Non-HPN Connection"); + if (options.hpn_buffer_size < 0) + options.hpn_buffer_size = 2*1024*1024; + } + else + { + if (options.hpn_buffer_size < 0) + options.hpn_buffer_size = BUFFER_MAX_LEN_HPN; + + /*create a socket but don't connect it */ + /* we use that the get the rcv socket size */ + sock = socket(AF_INET, SOCK_STREAM, 0); + /* if they are using the tcp_rcv_buf option */ + /* attempt to set the buffer size to that */ + if (options.tcp_rcv_buf) + setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&options.tcp_rcv_buf, + sizeof(options.tcp_rcv_buf)); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + close(sock); + debug("socksize %d", socksize); + if (options.tcp_rcv_buf_poll <= 0) + { + options.hpn_buffer_size = MIN(socksize,options.hpn_buffer_size); + debug ("MIN of TCP RWIN and HPNBufferSize: %d", options.hpn_buffer_size); + } + else + { + if (options.tcp_rcv_buf > 0) + options.hpn_buffer_size = MIN(options.tcp_rcv_buf, options.hpn_buffer_size); + debug ("MIN of TCPRcvBuf and HPNBufferSize: %d", options.hpn_buffer_size); + } + + } + + debug("Final hpn_buffer_size = %d", options.hpn_buffer_size); + + window = options.hpn_buffer_size; + packetmax = CHAN_SES_PACKET_DEFAULT; if (tty_flag) { + window = 4*CHAN_SES_PACKET_DEFAULT; window >>= 1; packetmax >>= 1; } @@ -1177,7 +1246,10 @@ "session", SSH_CHANNEL_OPENING, in, out, err, window, packetmax, CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); - + if ((options.tcp_rcv_buf_poll > 0) && (!options.hpn_disabled)) { + c->dynamic_window = 1; + debug ("Enabled Dynamic Window Scaling\n"); + } debug3("ssh_session2_open: channel_new: %d", c->self); channel_send_open(c->self); diff -Naur openssh-4.7p1-debian/sshconnect.c openssh-4.7p1/sshconnect.c --- openssh-4.7p1-debian/sshconnect.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/sshconnect.c 2008-04-02 14:10:52.000000000 +0200 @@ -171,6 +171,31 @@ } /* + * Set TCP receive buffer if requested. + * Note: tuning needs to happen after the socket is + * created but before the connection happens + * so winscale is negotiated properly -cjr + */ +static void +ssh_set_socket_recvbuf(int sock) +{ + void *buf = (void *)&options.tcp_rcv_buf; + int sz = sizeof(options.tcp_rcv_buf); + int socksize; + int socksizelen = sizeof(int); + + debug("setsockopt Attempting to set SO_RCVBUF to %d", options.tcp_rcv_buf); + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) { + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &socksizelen); + debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), socksize); + } + else + error("Couldn't set socket receive buffer to %d: %.100s", + options.tcp_rcv_buf, strerror(errno)); +} + + +/* * Creates a (possibly privileged) socket for use as the ssh connection. */ static int @@ -193,12 +218,18 @@ strerror(errno)); else debug("Allocated local port %d.", p); + + if (options.tcp_rcv_buf > 0) + ssh_set_socket_recvbuf(sock); return sock; } sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) error("socket: %.100s", strerror(errno)); + if (options.tcp_rcv_buf > 0) + ssh_set_socket_recvbuf(sock); + /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL) return sock; diff -Naur openssh-4.7p1-debian/sshconnect2.c openssh-4.7p1/sshconnect2.c --- openssh-4.7p1-debian/sshconnect2.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/sshconnect2.c 2008-04-02 14:10:52.000000000 +0200 @@ -73,6 +73,12 @@ extern char *client_version_string; extern char *server_version_string; extern Options options; +extern Kex *xxx_kex; + +/* tty_flag is set in ssh.c. use this in ssh_userauth2 */ +/* if it is set then prevent the switch to the null cipher */ + +extern int tty_flag; /* * SSH2 key exchange @@ -381,6 +387,28 @@ pubkey_cleanup(&authctxt); dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); + /* if the user wants to use the none cipher do it */ + /* post authentication and only if the right conditions are met */ + /* both of the NONE commands must be true and there must be no */ + /* tty allocated */ + if ((options.none_switch == 1) && (options.none_enabled == 1)) + { + if (!tty_flag) /* no null on tty sessions */ + { + debug("Requesting none rekeying..."); + myproposal[PROPOSAL_ENC_ALGS_STOC] = "none"; + myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none"; + kex_prop2buf(&xxx_kex->my,myproposal); + packet_request_rekeying(); + fprintf(stderr, "WARNING: ENABLED NONE CIPHER\n"); + } + else + { + /* requested NONE cipher when in a tty */ + debug("Cannot switch to NONE cipher with tty allocated"); + fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n"); + } + } debug("Authentication succeeded (%s).", authctxt.method->name); } diff -Naur openssh-4.7p1-debian/sshd.c openssh-4.7p1/sshd.c --- openssh-4.7p1-debian/sshd.c 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/sshd.c 2008-04-02 14:10:52.000000000 +0200 @@ -138,6 +138,9 @@ #define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) #define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4) +int myflag = 0; + + extern char *__progname; /* Server configuration options. */ @@ -474,6 +477,9 @@ } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); + logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s", + get_remote_ipaddr(), get_remote_port(), + remote_major, remote_minor, remote_version); compat_datafellows(remote_version); @@ -946,6 +952,8 @@ int ret, listen_sock, on = 1; struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + int socksize; + int socksizelen = sizeof(int); for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) @@ -983,6 +991,11 @@ debug("Bind to port %s on %s.", strport, ntop); + getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + debug("Server TCP RWIN socket size: %d", socksize); + debug("HPN Buffer Size: %d", options.hpn_buffer_size); + /* Bind the socket to the desired port. */ if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { error("Bind to port %s on %s failed: %.200s.", @@ -2160,9 +2173,15 @@ { Kex *kex; + myflag++; + debug ("MYFLAG IS %d", myflag); if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; + } else if (options.none_enabled == 1) { + debug ("WARNING: None cipher enabled"); + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_ENCRYPT_INCLUDE_NONE; } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); diff -Naur openssh-4.7p1-debian/sshd_config openssh-4.7p1/sshd_config --- openssh-4.7p1-debian/sshd_config 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/sshd_config 2008-04-02 14:10:52.000000000 +0200 @@ -111,6 +111,20 @@ # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server +# the following are HPN related configuration options +# tcp receive buffer polling. disable in non autotuning kernels +#TcpRcvBufPoll yes + +# allow the use of the none cipher +#NoneEnabled no + +# disable hpn performance boosts. +#HPNDisabled no + +# buffer size for hpn to non-hpn connections +#HPNBufferSize 2048 + + # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no diff -Naur openssh-4.7p1-debian/version.h openssh-4.7p1/version.h --- openssh-4.7p1-debian/version.h 2008-04-02 11:56:47.000000000 +0200 +++ openssh-4.7p1/version.h 2008-04-02 14:10:52.000000000 +0200 @@ -3,8 +3,9 @@ #define SSH_VERSION "OpenSSH_4.7" #define SSH_PORTABLE "p1" +#define SSH_HPN "-hpn13v1" #ifdef SSH_EXTRAVERSION -#define SSH_RELEASE SSH_VERSION SSH_PORTABLE " " SSH_EXTRAVERSION +#define SSH_RELEASE SSH_VERSION SSH_PORTABLE SSH_HPN " " SSH_EXTRAVERSION #else -#define SSH_RELEASE SSH_VERSION SSH_PORTABLE +#define SSH_RELEASE SSH_VERSION SSH_PORTABLE SSH_HPN #endif
Some results:
# ssh -c arcfour -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [50.5MB/s] # ssh -c arcfour128 -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [50.5MB/s] # ssh -c blowfish-cbc -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [31.9MB/s] # ssh -c aes128-cbc -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [30.7MB/s] # ssh -c aes128-ctr -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [25.9MB/s] # ssh -c aes256-cbc -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [ 25MB/s] # ssh -c aes256-ctr -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [16.2MB/s] # ssh -c cast128-cbc -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [13.1MB/s] # ssh -c arcfour256 -p8322 localhost "dd if=/dev/zero" |pv > /dev/null [12.9MB/s]
Results give the same order as on the official page, arcfour ranked #1, blowfish #2 & aes128 #3
# ssh -t -c none -oNoneSwitch=yes -oNoneEnabled=yes -p8322 localhost "dd if=/dev/zero" |pv > /dev/null Pre-authentication none cipher requests are not allowed.
(even with NoneEnabled=yes on the server-side :-( )